diff -Nru mlt-0.6.2/ChangeLog mlt-0.7.2/ChangeLog --- mlt-0.6.2/ChangeLog 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/ChangeLog 2011-05-02 05:59:12.000000000 +0000 @@ -1,15 +1,1090 @@ +2011-05-01 Dan Dennedy + + * Doxyfile, configure, docs/melt.1, src/framework/mlt_version.h: Set version + to 0.7.2 + + * NEWS: Add release notes for v0.7.2. + + * src/modules/avformat/filter_avresample.c, + src/modules/resample/filter_resample.c: Finish work to normalize channel + count. Also, refactor the audio resamplers to use mlt_audio_format_size() + and mlt_frame_set_audio(). Currently, there are no controls over which + channels to drop or duplicate. + + * src/framework/mlt_tractor.c, src/modules/core/producer_consumer.c, + src/modules/core/producer_noise.c, src/modules/core/producer_ppm.c: Refactor + to mlt_frame_set_audio(). + + * src/melt/melt.c: Let 'Q' stop melt as well. + + * src/modules/feeds/NTSC/data_fx.properties, + src/modules/feeds/PAL/data_fx.properties: Fix alpha on color of some + data-feed properties. + + * src/modules/avformat/factory.c: Free temp string. + + * src/modules/avformat/consumer_avformat.c, src/modules/avformat/factory.c, + src/modules/avformat/producer_avformat.c: Add support for new codec- and + muxer-specific AVOptions. + +2011-04-30 Dan Dennedy + + * setenv: DYLD_LIBRARY_PATH not needed for me on OS X. + + * src/modules/avformat/producer_avformat.c: Fix sample rate and channel count + from avformat producer. If unable to resample or the decoder does not give + the requested channel count, then we should return the actual values so + downstream components can do the correct thing if they can. A good example of + this is 6 channel AAC when the consumer requests 2 channels. Unlike the AC-3 + decoder, the AAC decoder can not downmix. So, we were returning audio pcm + containing 6 channels but with a channel count of 2. + +2011-04-29 Dan Dennedy + + * src/modules/avformat/producer_avformat.c: Try to duplicate last image if + decoding fails. + +2011-04-22 Dan Dennedy + + * src/framework/mlt_consumer.c: Fix intermitent crash in mlt_consumer + consumer_read_ahead_thread. + + * src/modules/avformat/producer_avformat.c: Use new + av_get_bits_per_sample_fmt() in avformat producer. + + * src/modules/avformat/consumer_avformat.c, + src/modules/avformat/producer_avformat.c: Use new avio functions in avformat + module. + +2011-04-21 Dan Dennedy + + * src/modules/sdl/consumer_sdl_audio.c: Fix deadlock in sdl_audio appearing + in kdenlive. + + * src/modules/core/producer_ppm.c: Fix compile warns in producer_ppm.c. + + * src/modules/avformat/filter_avcolour_space.c, + src/modules/avformat/producer_avformat.c: Fix regression initializing + coefficients. + + * src/modules/avformat/producer_avformat.c: Use newer + av_get_sample_fmt_name() if available. + + * src/modules/avformat/consumer_avformat.c, + src/modules/avformat/filter_avcolour_space.c, + src/modules/avformat/filter_swscale.c, + src/modules/avformat/producer_avformat.c: Fix avformat compile warns on const + and 64-bit string formatting. + + * src/modules/core/producer_hold.c, src/modules/jackrack/filter_jackrack.c: + Fix couple compile warns. + + * src/framework/mlt_property.c, src/framework/mlt_types.h, + src/modules/linsys/sdi_generator.c: Fix some compile warnings about + string-formatting 64bit. + + * src/modules/avformat/audioconvert.h, + src/modules/avformat/producer_avformat.c: Drop private audioconvert.h for + public samplefmt.h. + +2011-04-20 Dan Dennedy + + * src/modules/avformat/consumer_avformat.c, src/modules/avformat/factory.c, + src/modules/avformat/producer_avformat.c: More libavcodec v53 changes + required. + + * src/modules/avformat/consumer_avformat.c, + src/modules/avformat/producer_avformat.c: Fix avformat build with libavcodec + v53. + + * src/modules/avformat/configure: Fix detect swscale on libavcodec major + version bump. + +2011-04-18 Dan Dennedy + + * src/modules/core/producer_colour.c: Fix corruption in color producer + (3288984) + +2011-04-12 Dan Dennedy + + * src/modules/decklink/consumer_decklink.cpp: Fix decklink consumer on + devices without keyer. + +2011-04-09 Dan Dennedy + + * src/framework/mlt_profile.c, src/mlt++/MltProfile.cpp, + src/mlt++/MltProfile.h, src/swig/mlt.i: Add Mlt::Profile.list(). + + * src/framework/mlt_profile.c: Fix mlt_profile_list when MLT_PROFILES_PATH + not set. + +2011-04-08 Dan Dennedy + + * src/modules/kdenlive/filter_freeze.c: Fix deadlock in freeze filter. + Reported by Andrew Wason. + +2011-04-07 Dan Dennedy + + * src/modules/avformat/consumer_avformat.yml, src/modules/avformat/factory.c, + src/modules/avformat/producer_avformat.yml: Add avformat consumer metadata. + Improve avformat producer metadata. Significantly extend each with AVOptions. + +2011-04-06 Dan Dennedy + + * src/modules/core/transition_region.c: Better fix to the region regression + (3277867). This one works with bug report test case, timecode overlay in + Kdenlive Render, and Region transition in Kdenlive. + + * src/modules/core/transition_composite.c: Fix regression on region + transition (3277867). + +2011-04-04 Dan Dennedy + + * demo/README, demo/demo.ini, demo/mlt_pango_keyframes, + demo/pango_keyframes.mpl: Add mlt_pango_keyframes demo. + + * src/modules/gtk2/producer_pango.c: Make pango file on invalid file + (3272537). + +2011-04-03 Dan Dennedy + + * docs/melt.1, docs/melt.txt, src/melt/melt.c: Add -query formats and codecs + to melt. + + * docs/melt.1, docs/melt.txt, src/melt/melt.c: Add -query profile to melt. + + * src/framework/mlt_profile.c, src/framework/mlt_profile.h: Add + mlt_profile_list(). + + * src/modules/decklink/consumer_decklink.yml: Add parameter descriptions. + +2011-04-02 Dan Dennedy + + * src/modules/decklink/consumer_decklink.cpp: Add keyer support to decklink + consumer. + +2011-03-31 Dan Dennedy + + * src/modules/decklink/consumer_decklink.yml, + src/modules/decklink/producer_decklink.yml: Add metadata for decklink + consumer. + + * src/modules/decklink/Makefile, src/modules/decklink/producer_decklink.cpp, + src/modules/decklink/producer_decklink.yml: Add decklink producer. + +2011-03-27 Dan Dennedy + + * src/modules/avformat/consumer_avformat.c: Fail gracefully on unsupported + codec (3251438). + + * configure, src/modules/core/transition_composite.c: Fix regression in + region filter (3251260). + + * ChangeLog: Update ChangeLog for v0.7.0. + + * Doxyfile, configure, src/framework/mlt_version.h: Set version to 0.7.0 + + * NEWS: Add release notes for v0.7.0. + + * src/modules/melt/producer_melt.c: Fix segfault on missing melt argument + (3249982). + + * src/modules/avformat/producer_avformat.c: Fix a segfault in avformat with + parallel consumer. + + * src/modules/core/transition_composite.c: Fix composite using wrong B frame + scaling. This could happen when the caller of mlt_frame_get_image supplied 0 + for width and height. For example, Kdenlive's GL output with the sdl_audio + consumer with real_time > 1 and paused. + + * docs/melt.1: Fix segfaul on missing melt argument (3249982). + + * src/modules/sdl/consumer_sdl_audio.c: Fix some crashing in sdl_audio. + + * src/modules/sdl/consumer_sdl_audio.c: Also increase audio_buffer default in + sdl_audio. + + * src/modules/avformat/configure: Disable VDPAU by default. Require new + --avformat-vdpau to enable it. + + * src/modules/avformat/consumer_avformat.c, src/modules/sox/filter_sox.c, + src/modules/xml/producer_xml.c: Use mlt_properties_get_value where possible. + + * src/framework/mlt_playlist.c, src/framework/mlt_producer.c, + src/framework/mlt_properties.c, src/framework/mlt_properties.h, + src/framework/mlt_tractor.c, src/mlt++/MltProperties.cpp, + src/mlt++/MltProperties.h: Add mlt_properties_lock and _unlock. Fixes some + concurrency safetiness problems. + +2011-03-24 Dan Dennedy + + * src/modules/decklink/configure, src/modules/kino/configure, + src/modules/linsys/configure: Enable linsys by default on Linux. Disable + linsys and decklink by default on OS X and Windows. + + * src/modules/configure: Display all configure options with --help. + Regardless of --enable-gpl setting. + + * src/modules/avformat/producer_avformat.c: Redo locking in avformat + producer. This significantly improves concurrency. The service locks added + during parallel consumer development also introduced a concurrency + performance regression even for the single-threaded consumer. The result was + much audio discontinuity due to audio output buffer underruns. As a result, + the recent bug fix to re-open the video demuxer upon seeking to the first + frame had to be rewritten. + +2011-03-23 Dan Dennedy + + * src/modules/avformat/vdpau.c: Fix vdpau crashes when failed to init. + + * src/modules/avformat/vdpau.c: Fix unchecked vdpau pointer. + + * src/modules/sdl/consumer_sdl_preview.c: Default sdl_preview prefill to 1. + Since buffer and prefill were recently passed from sdl_preview onto sdl, + sdl's default buffer level changed to the base service default of 25. That + change increases the latency of transport controls. Changing the prefill to 1 + resolves that while still allowing the rendering thread a chance to do some + anticipatory work. + + * src/modules/decklink/consumer_decklink.cpp: Fix a comment in decklink + consumer. + + * src/framework/mlt_consumer.c, src/modules/decklink/consumer_decklink.cpp: + Fix a couple null pointer bugs. + +2011-03-22 Dan Dennedy + + * src/modules/decklink/consumer_decklink.cpp: Improve frame-dropping in + decklink. + +2011-03-20 Dan Dennedy + + * src/modules/jackrack/filter_jackrack.c, src/modules/jackrack/plugin.h, + src/modules/jackrack/process.c: Fix build of jackrack module on mingw. + +2011-03-19 Dan Dennedy + + * profiles/atsc_1080p_50, profiles/atsc_1080p_5994, profiles/atsc_1080p_60: + Add high frame rate 1080p profiles. + +2011-03-17 Dan Dennedy + + * src/modules/avformat/producer_avformat.c: Fix regression on seeking to + first frame with audio_index set. + +2011-03-14 Dan Dennedy + + * src/modules/avformat/producer_avformat.c: Add force_length and + adjust_length properties. The reporter on kdenlive bug 2003 reports another + user on IRC had the same problem with clips being too long. Change the + default length adjustment to be more safe and add new properties to affect + the heuristic for other applications that might want a different behavior. + adjust_length applies a plus/minus operand to the detected length. + force_length provides a brute force length override. + + * src/modules/avformat/producer_avformat.c: Fix some incorrect frame rates in + avformat (kdenlive-1616). + + * src/modules/frei0r/factory.c: Support frei0r transitions that use + f0r_update2(). + + * configure: Fix amd64 detection on FreeBSD. Patch from Alberto Villa. + +2011-03-13 Dan Dennedy + + * src/modules/core/filter_crop.c: Add boolean use_profile property to crop + filter. This lets one express crop amounts in pixels relative to profile + resolution instead of in terms of source resolution. + + * src/modules/frei0r/blacklist.txt: We do not yet support + f0r_param_position_t. + +2011-03-12 Ertan Deniz + + * src/framework/mlt_factory.c: Set global variables to NULL in + mlt_factory_close to enable mlt_factory to be initialized and closed + multiple times. + +2011-03-12 Dan Dennedy + + * src/modules/avformat/consumer_avformat.c: Prefer opening codec by name + instead of by ID. This fixes a bug with actually using libxvid instead of + mpeg4 because both share the same CODEC_ID_MPEG4. This is similar to the + recent problem with ac3 selection in new versions of ffmpeg that have 2 ac3 + encoders. + +2011-03-09 Dan Dennedy + + * src/modules/frei0r/filter_frei0r.c, src/modules/frei0r/frei0r_helper.c, + src/modules/frei0r/frei0r_helper.h, src/modules/frei0r/producer_frei0r.c, + src/modules/frei0r/transition_frei0r.c: Refactor frei0r and fix time + parameter. Refactored to use mlt_filter_get_position and + mlt_transition_get_position. frei0r's time parameter is seconds, but we were + passing frame count. + + * src/modules/core/transition_region.c: Fix region transition with more than + 2 tracks. + + * src/modules/core/transition_region.c, src/modules/plus/transition_affine.c: + Refactor to mlt_transition_get_position() + + * src/framework/mlt_transition.c, src/framework/mlt_transition.h, + src/mlt++/MltTransition.cpp, src/mlt++/MltTransition.h: Add + mlt_transition_get_position() + + * src/modules/core/transition_luma.c: Remove obsolete unique position on + frame. + + * src/framework/mlt_transition.c: Use the producer when always active. + + * src/modules/core/filter_luma.c, src/modules/core/filter_watermark.c, + src/modules/dgraft/filter_telecide.c, src/modules/kdenlive/filter_freeze.c, + .../motion_est/filter_autotrack_rectangle.c, + src/modules/motion_est/filter_crop_detect.c, + src/modules/oldfilm/filter_vignette.c, src/modules/plus/filter_affine.c, + src/modules/vmfx/filter_shape.c: Refactor to mlt_filter_get_position(). + +2011-03-08 Dan Dennedy + + * src/modules/core/filter_obscure.c: Refactor to mlt_filter_get_progress(). + + * src/framework/mlt_filter.c, src/framework/mlt_transition.c: Use the + producer when filter/transition always active. + + * src/framework/mlt_filter.c, src/framework/mlt_filter.h, + src/mlt++/MltFilter.cpp, src/mlt++/MltFilter.h: Add + mlt_filter_get_position(). + +2011-03-07 Dan Dennedy + + * src/modules/core/transition_composite.c, + src/modules/core/transition_luma.c: Refactor to + mlt_transition_get_progress_delta(). + + * src/framework/mlt_transition.c, src/framework/mlt_transition.h, + src/mlt++/MltTransition.cpp, src/mlt++/MltTransition.h: Add + mlt_transition_get_progress_delta(). + + * src/modules/core/transition_luma.c, src/modules/core/transition_mix.c: + Refactor to mlt_transition_get_progress(). + + * src/framework/mlt_transition.c, src/framework/mlt_transition.h, + src/mlt++/MltTransition.cpp, src/mlt++/MltTransition.h: Add + mlt_transition_get_progress(). + + * src/modules/core/filter_brightness.c, src/modules/core/filter_obscure.c, + src/modules/kdenlive/filter_boxblur.c, src/modules/kdenlive/filter_wave.c, + src/modules/normalize/filter_volume.c, src/modules/oldfilm/filter_dust.c, + src/modules/oldfilm/filter_grain.c, src/modules/oldfilm/filter_lines.c, + src/modules/oldfilm/filter_oldfilm.c: Refactor to mlt_filter_get_progress(). + + * src/framework/mlt_filter.c, src/framework/mlt_filter.h, + src/mlt++/MltFilter.cpp, src/mlt++/MltFilter.h: Add + mlt_filter_get_progress(). + + * src/modules/plus/transition_affine.c: Refactor to + mlt_transition_get_length(). + +2011-03-10 Dan Dennedy + + * src/modules/avformat/consumer_avformat.c: Fix regression on AC-3 fix. The + recent AC-3 fix broke automatic codec selection based on format. So, we + choose codec by name only for ac3 now. + + * src/modules/swfdec/configure: Fix typo in swfdec configure script. + + * src/modules/swfdec/Makefile, src/modules/swfdec/configure: Add build + support for swfdec 0.7. And prioritize newer versions over older ones. + + * src/modules/resample/filter_resample.c: Increase resample buffer size. For + example, trying to resample 6 channels of 48 KHz would fail. + + * src/modules/resample/filter_resample.c: Remove unnecessary audio conversion + to float. + + * src/modules/avformat/producer_avformat.c: Fix audio resample with + audio_index=all. This still only works with channels <= 2. Streams with + channels > 2 are resampled downstream with the resample filter. However, that + only works when said stream has the highest sample rate. + +2011-03-07 Till Theato + + * src/modules/rotoscoping/filter_rotoscoping.c: Rotoscoping: use new API + functions to prevent some possible issues. + +2011-03-07 Dan Dennedy + + * src/modules/core/filter_audioconvert.c: Fix regression in audioconvert. + +2011-03-06 Dan Dennedy + + * src/modules/core/transition_composite.c, + src/modules/plus/transition_affine.c: Refactor to use + mlt_transition_get_length(). + + * src/framework/mlt_transition.c, src/framework/mlt_transition.h, + src/mlt++/MltTransition.cpp, src/mlt++/MltTransition.h: Add + mlt_transition_get_length(). + + * src/modules/frei0r/filter_frei0r.c: Refactor to use mlt_frame_get_length(). + + * src/modules/normalize/filter_volume.c: Remove unused variable. + + * src/framework/mlt_filter.c, src/framework/mlt_filter.h, + src/mlt++/MltFilter.cpp, src/mlt++/MltFilter.h: Add mlt_filter_get_length(). + + * src/framework/mlt_playlist.c: Refactor to use mlt_producer_get_playtime(). + + * src/modules/core/filter_audioconvert.c, src/modules/core/filter_mono.c, + src/modules/core/producer_consumer.c: Refactor to mlt_audio_format_size(). + + * src/framework/mlt_frame.c, src/framework/mlt_frame.h: Add + mlt_audio_format_size(). + + * src/modules/core/producer_noise.c, src/modules/normalize/filter_volume.c: + Remove unused variables. + + * src/modules/avformat/filter_avcolour_space.c: Define out this unused code. + + * src/modules/avformat/filter_swscale.c, + src/modules/avformat/producer_avformat.c, src/modules/core/filter_crop.c, + src/modules/core/filter_resize.c, src/modules/core/producer_colour.c, + src/modules/gtk2/filter_rescale.c, src/modules/kdenlive/filter_freeze.c, + src/modules/kdenlive/producer_framebuffer.c: Refactor to use + mlt_image_format_size(). + + * src/framework/mlt_frame.c, src/framework/mlt_frame.h: Add + mlt_image_format_size() + + * src/framework/mlt_tractor.c, src/modules/avformat/filter_avcolour_space.c, + src/modules/avformat/filter_swscale.c, + src/modules/avformat/producer_avformat.c, + src/modules/core/filter_audiowave.c, src/modules/core/filter_crop.c, + src/modules/core/filter_imageconvert.c, src/modules/core/filter_luma.c, + src/modules/core/filter_rescale.c, src/modules/core/filter_resize.c, + src/modules/core/filter_watermark.c, src/modules/core/producer_colour.c, + src/modules/core/producer_consumer.c, src/modules/core/producer_hold.c, + src/modules/core/producer_noise.c, src/modules/core/producer_ppm.c, + src/modules/core/transition_composite.c, + src/modules/core/transition_region.c, src/modules/dgraft/filter_telecide.c, + src/modules/dv/producer_libdv.c, src/modules/frei0r/frei0r_helper.c, + src/modules/frei0r/producer_frei0r.c, src/modules/gtk2/filter_rescale.c, + src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c, + src/modules/kdenlive/filter_freeze.c, src/modules/kdenlive/filter_wave.c, + src/modules/kdenlive/producer_framebuffer.c, + src/modules/motion_est/producer_slowmotion.c, + src/modules/plus/filter_affine.c, src/modules/plus/filter_charcoal.c, + src/modules/qimage/producer_kdenlivetitle.c, + src/modules/qimage/producer_qimage.c, src/modules/sdl/producer_sdl_image.c, + src/modules/swfdec/producer_swfdec.c, src/modules/vmfx/producer_pgm.c, + src/modules/xine/filter_deinterlace.c: Refactor to use + mlt_frame_set_image/_alpha. + + * src/framework/mlt_frame.c, src/framework/mlt_frame.h, + src/mlt++/MltFrame.cpp, src/mlt++/MltFrame.h: Add mlt_frame_set_image and + mlt_frame_set_alpha. + + * src/framework/mlt_properties.c: Fix spelling error in doxygen. + + * src/framework/mlt_consumer.c: Fix thread cleanup on parallel consumer stop. + This was appearing often as a segfault at the end of melt with the avformat + consumer. + + * src/modules/gtk2/producer_pango.c, src/modules/gtk2/producer_pixbuf.c: + Alias bicubic for hyper in pango and pixbuf. + + * : Add gpl flag file to rotoscoping filter. + + * src/modules/avformat/consumer_avformat.c: Fix AC-3 encoding + (kdenlive-2010). FFmpeg now has separate encoders that take float versus + fixed samples. + +2011-03-05 Dan Dennedy + + * src/modules/gtk2/filter_rescale.c: Make 'bicubic' an alias for highest + quality in gtk scaler. + + * src/modules/qimage/qimage_wrapper.cpp: Fix handling monochrome in qimage. + +2011-03-03 Dan Dennedy + + * src/modules/core/transition_luma.c: Fix string comparison and requested + luma size. + + * src/modules/core/filter_resize.c: Prevent attempt to pad to a smaller size. + + * src/modules/core/transition_luma.c: Fix luma semantics when both reverse + and invert. Previously, when not using a wipe (dissolve), invert would make + the transition have no effect. Now, it works and does the same thing as + reverse. Also, when using a wipe, reverse had no effect when invert was set, + and the desired effect could not be achieved. Now, it works as expected. + + * demo/demo: Set a profile for the demo script. + + * demo/consumers.ini: Drop MainConcept and BlueFish444 from the demo + consumers. + + * src/framework/mlt_properties.c: Improve mlt_properties_close() in debugger. + +2011-03-02 Dan Dennedy + + * src/modules/kdenlive/filter_wave.c: Rewrite wave filter to be + parallel-safe. It does this by using mlt_frame_unique_properties(). Also, it + fixes a problem not properly processing a source image. + + * src/modules/normalize/filter_volume.c: Refactor volume to use + mlt_frame_unique_properties(). + + * src/framework/mlt_frame.c, src/framework/mlt_frame.h: Add + mlt_frame_unique_properties(). + + * src/modules/avformat/consumer_avformat.c, + src/modules/avformat/filter_avcolour_space.c, + src/modules/avformat/filter_avdeinterlace.c, + src/modules/avformat/filter_avresample.c, + src/modules/avformat/filter_swscale.c, + src/modules/avformat/producer_avformat.c, src/modules/avformat/vdpau.c: + Rename 'this' in avformat module. + + * src/modules/frei0r/not_thread_safe.txt: Mark more frei0r filters not + thread-safe. + +2011-03-01 Dan Dennedy + + * src/modules/kdenlive/producer_framebuffer.c: Fix deadlock regression in + framebuffer producer. + + * src/modules/frei0r/not_thread_safe.txt: Flag some frei0r filters as not + thread-safe. + + * src/modules/sdl/consumer_sdl.c: Fix deadlock in sdl_preview. This would + occur when trying to play from a paused state at the end of the project. + +2011-03-01 Till Theato + + * src/modules/rotoscoping/filter_rotoscoping.c, + src/modules/rotoscoping/filter_rotoscoping.yml: rotoscoping: remove parameter + precision. Its influence on speed was very minimal while it caused some + crashes. Also update YAML filter description. + +2011-02-28 Dan Dennedy + + * src/modules/core/transition_luma.c: Fix integrity of luma transition when + parallel. + + * src/modules/avformat/producer_avformat.c: Workaround incorrect duration on + some clips (kdenlive-2003). + + * src/modules/avformat/producer_avformat.c: Fix regression in determination + of seekable. + + * src/framework/mlt_consumer.c, src/framework/mlt_deque.c, + src/framework/mlt_events.c, src/framework/mlt_factory.c, + src/framework/mlt_field.c, src/framework/mlt_filter.c, + src/framework/mlt_frame.c, src/framework/mlt_geometry.c, + src/framework/mlt_multitrack.c, src/framework/mlt_parser.c, + src/framework/mlt_playlist.c, src/framework/mlt_pool.c, + src/framework/mlt_producer.c, src/framework/mlt_profile.c, + src/framework/mlt_properties.c, src/framework/mlt_property.c, + src/framework/mlt_property.h, src/framework/mlt_repository.c, + src/framework/mlt_service.c, src/framework/mlt_tokeniser.h, + src/framework/mlt_tractor.c, src/framework/mlt_transition.c: Rename this to + self in the framework. This makes doxygen output better match the headers, + and it improves life within a code-parsing IDE like Qt Creator. + + * demo/demo.ini: Fixup demo.ini + + * src/framework/mlt_geometry.c: Rename self to g in mlt_geometry. + + * src/modules/avformat/producer_avformat.c: Fix compiler error on older + version of libavutil. + +2011-02-27 Dan Dennedy + + * src/modules/avformat/consumer_avformat.c: Fix mlt_consumer_position when + encoding audio only. + + * src/modules/avformat/consumer_avformat.c, + src/modules/avformat/producer_avformat.c: Add support for FFmpeg AVMetadata + API. + + * src/modules/avformat/producer_avformat.c: Fix compiler warning on + av_get_pix_fmt(). + + * src/modules/avformat/producer_avformat.c: Rewrite seekable check in + avformat. Now, alsa input works: melt -profile dv_pal alsa:default + video4linux with alsa: melt -profile quarter_15 video4linux2:/dev/video1 \ + -track alsa:default -transition mix And files over HTTP can handle seeking. + +2011-02-27 Till Theato + + * src/modules/rotoscoping/filter_rotoscoping.c: rotoscoping: Add parameters + feather and feather_passes. Feathering is done by bluring the map containing + the masked area. + +2011-02-26 Dan Dennedy + + * src/modules/frei0r/blacklist.txt: Remove frei0r.facedetect from black list. + + * src/modules/frei0r/not_thread_safe.txt: Mark frei0r.cluster as not + thread-safe. + + * src/modules/frei0r/factory.c: Fix small memory leak each a frei0r plugin is + instantiated. + +2011-02-25 Dan Dennedy + + * src/modules/avformat/producer_avformat.c: Add support for pix_fmt on + avformat resource URL. For example, + libdc1394:/dev/raw1394?frame_rate:15\&pix_fmt:yuv422 makes a Firewire digital + camera (not DV camcorder) on Linux work. + + * src/modules/avformat/producer_avformat.c: Add support for avdevice video + channel selection. For example, video4linux2:/dev/video0?channel=2 sets the + input to S- + + * setenv: fix setenv + +2011-02-24 Dan Dennedy + + * src/framework/mlt_transition.c: Support forever transitions (in and out not + supplied). + + * src/modules/core/filter_rescale.c: Add 'factor' property to scale filters. + Under certain conditions it can be desirable to manually change the + resolution. Caution: one can still not use this in a completely generic way + with this change. For example, in a realtime playout situation, one can + attach swscale with factor=0.25, followed by frei0r.cluster, followed by + swscale again with no properties. The first swscale will downscale the image + for the heavy cluster filter. The last swscale will upscale it to make the + rest of the project components happy. + +2011-02-20 Dan Dennedy + + * src/modules/frei0r/Makefile, src/modules/frei0r/factory.c, + src/modules/frei0r/frei0r_helper.c, src/modules/frei0r/not_thread_safe.txt: + Mark some frei0r plugins as not thread safe. + +2011-02-20 Till Theato + + * src/modules/rotoscoping/filter_rotoscoping.c: rotoscoping: number of points + can now change from keyframe to keyframe. Result may be unexpected though. + Additionally some cleanup + + * src/modules/rotoscoping/filter_rotoscoping.c: rotoscoping: rename mode + "matte" to "luma" Additionally prevent serialization of internal parameters + +2011-02-19 Dan Dennedy + + * src/modules/avformat/producer_avformat.c: Fix video4linux in avformat + producer. melt video4linux2:/dev/video0 + + * docs/install.txt, docs/mlt-xml.txt, docs/services.txt, setenv: Remove info + about mainconcept and bluefish services. + + * src/framework/mlt_producer.c, src/framework/mlt_producer.h, + src/modules/core/producer_consumer.c, src/modules/core/producer_hold.c, + src/modules/core/producer_noise.c, src/modules/frei0r/factory.c, + src/modules/motion_est/producer_slowmotion.c: Add profile parameter to + mlt_producer_new. + + * src/framework/mlt_service.c: Check pointer passed to mlt_service_profile. + + * src/modules/core/producer_colour.c: Fix aspect ratio of color producer. + + * configure: Add --enable-debug option. + +2011-02-19 j-b-m + + * src/modules/gtk2/producer_pixbuf.c, src/modules/qimage/qimage_wrapper.cpp: + Store exif orientation. Patch attached internally stores the exif + orientation so that it can be accessible to the framework and apps using it. + Useful it in Kdenlive to correctly rotate images when creating proxy images. + +2011-02-19 Dan Dennedy + + * src/modules/motion_est/Makefile: Fix lib suffix on motion_est. + +2011-02-16 Dan Dennedy + + * src/modules/sdl/consumer_sdl_audio.c: Disable purging consumer on seek in + sdl_audio. Due to misbehaving on parallel-consumer. + +2011-02-16 Till Theato + + * src/modules/rotoscoping/filter_rotoscoping.c: rotoscoping: Use + "property-changed" event to find out when to parse the spline + +2011-02-13 Dan Dennedy + + * src/modules/sdl/consumer_sdl.c: Playout remaining frames in sdl at + end-of-stream. + + * src/framework/mlt_consumer.c, src/framework/mlt_consumer.h, + src/modules/sdl/consumer_sdl_preview.c: Fix deadlocks in sdl_preview with + parallel-consumer. + +2011-02-08 Dan Dennedy + + * src/modules/core/transition_composite.c: Fix image skew bug in composite + (kdenlive-1923). + + * src/modules/core/transition_luma.c: Fix deinterlace when luma is inverted + (kdenlive-1953). + +2011-02-07 j-b-m + + * src/modules/plus/transition_affine.c: Make offset in affine transition + keyframable. + +2011-02-05 Till Theato + + * src/modules/rotoscoping/filter_rotoscoping.c: rotoscoping: fix mode alpha + not working with image format rgb24a + +2011-02-03 Till Theato + + * src/modules/rotoscoping/filter_rotoscoping.c: rotoscoping: prevent possible + crash + +2011-01-31 Dan Dennedy + + * src/modules/core/producer_consumer.c: Copy the alpha channel in + producer_consumer. + +2011-01-30 Dan Dennedy + + * src/modules/avformat/consumer_avformat.c: Improve efficiency of memory copy + in avformat consumer. Patch from Paul Flinders . + + * src/modules/avformat/producer_avformat.c: Be pessimistic about the duration + (kdenlive-1962). Some clip formats give a slightly longer duration estimate, + and MLT does not handle that well especially in some non-interactive use + cases like transcoding and automated processing. + +2011-01-27 Dan Dennedy + + * src/modules/gtk2/Makefile: Link pango producer with libiconv on Mac OS X. + +2011-01-27 Till Theato + + * src/modules/rotoscoping/Makefile, src/modules/rotoscoping/factory.c, + src/modules/rotoscoping/filter_rotoscoping.c, + src/modules/rotoscoping/filter_rotoscoping.yml: Rotoscoping: Set default mode + to alpha and add YAML filter description + +2011-01-26 Dan Dennedy + + * src/modules/avformat/producer_avformat.c: Do not round up the duration + (kdenlive-1962). + + * src/modules/avformat/producer_avformat.c: Fix pausing on vdpau with + noimagecache. Also uses AVFrame we already have instead of local AVPicture. + + * src/modules/avformat/producer_avformat.c: Make seeking to first frame more + reliable. + +2011-01-25 Dan Dennedy + + * src/modules/sdl/consumer_sdl.c: Increase default SDL audio buffer to + prevent crackling. + + * src/framework/mlt_consumer.c: Make worker thread handle tracking more + portable. + +2011-01-25 Till Theato + + * src/modules/rotoscoping/filter_rotoscoping.c: Rotoscoping: another small + cleanup + + * src/modules/rotoscoping/filter_rotoscoping.c: Rotoscoping: cleanup + + * src/modules/rotoscoping/filter_rotoscoping.c: Rotoscoping: Mode matte + should also work in yuv420p (untested since forcing a conversion from yuv422 + does not work) + + * src/modules/rotoscoping/filter_rotoscoping.c: Rotoscoping: only the mode + rgb requires a specific colorspace + +2011-01-24 Till Theato + + * src/modules/rotoscoping/filter_rotoscoping.c: Rotoscoping: Save the the + json object so we do not have to parse the parameter at every processing but + only when it changed + + * src/modules/rotoscoping/filter_rotoscoping.c: Rotoscoping: use mlt_pool + + * src/modules/rotoscoping/filter_rotoscoping.c: Rotoscoping: rename "mask" + mode to "matte" + +2010-11-23 Dan Dennedy + + * src/modules/plus/filter_affine.c: Reduce service lock contention in affine + filter. + + * src/modules/frei0r/filter_frei0r.c, src/modules/frei0r/frei0r_helper.c, + src/modules/frei0r/frei0r_helper.h, src/modules/frei0r/producer_frei0r.c, + src/modules/frei0r/transition_frei0r.c: Reduce service lock contention in + frei0r module. + +2010-11-04 Dan Dennedy + + * src/framework/mlt_consumer.c: Fix race condition on frame pointer in + parallel consumer. + +2010-10-17 Dan Dennedy + + * src/framework/mlt_consumer.c: Fix multiple workers getting the same frame. + +2010-10-04 Dan Dennedy + + * src/framework/mlt_consumer.c, src/framework/mlt_consumer.h, + src/framework/mlt_frame.h: Use a single queue for parallel workers. This is + a major change from the previous model of moving work items (frames) from one + queue to another. This new model improves the behavior of realtime mode and + performance overall. In the new model, a single queue is used along with an + is_processed flag on the frame. Also, there is an index into the queue + (process_head) that indicates from which point should a worker consider + fetching the next unprocessed frame. There are situations in realtime mode + where the processing of a frame takes longer than the queue (or from head to + its fetch index). Over extended periods of this heavy processing, the video + frame in the consumer may never be updated (rendered=1)! To remedy this, the + consumer detects this and automatically moves the process_head towards the + tail, but even this may not be good enough. The only real remedy is to + increase buffers and suffer with poor latency. If lower latency is preferred, + then it may be better to not use realtime mode and permit audio + discontinuity. + + * src/framework/mlt_types.h: Add a MLT_FRAME() cast. And white-space align + the casts. + + * src/framework/mlt_deque.c, src/framework/mlt_deque.h: Add mlt_deque_peek() + with index. + +2010-06-15 Dan Dennedy + + * src/framework/mlt_consumer.c: Remove audio processing from the worker + threads. This has a bad interaction with the avformat producer, which + contains a buffer of unused decoded samples. This shifts audio processing to + the main consumer thread, which is often light anyways. I recommend to set + the threads property to 2 or more on the avformat consumer to offload video + encoding to separate threads from the audio processing and encoding. + + * src/modules/xine/filter_deinterlace.c: Make YADIF reentrant. + + * src/framework/mlt_consumer.c: Fix regression frames out-of-order. + + * src/framework/mlt_consumer.c: Fix compiler warning on this enum. + +2010-06-14 Dan Dennedy + + * src/framework/mlt_consumer.c: Change this log message back to debug level. + + * src/framework/mlt_consumer.c, src/framework/mlt_frame.c, + src/framework/mlt_tractor.c, src/modules/core/filter_imageconvert.c, + src/modules/sdl/consumer_sdl.c: Fix image format consistency and conversion. + +2010-06-11 Dan Dennedy + + * src/framework/mlt_consumer.c, src/framework/mlt_tractor.c: Remove the + tractor service locking. This completely inhibited parallelism, but removing + it also exposes more race conditions that require resolution. + + * src/framework/mlt_consumer.c: Add work queue to the parallel consumer. + This removes get_frame calls from the worker threads. The get_frame call must + take a service lock and that creates contention between the threads. + + * src/modules/xine/filter_deinterlace.c: Add service locks around yadif + context. + +2010-04-15 Dan Dennedy + + * src/framework/mlt_consumer.c: Change this log message to debug level. + +2010-03-04 Dan Dennedy + + * .../motion_est/filter_autotrack_rectangle.c, + src/modules/motion_est/filter_crop_detect.c, + src/modules/motion_est/filter_motion_est.c, + src/modules/normalize/filter_volume.c, src/modules/oldfilm/filter_dust.c, + src/modules/oldfilm/filter_lines.c, src/modules/plus/filter_affine.c, + src/modules/plus/transition_affine.c, + src/modules/qimage/producer_kdenlivetitle.c, + src/modules/qimage/producer_qimage.c, src/modules/sox/filter_sox.c, + src/modules/vorbis/producer_vorbis.c: Add service locks for parallelism. + + * src/modules/sdl/consumer_sdl_preview.c: Pass real_time, buffer, and prefill + properties onto normal sdl consumer. + + * src/modules/sdl/consumer_sdl.c: Log dropped frames at info log level. + + * src/modules/avformat/filter_avresample.c, + src/modules/avformat/filter_swscale.c, + src/modules/avformat/producer_avformat.c, + src/modules/core/filter_data_show.c, src/modules/core/filter_luma.c, + src/modules/core/filter_watermark.c, src/modules/core/producer_colour.c, + src/modules/core/transition_composite.c, src/modules/core/transition_luma.c, + src/modules/core/transition_region.c, src/modules/effectv/filter_burn.c, + src/modules/frei0r/filter_frei0r.c, src/modules/frei0r/producer_frei0r.c, + src/modules/frei0r/transition_frei0r.c, src/modules/gtk2/producer_pango.c, + src/modules/gtk2/producer_pixbuf.c, src/modules/kdenlive/filter_freeze.c, + src/modules/kdenlive/producer_framebuffer.c, + src/modules/resample/filter_resample.c: Add service locks for parallelism. + RGB filters and transitions from frei0r and burningtv are still not safe + enough. + + * src/framework/mlt_tractor.c: Set the proper size of "image" where known. + + * src/framework/mlt_consumer.c, src/framework/mlt_consumer.h: Add parallelism + to mlt_consumer. To use set real_time greater than 1 for frame-dropping or + less than -1 for no frame-dropping. It works better with a liberal buffer + size. You can still set prefill less than buffer size, but it must be at + least the same number as real_time, preferably a little higher to help with + frame ordering. + +2010-02-20 Dan Dennedy + + * src/framework/mlt_deque.c, src/framework/mlt_deque.h: Add + mlt_deque_insert(). + +2010-02-16 Dan Dennedy + + * src/framework/mlt_consumer.c, src/framework/mlt_consumer.h: Qualify queue, + mutex, and cond vars with frame_queue_. + 2011-01-23 Dan Dennedy + * src/modules/qimage/producer_qimage.c: Fix build outside MinGW. + + * src/modules/jackrack/configure: Fix getting LADSPA include dir from + listplugins. + + * configure, src/framework/mlt_version.h: Move to an interim version number. + +2011-01-17 Dan Dennedy + + * src/examples/Makefile: Make this example use the mlt++ pkg-config. This + more accurately demonstrates how to build a C++ app against mlt++. + + * src/modules/sdl/consumer_sdl.c, src/modules/sdl/consumer_sdl_still.c: SDL + tweaks for Windows discovered when embedded. + + * src/framework/Makefile, src/mlt++/Makefile, src/mlt++/config.h: On Windows + install .def and version-less DLLs to let apps build against us. + + * src/framework/mlt_factory.c, src/modules/avformat/configure, + src/modules/frei0r/factory.c, src/modules/jackrack/plugin_mgr.c: On Windows + locate plugins and data by directory relative to current directory. lib\mlt + lib\frei0r-1 lib\ladspa share\mlt share\ffmpeg + +2010-12-31 Dan Dennedy + + * src/modules/swfdec/Makefile: Fix swfdec build on MinGW. + + * src/modules/xml/consumer_xml.c, src/modules/xml/producer_xml.c: Cleanup + libxml changes for MinGW. + + * src/modules/jackrack/configure, src/modules/jackrack/jack_rack.c: Fix + JackRack build on MinGW. + + * src/modules/qimage/Makefile, src/modules/qimage/configure, + src/modules/qimage/producer_qimage.c, src/modules/qimage/qimage_wrapper.cpp, + src/modules/qimage/qimage_wrapper.h: Fix qimage build for MinGW. + +2010-12-30 Dan Dennedy + + * src/modules/sox/configure: Fix sox build on MinGW. + + * src/modules/frei0r/factory.c: Fix frei0r build on MinGW. + + * src/modules/xml/consumer_xml.c, src/modules/xml/producer_xml.c: Fix libxml2 + build on MinGW. + + * src/modules/gtk2/Makefile, src/modules/gtk2/consumer_gtk2.c, + src/modules/gtk2/producer_pixbuf.c: Fix gtk2 build on mingw. + +2010-12-15 Dan Dennedy + + * src/melt/Makefile, src/melt/io.c, src/melt/melt.c, + src/modules/sdl/consumer_sdl.c: Fix SDL and keyboard input on Win32. + +2010-12-05 Dan Dennedy + + * src/modules/sdl/Makefile: Fix build of mingw branch on Linux. Fixing this + here prior to merging into master. + +2010-12-03 Dan Dennedy + + * configure, src/framework/Makefile, src/melt/Makefile, src/melt/io.c, + src/mlt++/Makefile, src/mlt++/MltFactory.cpp, src/mlt++/MltFactory.h, + src/mlt++/config.h, src/mlt++/configure, src/modules/avformat/Makefile, + src/modules/core/Makefile, src/modules/core/producer_loader.c, + src/modules/kino/configure, src/modules/motion_est/Makefile, + src/modules/sdl/Makefile, src/modules/sdl/consumer_sdl.c, + src/modules/sdl/consumer_sdl_audio.c, src/modules/sdl/consumer_sdl_preview.c, + src/modules/sdl/consumer_sdl_still.c, src/win32/fnmatch.c, + src/win32/fnmatch.h, src/win32/win32.c: Initial port to Windows using MinGW. + Much of the credit goes to Michael Zenov. + +2011-01-23 Dan Dennedy + + * ChangeLog: Update ChangeLog for v0.6.2. + * Doxyfile, configure, docs/melt.1, src/framework/mlt_version.h: Set version to 0.6.2. * NEWS: Add v0.6.2 release notes. +2011-01-22 Till Theato + + * src/modules/rotoscoping/filter_rotoscoping.c: Rotoscoping: add parameter + alpha_operation with possible values: clear, max, min, add, sub + + * src/modules/rotoscoping/filter_rotoscoping.c: Fix not every point + calculated for the spline was used + +2011-01-21 Till Theato + + * src/modules/rotoscoping/filter_rotoscoping.c: Rotoscoping: - Rename + parameter polygon to spline - Add parameter precision setting the maximum + distance between two points when calculating the spline - some cleanup + +2011-01-20 Till Theato + + * src/modules/rotoscoping/filter_rotoscoping.c: Rotoscoping: Use cubic Bezier + spline instead of simple polygon to define masks + 2011-01-16 j-b-m * src/modules/plus/transition_affine.c: Add always_active property to affine transition. +2011-01-16 Till Theato + + * src/modules/rotoscoping/filter_rotoscoping.c: Rotoscoping: Add parameter + invert + + * src/modules/rotoscoping/Makefile, src/modules/rotoscoping/cJSON.c, + src/modules/rotoscoping/cJSON.h, + src/modules/rotoscoping/filter_rotoscoping.c: Rotoscoping: Add support for + simple keyframes - current limits: - number of points has to be equal for all + keyframes - points have to be in "correct" order (1. point in 1. kf will be + moved to 1. point in 2. kf, ...) - the parameter "polygon" is now formated + using json: - no keyframes: polygon="[[x,y], [x,y], ...]" - keyframes: + polygon= '{ "framepos1" : [[x,y], [x,y], ...], "framepos2" : [[x,y], [x,y], + ...], ...}' + +2011-01-15 Till Theato + + * src/modules/rotoscoping/filter_rotoscoping.c: rotoscoping filter: add modes + - rgb (everything but polygon black, default) - alpha (polygon alpha value = + 255, the rest = 0) - mask (polygon white, the rest black) + + * src/modules/rotoscoping/Makefile, src/modules/rotoscoping/factory.c, + src/modules/rotoscoping/filter_rotoscoping.c: Add rotoscoping filter (WIP): + It hides everything not in the polygon defined by the vertices given through + the "polygon" parameter + 2011-01-11 Dan Dennedy * src/modules/plus/transition_affine.c: fix compiler warning diff -Nru mlt-0.6.2/configure mlt-0.7.2/configure --- mlt-0.6.2/configure 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/configure 2011-05-02 05:59:12.000000000 +0000 @@ -1,7 +1,7 @@ #!/bin/sh -export version=0.6.2 -export soversion=3 +export version=0.7.2 +export soversion=4 show_help() { @@ -19,6 +19,7 @@ --datadir=directory - data directory (default: $prefix/share) --mandir=directory - man documentation directory (default: $prefix/share/man) --enable-gpl - Enable GPL components + --enable-debug - Compile without optimizations support (default: off) --disable-debug - Compile without debug support (default: on) --disable-mmx - Compile without MMX support (default: on) --disable-sse - Compile without SSE support (default: on) @@ -69,42 +70,55 @@ [ "$arch" != "" ] && echo "TARGETARCH=-march=$arch" [ "$cpu" != "" ] && echo "TARGETCPU=-mcpu=$cpu" - echo "OPTIMISATIONS=-O2 -pipe -fomit-frame-pointer" + [ "$optimisations" = "true" ] && + echo "OPTIMISATIONS=-O2 -pipe -fomit-frame-pointer" - echo "CFLAGS+=-Wall -fPIC -DPIC \$(TARGETARCH) \$(TARGETCPU) \$(OPTIMISATIONS) \$(MMX_FLAGS) \$(SSE_FLAGS) \$(SSE2_FLAGS) \$(DEBUG_FLAGS) \$(LARGE_FILE)" + echo "CFLAGS+=-Wall -DPIC \$(TARGETARCH) \$(TARGETCPU) \$(OPTIMISATIONS) \$(MMX_FLAGS) \$(SSE_FLAGS) \$(SSE2_FLAGS) \$(DEBUG_FLAGS) \$(LARGE_FILE)" case $targetos in Darwin) sysctl -a hw | grep "x86_64: 1" > /dev/null && echo "ARCH_X86_64=1" && echo "CFLAGS+=-DARCH_X86_64" - echo "CFLAGS+=-D__DARWIN__ `sdl-config --cflags`" + echo "CFLAGS+=-fPIC -D__DARWIN__ `sdl-config --cflags`" echo "SHFLAGS=-dynamiclib" echo "LDFLAGS+=`sdl-config --libs`" ;; Linux) [ "$(uname -m)" = "x86_64" ] && echo "ARCH_X86_64=1" && echo "CFLAGS+=-DARCH_X86_64" - echo "OPTIMISATIONS+=-ffast-math" - echo "CFLAGS+=-pthread" + [ "$optimisations" = "true" ] && + echo "OPTIMISATIONS+=-ffast-math" + echo "CFLAGS+=-fPIC -pthread" echo "SHFLAGS=-shared" echo "LIBDL=-ldl" echo "RDYNAMIC=-rdynamic" echo "LDFLAGS+=-Wl,--no-undefined -Wl,--as-needed" ;; FreeBSD) - [ "$(uname -m)" = "x86_64" ] && echo "ARCH_X86_64=1" && echo "CFLAGS+=-DARCH_X86_64" - echo "OPTIMISATIONS+=-ffast-math" - echo "CFLAGS+=-pthread" + [ "$(uname -m)" = "amd64" -o "$(uname -m)" = "x86_64" ] && echo "ARCH_X86_64=1" && echo "CFLAGS+=-DARCH_X86_64" + [ "$optimisations" = "true" ] && + echo "OPTIMISATIONS+=-ffast-math" + echo "CFLAGS+=-fPIC -pthread" echo "SHFLAGS=-shared" echo "RDYNAMIC=-rdynamic" echo "LDFLAGS+=-Wl,--no-undefined -Wl,--as-needed" ;; NetBSD) [ "$(uname -m)" = "amd64" ] && echo "ARCH_X86_64=1" && echo "CFLAGS+=-DARCH_X86_64" - echo "OPTIMISATIONS+=-ffast-math" + [ "$optimisations" = "true" ] && + echo "OPTIMISATIONS+=-ffast-math" echo "CFLAGS+=-pthread" echo "SHFLAGS=-shared" echo "RDYNAMIC=-rdynamic" echo "LDFLAGS+=-Wl,--no-undefined -Wl,--as-needed" ;; + MinGW) + [ "$(uname -m)" = "x86_64" ] && echo "ARCH_X86_64=1" && echo "CFLAGS+=-DARCH_X86_64" + [ "$optimisations" = "true" ] && + echo "OPTIMISATIONS+=-ffast-math" + echo "SHFLAGS=-shared" + echo "LIBDL=-ldl" + echo "RDYNAMIC=" + echo "LDFLAGS+=-Wl,--no-undefined -Wl,--as-needed" + ;; *) ;; esac @@ -163,6 +177,7 @@ export datadir="" export mandir="" export help=0 +export optimisations=true export debug=true export mmx=true export sse=true @@ -182,6 +197,10 @@ Linux|FreeBSD|NetBSD) LIBSUF=".so" ;; + MINGW32_NT-*) + targetos="MinGW" + LIBSUF=".dll" + ;; *) LIBSUF=".so" ;; @@ -197,6 +216,7 @@ --libdir=* ) libdir="${i#--libdir=}" ;; --datadir=* ) datadir="${i#--datadir=}" ;; --mandir=* ) mandir="${i#--mandir=}" ;; + --enable-debug ) optimisations=false ;; --disable-debug ) debug=false ;; --disable-mmx ) mmx=false; sse=false; sse2=false ;; --disable-sse ) sse=false; sse2=false ;; diff -Nru mlt-0.6.2/debian/changelog mlt-0.7.2/debian/changelog --- mlt-0.6.2/debian/changelog 2011-02-22 22:48:56.000000000 +0000 +++ mlt-0.7.2/debian/changelog 2011-05-13 19:23:41.000000000 +0000 @@ -1,8 +1,37 @@ -mlt (0.6.2-2~ppa1~lucid1) lucid; urgency=low +mlt (0.7.2-1~ppa1~lucid1) lucid; urgency=low - * Backport to lucidbleed ppa. + * Backport to Lucidbleed ppa. - -- Nicola Ferralis Tue, 22 Feb 2011 17:47:51 -0500 + -- Nicola Ferralis Fri, 13 May 2011 15:22:29 -0400 + +mlt (0.7.2-1) unstable; urgency=low + + * New upstream release. + + -- Patrick Matthäi Tue, 03 May 2011 19:43:32 +0200 + +mlt (0.7.0-2) unstable; urgency=low + + * Bump Standards-Version to 3.9.2 (no changes needed). + * Wrap build dependencies. + * Build with enabled hardening-wrapper. + + -- Patrick Matthäi Sat, 30 Apr 2011 20:44:02 +0200 + +mlt (0.7.0-1) unstable; urgency=low + + * New upstream release. + Closes: #606123 + - Bumped SONAME of libmlt to 4. + + -- Patrick Matthäi Mon, 28 Mar 2011 21:05:04 +0200 + +mlt (0.6.2-3) unstable; urgency=low + + * Remove python-mlt3.install, it is done automagic by debian/rules. + Thanks to Evgeni Golov. + + -- Patrick Matthäi Sun, 20 Feb 2011 11:16:32 +0100 mlt (0.6.2-2) unstable; urgency=low diff -Nru mlt-0.6.2/debian/control mlt-0.7.2/debian/control --- mlt-0.6.2/debian/control 2011-02-07 17:03:14.000000000 +0000 +++ mlt-0.7.2/debian/control 2011-05-03 17:43:46.000000000 +0000 @@ -2,20 +2,37 @@ Priority: optional Maintainer: Fathi Boudra Uploaders: Patrick Matthäi -Build-Depends: debhelper (>= 7.0.50), ffmpeg, - kdelibs5-dev, ladspa-sdk, libavdevice-dev, libavformat-dev, libdv4-dev, - libgtk2.0-dev, libjack-dev, libquicktime-dev, libsamplerate-dev, - libsdl1.2-dev, libsox-dev (>= 14.3.0), libswscale-dev, libvorbis-dev, - libxine-dev, libxml2-dev, imagemagick, frei0r-plugins-dev, swig, - python-dev, python-support -Standards-Version: 3.9.1 +Build-Depends: debhelper (>= 7.0.50), + ffmpeg, + kdelibs5-dev, + ladspa-sdk, + libavdevice-dev, + libavformat-dev, + libdv4-dev, + libgtk2.0-dev, + libjack-dev, + libquicktime-dev, + libsamplerate-dev, + libsdl1.2-dev, + libsox-dev (>= 14.3.0), + libswscale-dev, + libvorbis-dev, + libxine-dev, + libxml2-dev, + imagemagick, + frei0r-plugins-dev, + swig, + python-dev, + hardening-wrapper, + python-support +Standards-Version: 3.9.2 Section: libs Homepage: http://www.mltframework.org Package: libmlt-dev Section: libdevel Architecture: any -Depends: ${misc:Depends}, libmlt3 (= ${binary:Version}) +Depends: ${misc:Depends}, libmlt4 (= ${binary:Version}) Description: multimedia framework (development) MLT is an open source multimedia framework, designed and developed for television broadcasting. It provides a toolkit for broadcasters, video @@ -27,12 +44,12 @@ This package contains the static libraries and headers for developing applications that use the MLT multimedia framework. -Package: libmlt3 +Package: libmlt4 Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Recommends: libmlt-data (>= ${source:Version}) -Conflicts: libmlt0.2, libmlt0.2.5, libmlt1, libmlt2 -Replaces: libmlt0.2, libmlt0.2.5, libmlt1, libmlt2 +Conflicts: libmlt0.2, libmlt0.2.5, libmlt1, libmlt2, libmlt3 +Replaces: libmlt0.2, libmlt0.2.5, libmlt1, libmlt2, libmlt3 Description: multimedia framework (runtime) MLT is an open source multimedia framework, designed and developed for television broadcasting. It provides a toolkit for broadcasters, video @@ -47,7 +64,7 @@ Package: libmlt-data Architecture: all Depends: ${misc:Depends} -Enhances: libmlt3 +Enhances: libmlt4 Description: multimedia framework (data) MLT is an open source multimedia framework, designed and developed for television broadcasting. It provides a toolkit for broadcasters, video @@ -93,7 +110,8 @@ Section: debug Priority: extra Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, libmlt3 (= ${binary:Version}), libmlt++3 (= ${binary:Version}) +Depends: ${shlibs:Depends}, ${misc:Depends}, libmlt4 (= ${binary:Version}), + libmlt++3 (= ${binary:Version}) Description: multimedia framework (debugging symbols) MLT is an open source multimedia framework, designed and developed for television broadcasting. It provides a toolkit for broadcasters, video diff -Nru mlt-0.6.2/debian/libmlt3.install mlt-0.7.2/debian/libmlt3.install --- mlt-0.6.2/debian/libmlt3.install 2011-02-07 17:03:14.000000000 +0000 +++ mlt-0.7.2/debian/libmlt3.install 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -usr/lib/libmlt.so.* -usr/lib/mlt/libmlt*.so -usr/lib/mlt/* diff -Nru mlt-0.6.2/debian/libmlt4.install mlt-0.7.2/debian/libmlt4.install --- mlt-0.6.2/debian/libmlt4.install 1970-01-01 00:00:00.000000000 +0000 +++ mlt-0.7.2/debian/libmlt4.install 2011-05-03 17:43:46.000000000 +0000 @@ -0,0 +1,3 @@ +usr/lib/libmlt.so.* +usr/lib/mlt/libmlt*.so +usr/lib/mlt/* diff -Nru mlt-0.6.2/debian/python-mlt3.install mlt-0.7.2/debian/python-mlt3.install --- mlt-0.6.2/debian/python-mlt3.install 2011-02-07 17:03:14.000000000 +0000 +++ mlt-0.7.2/debian/python-mlt3.install 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -src/swig/python/mlt.py usr/lib/python2.5/site-packages/ -src/swig/python/_mlt.so usr/lib/python2.5/site-packages/ diff -Nru mlt-0.6.2/debian/rules mlt-0.7.2/debian/rules --- mlt-0.6.2/debian/rules 2011-02-07 17:03:14.000000000 +0000 +++ mlt-0.7.2/debian/rules 2011-05-03 17:43:46.000000000 +0000 @@ -1,5 +1,7 @@ #!/usr/bin/make -f +export DEB_BUILD_HARDENING=1 + # Enable motion estimation, MMX and SSE on amd64 architecture ifeq ($(DEB_HOST_ARCH),$(findstring $(DEB_HOST_ARCH), "amd64")) EXTRA_CONFIGURE_OPTS += --enable-motion_est --enable-mmx --enable-sse diff -Nru mlt-0.6.2/demo/consumers.ini mlt-0.7.2/demo/consumers.ini --- mlt-0.6.2/demo/consumers.ini 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/demo/consumers.ini 2011-05-02 05:59:12.000000000 +0000 @@ -4,9 +4,6 @@ SDL Progressive sdl progressive=1 XML to Terminal xml XML to File xml: -MainConcept DV to /dev/dv1394/0 mcdv:/dev/dv1394/0 rescale=nearest buffer=25 libdv to /dev/dv1394/0 libdv:/dev/dv1394/0 rescale=nearest buffer=25 -BlueFish444 PAL bluefish:1 -BlueFish444 NTSC bluefish:1 standard=NTSC -BlueFish444 PAL Prog LL bluefish:1 progressive=1 buffer=1 frames=4 -BlueFish444 NTSC Prog LL bluefish:1 standard=NTSC progressive=1 buffer=1 frames=4 +DeckLink decklink +DeckLink Prog LL decklink progressive=1 buffer=1 diff -Nru mlt-0.6.2/demo/demo mlt-0.7.2/demo/demo --- mlt-0.6.2/demo/demo 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/demo/demo 2011-05-02 05:59:12.000000000 +0000 @@ -1,5 +1,7 @@ #!/bin/bash +export MLT_PROFILE=dv_pal + function show_consumers( ) { awk -F '\t' '{ printf( "%d. %s\n", ++ i, $1 ); }' < consumers.ini diff -Nru mlt-0.6.2/demo/demo.ini mlt-0.7.2/demo/demo.ini --- mlt-0.6.2/demo/demo.ini 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/demo/demo.ini 2011-05-02 05:59:12.000000000 +0000 @@ -13,7 +13,7 @@ mlt_voiceover Voiceover 2 clips with title clip1.dv,clip2.mpeg,music1.ogg mlt_avantika_title GJ-TTAvantika title pango.mlt mlt_title_over_gfx Title over graphic watermark1.png,clip1.dv -mlt_slideshow Slideshow Scotland +mlt_slideshow Slideshow photos mlt_bouncy Bouncy, Bouncy clip1.dv,clip3.dv mlt_bouncy_ball Bouncy, Bouncy Ball clip1.mpeg,clip3.mpeg,circle.png mlt_news Breaking News clip1.dv,clip2.dv @@ -25,4 +25,6 @@ mlt_push Push wipe clip1.mpeg, clip2.mpeg mlt_ticker Ticker tape clip1.dv mlt_attributes Attributes clip1.dv -mlt_slideshow_black Composite slideshow Scotland +mlt_slideshow_black Composite slideshow photos +mlt_slideshow2 Ken Burns slideshow photos +mlt_pango_keyframes Pango Keyframed Markup pango_keyframes.mpl diff -Nru mlt-0.6.2/demo/mlt_pango_keyframes mlt-0.7.2/demo/mlt_pango_keyframes --- mlt-0.6.2/demo/mlt_pango_keyframes 1970-01-01 00:00:00.000000000 +0000 +++ mlt-0.7.2/demo/mlt_pango_keyframes 2011-05-02 05:59:12.000000000 +0000 @@ -0,0 +1,4 @@ +melt \ +color:#03CF0 \ +-filter watermark:pango_keyframes.mpl composite.halign=c composite.valign=m \ +$* diff -Nru mlt-0.6.2/demo/pango_keyframes.mpl mlt-0.7.2/demo/pango_keyframes.mpl --- mlt-0.6.2/demo/pango_keyframes.mpl 1970-01-01 00:00:00.000000000 +0000 +++ mlt-0.7.2/demo/pango_keyframes.mpl 2011-05-02 05:59:12.000000000 +0000 @@ -0,0 +1,4 @@ +0=Hello +40= +50=World~the end +90= diff -Nru mlt-0.6.2/demo/README mlt-0.7.2/demo/README --- mlt-0.6.2/demo/README 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/demo/README 2011-05-02 05:59:12.000000000 +0000 @@ -215,3 +215,14 @@ the compositor when viewed on an analog monitor using a DV or BlueFish444 consumer. The demo also shows the potientional for using and extending the existing set of services for a full blown news ticker implementation. + +Pango Keyframed Markup + + You can create timed text and subtitles using a .mpl file, which is a + properties format file. A properties file contains key=value pairs on + separate lines. For .mpl the key is a frame number and the value is + Pango Markup Language. A tilde is interpreted as a new line. This + example also demonstrates using the watermark and the alignment + properties of its encapsulated composite transition where halign + is the horizontal, valign is the vertical, c is for center, and m + is for middle. diff -Nru mlt-0.6.2/docs/install.txt mlt-0.7.2/docs/install.txt --- mlt-0.6.2/docs/install.txt 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/docs/install.txt 2011-05-02 05:59:12.000000000 +0000 @@ -23,11 +23,9 @@ + framework - The mlt media framework + modules - All services are defined here + avformat - libavformat dependent services - + bluefish - Bluefish dependent services (*) + core - Independent MLT services + dv - libdv dependent services + gtk2 - pango and pixbuf dependent services - + mainconcept - mainconcept dependent services (*) + normalize - audio normalisation functions (**) + plus - throwaway silliness + resample - libresample dependent services (**) @@ -64,18 +62,12 @@ avformat Provided from ffmpeg CVS and compiled as a shared library. URL: http://ffmpeg.sf.net ----------- ---------------------------------------------------------- - bluefish Bluefish hardware and software development kit - URL: http://www.bluefish444.com - ----------- ---------------------------------------------------------- dv libdv 0.102 or later. URL: http://libdv.sf.net ----------- ---------------------------------------------------------- gtk2 GTK2 and associated dependencies. URL: http://www.gtk.org ----------- ---------------------------------------------------------- - mainconcept Mainconcept MPEG and DVCPRO Release SDKs. - URL: http://www.mainconcept.com - ----------- ---------------------------------------------------------- resample libsamplerate 0.15 or later URL: http://www.mega-nerd.com/SRC/ (GPL) ----------- ---------------------------------------------------------- diff -Nru mlt-0.6.2/docs/melt.1 mlt-0.7.2/docs/melt.1 --- mlt-0.6.2/docs/melt.1 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/docs/melt.1 2011-05-02 05:59:12.000000000 +0000 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.36. -.TH MELT "1" "January 2011" "MLT melt 0.6.2" "User Commands" +.TH MELT "1" "May 2011" "MLT melt 0.7.2" "User Commands" .SH NAME -melt \- manual page for MLT melt 0.6.2 +melt \- author, play, and encode multitrack audio/video compositions .SH SYNOPSIS .B melt [\fIoptions\fR] [\fIproducer \fR[\fIname=value\fR]\fI* \fR]\fI+\fR @@ -78,6 +78,18 @@ \fB\-query\fR "transitions" | "transition"=id List transitions, show info about one .TP +\fB\-query\fR "profiles" | "profile"=id +List profiles, show info about one +.TP +\fB\-query\fR "formats" +List audio/video formats +.TP +\fB\-query\fR "audio_codecs" +List audio codecs +.TP +\fB\-query\fR "video_codecs" +List video codecs +.TP \fB\-serialise\fR [filename] Write the commands to a text file .TP @@ -107,7 +119,7 @@ .PP For more help: .SH COPYRIGHT -Copyright \(co 2002-2009 Ushodaya Enterprises Limited +Copyright \(co 2002-2011 Ushodaya Enterprises Limited .br This is free software; see the source for copying conditions. There is NO diff -Nru mlt-0.6.2/docs/melt.txt mlt-0.7.2/docs/melt.txt --- mlt-0.6.2/docs/melt.txt 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/docs/melt.txt 2011-05-02 05:59:12.000000000 +0000 @@ -2,7 +2,8 @@ Copyright (C) 2004-2009 Ushodaya Enterprised Limited Author: Charles Yates -Last Revision: 2009-05-08 +Author: Dan Dennedy +Last Revision: 2011-04-03 MELT @@ -46,6 +47,10 @@ -query "filters" | "filter"=id List filters or show info about one -query "producers" | "producer"=id List producers or show info about one -query "transitions" | "transition"=id List transitions or show info about one + -query "profiles" | "profile"=id List profiles or show info about one + -query "formats" List audio/video formats + -query "audio_codecs" List audio codecs + -query "video_codecs" List video codecs -serialise [filename] Write the commands to a text file -silent Do not display position/transport help -split relative-frame Split the last cut into two cuts diff -Nru mlt-0.6.2/docs/mlt-xml.txt mlt-0.7.2/docs/mlt-xml.txt --- mlt-0.6.2/docs/mlt-xml.txt 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/docs/mlt-xml.txt 2011-05-02 05:59:12.000000000 +0000 @@ -33,7 +33,7 @@ In the mlt model, producers are created and attached to 'consumers' - consumers are software playback components (such as SDL), or wrappers for - hardware drivers (such as bluefish) or even the XML serialising + hardware drivers (such as sdi) or even the XML serialising consumer itself (the latter doesn't receive frames - it merely interrogates the connected producer for its configuration). diff -Nru mlt-0.6.2/docs/services.txt mlt-0.7.2/docs/services.txt --- mlt-0.6.2/docs/services.txt 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/docs/services.txt 2011-05-02 05:59:12.000000000 +0000 @@ -174,67 +174,6 @@ DVCPRO is incorrectly identified as 16:9 aspect ratio. You must use libdv from CVS or a post 0.101 release. - mcdv (Proprietary) - - Description - - MainConcept based dv decoder for video and audio. - - Constructor Argument - - 'file' - produce a/v from file - - Initialisation Properties - - int in - in point - int out - out point - - Read Only Properties - - string resource - file location - double fps - output frames per second - int length - duration of resource (in frames) - - Dependencies - - MainConcept DV or DVCPRO SDK, libdv. - "dv_sdk" installed parallel to mlt. - - Known Bugs - - None - - mcmpeg (Proprietary) - - Description - - MainConcept based mpeg decoder for video and audio. - - Constructor Argument - - 'file' - produce a/v from file - - Initialisation Properties - - int in - in point - int out - out point - - Read Only Properties - - string resource - file location - double fps - output frames per second - double aspect_ratio - sample aspect ratio of video - int length - duration of resource (in frames) - - Dependencies - - MainConcept MPEG SDK. - "mpeg_sdk_release" installed parallel to mlt. - - Known Bugs - - None. - noise Description @@ -812,45 +751,6 @@ none - mcrescale - - Description - - Scale the producer video frame size to match the consumer. - This filter is designed for use as a normaliser for the loader producer. - - Constructor Argument - - interpolation - the rescaling method, one of: - nearest (lowest quality, fastest), - bilinear (default; good quality, moderate speed), - hyper (best quality, slowest). - - Initialisation Properties - - int in - in point - int out - out point - - Mutable Properties - - string interpolation - see constructor argument above - - If a property "consumer_aspect_ratio" exists on the frame, then - rescaler normalises the producer's aspect ratio and maximises the - size of the frame, but may not produce the consumer's requested - dimension. Therefore, this option works best in conjunction with the - resize filter. This behavior can be disabled by another service by - either removing the property, setting it to zero, or setting - frame property "distort" to 1. - - Dependencies - - the mainconcept rescaling sdk. - - Known Bugs - - none - mirror Description @@ -1156,8 +1056,8 @@ string resource - the producer to use string factory - producer required for the resource (default: 'loader') - string geometry - composite geometry - string distort - control scaling + string composite.geometry - composite geometry + string composite.distort - control scaling int in - in point int out - out point @@ -1412,44 +1312,6 @@ Plenty. - bluefish (Proprietary) - - Description - - BlueFish444 audio and video output module. - - Constructor Argument - - card - a numeric card id starting at 1, default is 1. - - Initialisation Properties - - string standard - "PAL" (default) or "NTSC" - - default is based upon MLT_NORMALISATION - environment variable, which defaults to PAL. - int frames - the number of DMA video frames. default is 8. - minimum is 2. maximum on my system is 11. - int buffer - the number of frames to buffer within MLT, minimum 1, - default 25. - string rescale - a rescale method, see the Filters/rescale. - - Read Only Properties - - none - - Dependencies - - BlueVelvet SDK installed parallel to mlt in "bluefish." - - Known Bugs - - Does not work with any service that uses pipes! - - If mlt crashes, you might need to reload the BlueDriver kernel - module due to unreleased DMA buffers. - - Only supports 2 channel audio at the moment. - libdv Description @@ -1482,41 +1344,6 @@ none - mcmpeg - - Description - - Mainconcept MPEG encoder. - - Constructor Argument - - string target - the filename to write to. - - Initialisation Properties - - int buffer - the number of frames to buffer, minimum 1, default 25. - string rescale - a rescale method, see the Filters/rescale. - string format - vcd [default], svcd or dvd provide base settings - int motion_search_type - 0 to 16 - reduces quality/cpu usage - int gop - group of picture size (default: format dependent) - - Mutable Properties - - int progressive - indicates whether to use progressive or field- - based rendering, default 0 (off). - - Read Only Properties - - none - - Dependencies - - Mainconcept MPEG SDK - - Known Bugs - - none - sdl Description diff -Nru mlt-0.6.2/Doxyfile mlt-0.7.2/Doxyfile --- mlt-0.6.2/Doxyfile 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/Doxyfile 2011-05-02 05:59:12.000000000 +0000 @@ -31,7 +31,7 @@ # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = 0.6.2 +PROJECT_NUMBER = 0.7.2 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. diff -Nru mlt-0.6.2/NEWS mlt-0.7.2/NEWS --- mlt-0.6.2/NEWS 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/NEWS 2011-05-02 05:59:12.000000000 +0000 @@ -1,7 +1,64 @@ MLT Release Notes ----------------- -Version 0.6.2 +Version 0.7.2 - May 1, 2011 + +This is a minor release to fix a few things between the 0.7.0 release +and the release of Kdenlive 0.8. I recommend Kdenlive v0.8 users to +upgrade to this version of Mlt. Beyond that there are some exciting +additions to the Blackmagic Design DeckLink plugin! + +Framework + * Added mlt_profile_list(). + +Modules + * Added decklink producer (i.e. capture, live encoding). + * Added keyer output for decklink consumer. + * Added AVOptions to the avformat service metadata. + * Added support for new major API versions (53) of FFmpeg. + +Melt + * Added '-query profile' option. + * Added '-query formats', '-query audio_codecs' and '-query video_codecs'. + +The recommended version of FFmpeg for use with this release is 0.6.1. + + +Version 0.7.0 - March 27, 2011 + +This is a major new release due to signficant additions to API, framework, +and build. + +Build + * Added support for Windows via MinGW. + * Enabled linsys module by default. + * Disabled VDPAU by default and added --avformat-vdpau to enable it. + * Added support for swfdec 0.7. + +Framework: + * Added parallelism to mlt_consumer when 'real_time' > 1 or < -1. + * Added mlt_deque_insert() and mlt_deque_peek(). + * Added mlt_profile parameter to mlt_producer_new(). + * Let transitions with no out point run forever. + * Added mlt_frame_unique_properties(). + * Added mlt_frame_set_image() and mlt_frame_set_alpha(). + * Added mlt_image_format_size() and mlt_audio_format_size(). + * Added mlt_filter_get_length() and mlt_transition_get_length(). + * Added mlt_filter_get_progress(), mlt_transition_get_progress(), + and mlt_transition_get_progress_delta(). + * Added mlt_filter_get_position() and mlt_transition_get_position(). + * Added mlt_properties_lock() and mlt_properties_unlock(). + +Modules + * Added rotoscoping filter. + * Improve libavdevice support (V4L2, ALSA, libdc1394). + * Added support for new FFmpeg metadata API. + * Various fixes, refactoring, and improvements. + +The recommended version of FFmpeg for use with this release is 0.6.1. + + +Version 0.6.2 - January 23, 2011 This is just a minor release to address a few things prior to introducing major changes from other branches. @@ -16,7 +73,7 @@ The recommended version of FFmpeg for use with this release is 0.6.1. -Version 0.6.0 +Version 0.6.0 - January 1, 2011 The recommended version of FFmpeg for use with this release is 0.6.1. There were quite a few enhancements and changes including a minor interface @@ -53,7 +110,7 @@ based rendering available only explicitly. -Version 0.5.10 +Version 0.5.10 - September 13, 2010 This is a quick followup to the 0.5.8 release to address an issue I want to address immediately. I noticed an extra unconditional colorspace conversion @@ -61,7 +118,7 @@ have enabled the avcolor_space filter on OS X since it works now. -Version 0.5.8 +Version 0.5.8 - September 12, 2010 The recommended version of FFmpeg for use with this release is 0.6. This is a maintenance release to address some bugs that appeared @@ -77,7 +134,7 @@ * Added support for inline images in kdenlivetitler. -Version 0.5.6 +Version 0.5.6 - June 20, 2010 The recommended version of FFmpeg for use with this release is 0.6. This is a maintenance release to address some bugs that appeared @@ -88,7 +145,7 @@ * Added interlaced field rendering to kdenlivetitle producer. -Version 0.5.4 +Version 0.5.4 - April 19, 2010 The recommended version of FFmpeg for use with this release is SVN r21322. This is another maintenance release to address some bugs that appeared @@ -99,7 +156,7 @@ * Linsys SDI consumer now configures itself from MLT profile. -Version 0.5.2 +Version 0.5.2 - March 10, 2010 The recommended version of FFmpeg for use with this release is SVN r21322. This is a minor maintenance release, but it is interesting because it now @@ -115,7 +172,7 @@ * Fixed compiling yadif for non-sse2 builds -Version 0.5.0 +Version 0.5.0 - February 15, 2010 The recommended version of FFmpeg for use with this release is SVN r21322. This is an enhancement release, confined mainly to the modules rather than @@ -164,14 +221,14 @@ * change descriptions from using Hz to fps -Version 0.4.10 +Version 0.4.10 - December 8, 2009 The recommended version of FFmpeg for use with this release is SVN r19873. This is "hotfix" for the 0.4.8 release that fixes a couple of regression bugs introduced just before the release. -Version 0.4.8 +Version 0.4.8 - December 7, 2009 The recommended version of FFmpeg for use with this release is SVN r19873. This is mainly a maintenance release. Besides bug fixes here are other @@ -190,7 +247,7 @@ * qimage/kdenlivetitle: add typewriter effect -Version 0.4.6 +Version 0.4.6 - October 7, 2009 The recommended version of FFmpeg for use with this release is SVN r19873. This release is an enhancement release along with numerous build, A/V synch, @@ -227,7 +284,7 @@ - added mlt_audio_float -Version 0.4.4 +Version 0.4.4 - June 30, 2009 The recommended version of FFmpeg for use with this release is 0.5.0. This release is a minor maintenance update to the 0.4.2 - just build and @@ -244,14 +301,14 @@ * added Lua binding via SWIG -Version 0.4.2 +Version 0.4.2 - May 30, 2009 The recommended version of FFmpeg for use with this release is 0.5.0. This release is a minor maintenance update to the 0.4.0 - just build and bug fixes. -Version 0.4.0 +Version 0.4.0 - May 17, 2009 The recommended version of FFmpeg for use with this release is 0.5.0. @@ -270,7 +327,7 @@ * improve seeking performance of DNxHD and HuffYUV -Version 0.3.8 +Version 0.3.8 - April 15, 2009 The recommended version of FFmpeg for use with this release is SVN r17923. @@ -292,7 +349,7 @@ * sdl: added window_background color property -Version 0.3.6 +Version 0.3.6 - February 2, 2009 The recommended version of FFmpeg for use with this release is SVN r16849. @@ -311,7 +368,7 @@ f-list[[,]acodec-list][[,]vcodec-list] -Version 0.3.4 +Version 0.3.4 - December 29, 2008 The recommended version of FFmpeg for use with this release is SVN r16313. @@ -336,7 +393,7 @@ * improved build for OS X and x86-64 and improved handling of mmx/sse -Version 0.3.2 +Version 0.3.2 - November 10, 2008 In addition to bug fixes detailed in the ChangeLog, here is a list of enhancements. @@ -360,7 +417,7 @@ * removed realtime process scheduling -Version 0.3.0 +Version 0.3.0 - August 5, 2008 framework: * fix bugs with introduction of mlt_profile in v0.2.4 @@ -400,7 +457,7 @@ * added -profile option and support for progress=1 for kdenlive -Version 0.2.4 +Version 0.2.4 - August 4, 2007 * framework: new extensible profiles system to replace MLT_NORMALISATION * module avformat: interlaced coding support for ffmpeg/libavcodec @@ -410,7 +467,7 @@ * numerous bugfixes -Version 0.2.3 +Version 0.2.3 - April 9, 2007 * Addition of kdenlive module * Support for ffmpeg from subversion @@ -418,25 +475,25 @@ * Copyright and license cleanup -Version 0.2.2 +Version 0.2.2 - May 27, 2006 * Prepared specifically for the kdenlive 0.3 release. * Contains some patches to support rgb24a output for the gdk-pixbuf and qimage producers as well as some minor bugfixes. -Version 0.2.1 +Version 0.2.1 - December 5, 2005 * Many improvements since initial releases due to development of Shotcut and Jahshaka editing interfaces. -Version 0.1.1 +Version 0.1.1 - June 9, 2004 * Minor modifications and bug fixes from the previous release. Better ffmpeg/avformat integration and more reliable playback. -Version 0.1.0 +Version 0.1.0 - May 6, 2004 * First official release diff -Nru mlt-0.6.2/profiles/atsc_1080p_50 mlt-0.7.2/profiles/atsc_1080p_50 --- mlt-0.6.2/profiles/atsc_1080p_50 1970-01-01 00:00:00.000000000 +0000 +++ mlt-0.7.2/profiles/atsc_1080p_50 2011-05-02 05:59:12.000000000 +0000 @@ -0,0 +1,11 @@ +description=HD 1080p 50 fps +frame_rate_num=50 +frame_rate_den=1 +width=1920 +height=1080 +progressive=1 +sample_aspect_num=1 +sample_aspect_den=1 +display_aspect_num=16 +display_aspect_den=9 +colorspace=709 diff -Nru mlt-0.6.2/profiles/atsc_1080p_5994 mlt-0.7.2/profiles/atsc_1080p_5994 --- mlt-0.6.2/profiles/atsc_1080p_5994 1970-01-01 00:00:00.000000000 +0000 +++ mlt-0.7.2/profiles/atsc_1080p_5994 2011-05-02 05:59:12.000000000 +0000 @@ -0,0 +1,11 @@ +description=HD 1080p 59.94 fps +frame_rate_num=60000 +frame_rate_den=1001 +width=1920 +height=1080 +progressive=1 +sample_aspect_num=1 +sample_aspect_den=1 +display_aspect_num=16 +display_aspect_den=9 +colorspace=709 diff -Nru mlt-0.6.2/profiles/atsc_1080p_60 mlt-0.7.2/profiles/atsc_1080p_60 --- mlt-0.6.2/profiles/atsc_1080p_60 1970-01-01 00:00:00.000000000 +0000 +++ mlt-0.7.2/profiles/atsc_1080p_60 2011-05-02 05:59:12.000000000 +0000 @@ -0,0 +1,11 @@ +description=HD 1080p 60 fps +frame_rate_num=60 +frame_rate_den=1 +width=1920 +height=1080 +progressive=1 +sample_aspect_num=1 +sample_aspect_den=1 +display_aspect_num=16 +display_aspect_den=9 +colorspace=709 diff -Nru mlt-0.6.2/setenv mlt-0.7.2/setenv --- mlt-0.6.2/setenv 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/setenv 2011-05-02 05:59:12.000000000 +0000 @@ -8,13 +8,8 @@ export LD_LIBRARY_PATH=\ `pwd`/src/framework:\ `pwd`/src/mlt++:\ -`pwd`/src/modules/bluefish:\ -`pwd`/../BlueLinuxDriver/install/lib:\ -`pwd`/../mpeg_sdk_release/bin:\ -`pwd`/../dvcpro_sdk_release/lib:\ -`pwd`/../sr_sdk_release:\ $LD_LIBRARY_PATH -[ $(uname -s) = Darwin ] && export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH +#[ $(uname -s) = Darwin ] && export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH export PATH=`pwd`/src/melt:$PATH diff -Nru mlt-0.6.2/src/examples/Makefile mlt-0.7.2/src/examples/Makefile --- mlt-0.6.2/src/examples/Makefile 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/examples/Makefile 2011-05-02 05:59:12.000000000 +0000 @@ -1,5 +1,5 @@ -CXXFLAGS += -Wall -g `pkg-config mlt-framework --cflags` -I ../mlt++ -LDFLAGS += -L../mlt++ -lmlt++ `pkg-config mlt-framework --libs` +CXXFLAGS += -Wall -g `pkg-config mlt++ --cflags` +LDFLAGS += `pkg-config mlt++ --libs` CC=c++ all: play diff -Nru mlt-0.6.2/src/framework/Makefile mlt-0.7.2/src/framework/Makefile --- mlt-0.6.2/src/framework/Makefile 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/Makefile 2011-05-02 05:59:12.000000000 +0000 @@ -3,16 +3,20 @@ NAME = libmlt$(LIBSUF) TARGET = $(NAME).$(version) -ifneq ($(targetos), Darwin) -NAME = libmlt$(LIBSUF) -TARGET = $(NAME).$(version) -SONAME = $(NAME).$(soversion) -SHFLAGS += -Wl,-soname,$(SONAME) -else +ifeq ($(targetos), Darwin) NAME = libmlt$(LIBSUF) TARGET = libmlt.$(version)$(LIBSUF) SONAME = libmlt.$(soversion)$(LIBSUF) SHFLAGS += -install_name $(libdir)/$(SONAME) -current_version $(version) -compatibility_version $(soversion) +else ifeq ($(targetos), MinGW) +NAME = libmlt$(LIBSUF) +TARGET = libmlt-$(soversion)$(LIBSUF) +SHFLAGS += -Wl,--output-def,libmlt.def +else +NAME = libmlt$(LIBSUF) +TARGET = $(NAME).$(version) +SONAME = $(NAME).$(soversion) +SHFLAGS += -Wl,-soname,$(SONAME) endif OBJS = mlt_frame.o \ @@ -78,7 +82,9 @@ $(TARGET): $(OBJS) $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) ln -sf $(TARGET) $(NAME) - ln -sf $(TARGET) $(SONAME) + if [ "$(targetos)" != "MinGW" ]; then \ + ln -sf $(TARGET) $(SONAME) ; \ + fi depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend @@ -91,9 +97,15 @@ install: install -d $(DESTDIR)$(libdir) - install -m 755 $(TARGET) $(DESTDIR)$(libdir) - ln -sf $(TARGET) $(DESTDIR)$(libdir)/$(SONAME) - ln -sf $(TARGET) $(DESTDIR)$(libdir)/$(NAME) + if [ "$(targetos)" = "MinGW" ]; then \ + install -m 755 $(TARGET) $(DESTDIR)$(prefix) ; \ + install -m 755 $(TARGET) $(DESTDIR)$(libdir)/libmlt.dll ; \ + install -m 644 libmlt.def $(DESTDIR)$(libdir) ; \ + else \ + install -m 755 $(TARGET) $(DESTDIR)$(libdir) ; \ + ln -sf $(TARGET) $(DESTDIR)$(libdir)/$(SONAME) ; \ + ln -sf $(TARGET) $(DESTDIR)$(libdir)/$(NAME) ; \ + fi install -d "$(DESTDIR)$(prefix)/include/mlt/framework" install -m 644 $(INCS) "$(DESTDIR)$(prefix)/include/mlt/framework" install -d "$(DESTDIR)$(datadir)/mlt" @@ -101,8 +113,10 @@ uninstall: rm -f "$(DESTDIR)$(libdir)/$(TARGET)" - rm -f "$(DESTDIR)$(libdir)/$(SONAME)" - rm -f "$(DESTDIR)$(libdir)/$(NAME)" + if [ "$(targetos)" != "MinGW" ]; then \ + rm -f "$(DESTDIR)$(libdir)/$(SONAME)" ; \ + rm -f "$(DESTDIR)$(libdir)/$(NAME)" ; \ + fi rm -rf "$(DESTDIR)$(prefix)/include/mlt/framework" rm -f "$(DESTDIR)$(datadir)/mlt/metaschema.yaml" diff -Nru mlt-0.6.2/src/framework/mlt_consumer.c mlt-0.7.2/src/framework/mlt_consumer.c --- mlt-0.6.2/src/framework/mlt_consumer.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_consumer.c 2011-05-02 05:59:12.000000000 +0000 @@ -3,8 +3,9 @@ * \brief abstraction for all consumer services * \see mlt_consumer_s * - * Copyright (C) 2003-2009 Ushodaya Enterprises Limited + * Copyright (C) 2003-2010 Ushodaya Enterprises Limited * \author Charles Yates + * \author Dan Dennedy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -42,32 +43,32 @@ */ pthread_mutex_t mlt_sdl_mutex = PTHREAD_MUTEX_INITIALIZER; -static void mlt_consumer_frame_render( mlt_listener listener, mlt_properties owner, mlt_service this, void **args ); -static void mlt_consumer_frame_show( mlt_listener listener, mlt_properties owner, mlt_service this, void **args ); -static void mlt_consumer_property_changed( mlt_properties owner, mlt_consumer this, char *name ); -static void apply_profile_properties( mlt_consumer this, mlt_profile profile, mlt_properties properties ); -static void on_consumer_frame_show( mlt_properties owner, mlt_consumer this, mlt_frame frame ); +static void mlt_consumer_frame_render( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ); +static void mlt_consumer_frame_show( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ); +static void mlt_consumer_property_changed( mlt_properties owner, mlt_consumer self, char *name ); +static void apply_profile_properties( mlt_consumer self, mlt_profile profile, mlt_properties properties ); +static void on_consumer_frame_show( mlt_properties owner, mlt_consumer self, mlt_frame frame ); /** Initialize a consumer service. * * \public \memberof mlt_consumer_s - * \param this the consumer to initialize + * \param self the consumer to initialize * \param child a pointer to the object for the subclass * \param profile the \p mlt_profile_s to use (optional but recommended, - * uses the environment variable MLT if this is NULL) + * uses the environment variable MLT if self is NULL) * \return true if there was an error */ -int mlt_consumer_init( mlt_consumer this, void *child, mlt_profile profile ) +int mlt_consumer_init( mlt_consumer self, void *child, mlt_profile profile ) { int error = 0; - memset( this, 0, sizeof( struct mlt_consumer_s ) ); - this->child = child; - error = mlt_service_init( &this->parent, this ); + memset( self, 0, sizeof( struct mlt_consumer_s ) ); + self->child = child; + error = mlt_service_init( &self->parent, self ); if ( error == 0 ) { // Get the properties from the service - mlt_properties properties = MLT_SERVICE_PROPERTIES( &this->parent ); + mlt_properties properties = MLT_SERVICE_PROPERTIES( &self->parent ); // Apply profile to properties if ( profile == NULL ) @@ -75,10 +76,10 @@ // Normally the application creates the profile and controls its lifetime // This is the fallback exception handling profile = mlt_profile_init( NULL ); - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); + mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); mlt_properties_set_data( properties, "_profile", profile, 0, (mlt_destructor)mlt_profile_close, NULL ); } - apply_profile_properties( this, profile, properties ); + apply_profile_properties( self, profile, properties ); // Default rescaler for all consumers mlt_properties_set( properties, "rescale", "bilinear" ); @@ -97,20 +98,20 @@ mlt_properties_set( properties, "test_card", mlt_environment( "MLT_TEST_CARD" ) ); // Hmm - default all consumers to yuv422 :-/ - this->format = mlt_image_yuv422; + self->format = mlt_image_yuv422; mlt_events_register( properties, "consumer-frame-show", ( mlt_transmitter )mlt_consumer_frame_show ); mlt_events_register( properties, "consumer-frame-render", ( mlt_transmitter )mlt_consumer_frame_render ); mlt_events_register( properties, "consumer-stopped", NULL ); - mlt_events_listen( properties, this, "consumer-frame-show", ( mlt_listener )on_consumer_frame_show ); + mlt_events_listen( properties, self, "consumer-frame-show", ( mlt_listener )on_consumer_frame_show ); // Register a property-changed listener to handle the profile property - // subsequent properties can override the profile - this->event_listener = mlt_events_listen( properties, this, "property-changed", ( mlt_listener )mlt_consumer_property_changed ); + self->event_listener = mlt_events_listen( properties, self, "property-changed", ( mlt_listener )mlt_consumer_property_changed ); // Create the push mutex and condition - pthread_mutex_init( &this->put_mutex, NULL ); - pthread_cond_init( &this->put_cond, NULL ); + pthread_mutex_init( &self->put_mutex, NULL ); + pthread_cond_init( &self->put_cond, NULL ); } return error; @@ -119,14 +120,14 @@ /** Convert the profile into properties on the consumer. * * \private \memberof mlt_consumer_s - * \param this a consumer + * \param self a consumer * \param profile a profile * \param properties a properties list (typically, the consumer's) */ -static void apply_profile_properties( mlt_consumer this, mlt_profile profile, mlt_properties properties ) +static void apply_profile_properties( mlt_consumer self, mlt_profile profile, mlt_properties properties ) { - mlt_event_block( this->event_listener ); + mlt_event_block( self->event_listener ); mlt_properties_set_double( properties, "fps", mlt_profile_fps( profile ) ); mlt_properties_set_int( properties, "frame_rate_num", profile->frame_rate_num ); mlt_properties_set_int( properties, "frame_rate_den", profile->frame_rate_den ); @@ -140,26 +141,26 @@ mlt_properties_set_int( properties, "display_aspect_num", profile->display_aspect_num ); mlt_properties_set_int( properties, "display_aspect_num", profile->display_aspect_num ); mlt_properties_set_int( properties, "colorspace", profile->colorspace ); - mlt_event_unblock( this->event_listener ); + mlt_event_unblock( self->event_listener ); } /** The property-changed event listener * * \private \memberof mlt_consumer_s * \param owner the events object - * \param this the consumer + * \param self the consumer * \param name the name of the property that changed */ -static void mlt_consumer_property_changed( mlt_properties owner, mlt_consumer this, char *name ) +static void mlt_consumer_property_changed( mlt_properties owner, mlt_consumer self, char *name ) { if ( !strcmp( name, "profile" ) ) { // Get the properies - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); + mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); // Get the current profile - mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( this ) ); + mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) ); // Load the new profile mlt_profile new_profile = mlt_profile_init( mlt_properties_get( properties, name ) ); @@ -180,13 +181,13 @@ } // Apply to properties - apply_profile_properties( this, profile, properties ); + apply_profile_properties( self, profile, properties ); } } else if ( !strcmp( name, "frame_rate_num" ) ) { - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); - mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( this ) ); + mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); + mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) ); if ( profile ) { profile->frame_rate_num = mlt_properties_get_int( properties, "frame_rate_num" ); @@ -195,8 +196,8 @@ } else if ( !strcmp( name, "frame_rate_den" ) ) { - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); - mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( this ) ); + mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); + mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) ); if ( profile ) { profile->frame_rate_den = mlt_properties_get_int( properties, "frame_rate_den" ); @@ -205,45 +206,45 @@ } else if ( !strcmp( name, "width" ) ) { - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); - mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( this ) ); + mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); + mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) ); if ( profile ) profile->width = mlt_properties_get_int( properties, "width" ); } else if ( !strcmp( name, "height" ) ) { - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); - mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( this ) ); + mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); + mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) ); if ( profile ) profile->height = mlt_properties_get_int( properties, "height" ); } else if ( !strcmp( name, "progressive" ) ) { - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); - mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( this ) ); + mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); + mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) ); if ( profile ) profile->progressive = mlt_properties_get_int( properties, "progressive" ); } else if ( !strcmp( name, "sample_aspect_num" ) ) { - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); - mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( this ) ); + mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); + mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) ); profile->sample_aspect_num = mlt_properties_get_int( properties, "sample_aspect_num" ); if ( profile ) mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile ) ); } else if ( !strcmp( name, "sample_aspect_den" ) ) { - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); - mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( this ) ); + mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); + mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) ); profile->sample_aspect_den = mlt_properties_get_int( properties, "sample_aspect_den" ); if ( profile ) mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile ) ); } else if ( !strcmp( name, "display_aspect_num" ) ) { - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); - mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( this ) ); + mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); + mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) ); if ( profile ) { profile->display_aspect_num = mlt_properties_get_int( properties, "display_aspect_num" ); @@ -252,8 +253,8 @@ } else if ( !strcmp( name, "display_aspect_den" ) ) { - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); - mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( this ) ); + mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); + mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) ); if ( profile ) { profile->display_aspect_den = mlt_properties_get_int( properties, "display_aspect_den" ); @@ -262,8 +263,8 @@ } else if ( !strcmp( name, "colorspace" ) ) { - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); - mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( this ) ); + mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); + mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) ); if ( profile ) profile->colorspace = mlt_properties_get_int( properties, "colorspace" ); } @@ -276,14 +277,14 @@ * \private \memberof mlt_consumer_s * \param listener a function pointer that will be invoked * \param owner the events object that will be passed to \p listener - * \param this a service that will be passed to \p listener + * \param self a service that will be passed to \p listener * \param args an array of pointers - the first entry is passed as a string to \p listener */ -static void mlt_consumer_frame_show( mlt_listener listener, mlt_properties owner, mlt_service this, void **args ) +static void mlt_consumer_frame_show( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ) { if ( listener != NULL ) - listener( owner, this, ( mlt_frame )args[ 0 ] ); + listener( owner, self, ( mlt_frame )args[ 0 ] ); } /** The transmitter for the consumer-frame-render event @@ -293,14 +294,14 @@ * \private \memberof mlt_consumer_s * \param listener a function pointer that will be invoked * \param owner the events object that will be passed to \p listener - * \param this a service that will be passed to \p listener + * \param self a service that will be passed to \p listener * \param args an array of pointers - the first entry is passed as a string to \p listener */ -static void mlt_consumer_frame_render( mlt_listener listener, mlt_properties owner, mlt_service this, void **args ) +static void mlt_consumer_frame_render( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ) { if ( listener != NULL ) - listener( owner, this, ( mlt_frame )args[ 0 ] ); + listener( owner, self, ( mlt_frame )args[ 0 ] ); } /** A listener on the consumer-frame-show event @@ -329,46 +330,46 @@ mlt_consumer mlt_consumer_new( mlt_profile profile ) { // Create the memory for the structure - mlt_consumer this = malloc( sizeof( struct mlt_consumer_s ) ); + mlt_consumer self = malloc( sizeof( struct mlt_consumer_s ) ); // Initialise it - if ( this != NULL ) - mlt_consumer_init( this, NULL, profile ); + if ( self != NULL ) + mlt_consumer_init( self, NULL, profile ); // Return it - return this; + return self; } /** Get the parent service object. * * \public \memberof mlt_consumer_s - * \param this a consumer + * \param self a consumer * \return the parent service class * \see MLT_CONSUMER_SERVICE */ -mlt_service mlt_consumer_service( mlt_consumer this ) +mlt_service mlt_consumer_service( mlt_consumer self ) { - return this != NULL ? &this->parent : NULL; + return self != NULL ? &self->parent : NULL; } /** Get the consumer properties. * * \public \memberof mlt_consumer_s - * \param this a consumer + * \param self a consumer * \return the consumer's properties list * \see MLT_CONSUMER_PROPERTIES */ -mlt_properties mlt_consumer_properties( mlt_consumer this ) +mlt_properties mlt_consumer_properties( mlt_consumer self ) { - return this != NULL ? MLT_SERVICE_PROPERTIES( &this->parent ) : NULL; + return self != NULL ? MLT_SERVICE_PROPERTIES( &self->parent ) : NULL; } /** Connect the consumer to the producer. * * \public \memberof mlt_consumer_s - * \param this a consumer + * \param self a consumer * \param producer a producer * \return > 0 warning, == 0 success, < 0 serious error, * 1 = this service does not accept input, @@ -376,33 +377,32 @@ * 3 = the producer is already registered with this consumer */ -int mlt_consumer_connect( mlt_consumer this, mlt_service producer ) +int mlt_consumer_connect( mlt_consumer self, mlt_service producer ) { - return mlt_service_connect_producer( &this->parent, producer, 0 ); + return mlt_service_connect_producer( &self->parent, producer, 0 ); } /** Start the consumer. * * \public \memberof mlt_consumer_s - * \param this a consumer + * \param self a consumer * \return true if there was an error */ -int mlt_consumer_start( mlt_consumer this ) +int mlt_consumer_start( mlt_consumer self ) { // Stop listening to the property-changed event - mlt_event_block( this->event_listener ); + mlt_event_block( self->event_listener ); // Get the properies - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); + mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); // Determine if there's a test card producer char *test_card = mlt_properties_get( properties, "test_card" ); // Just to make sure nothing is hanging around... - mlt_frame_close( this->put ); - this->put = NULL; - this->put_active = 1; + self->put = NULL; + self->put_active = 1; // Deal with it now. if ( test_card != NULL ) @@ -410,7 +410,7 @@ if ( mlt_properties_get_data( properties, "test_card_producer", NULL ) == NULL ) { // Create a test card producer - mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( this ) ); + mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( self ) ); mlt_producer producer = mlt_factory_producer( profile, NULL, test_card ); // Do we have a producer @@ -440,14 +440,18 @@ // Check and run an ante command if ( mlt_properties_get( properties, "ante" ) ) if ( system( mlt_properties_get( properties, "ante" ) ) == -1 ) - mlt_log( MLT_CONSUMER_SERVICE( this ), MLT_LOG_ERROR, "system(%s) failed!\n", mlt_properties_get( properties, "ante" ) ); + mlt_log( MLT_CONSUMER_SERVICE( self ), MLT_LOG_ERROR, "system(%s) failed!\n", mlt_properties_get( properties, "ante" ) ); // Set the real_time preference - this->real_time = mlt_properties_get_int( properties, "real_time" ); + self->real_time = mlt_properties_get_int( properties, "real_time" ); + + // For worker threads implementation, buffer must be at least # threads + if ( abs( self->real_time ) > 1 && mlt_properties_get_int( properties, "buffer" ) <= abs( self->real_time ) ) + mlt_properties_set_int( properties, "buffer", abs( self->real_time ) + 1 ); // Start the service - if ( this->start != NULL ) - return this->start( this ); + if ( self->start != NULL ) + return self->start( self ); return 0; } @@ -457,36 +461,36 @@ * Only valid if the consumer itself is not connected. * * \public \memberof mlt_consumer_s - * \param this a consumer + * \param self a consumer * \param frame a frame - * \return true (ignore this for now) + * \return true (ignore self for now) */ -int mlt_consumer_put_frame( mlt_consumer this, mlt_frame frame ) +int mlt_consumer_put_frame( mlt_consumer self, mlt_frame frame ) { int error = 1; // Get the service assoicated to the consumer - mlt_service service = MLT_CONSUMER_SERVICE( this ); + mlt_service service = MLT_CONSUMER_SERVICE( self ); if ( mlt_service_producer( service ) == NULL ) { struct timeval now; struct timespec tm; - pthread_mutex_lock( &this->put_mutex ); - while ( this->put_active && this->put != NULL ) + pthread_mutex_lock( &self->put_mutex ); + while ( self->put_active && self->put != NULL ) { gettimeofday( &now, NULL ); tm.tv_sec = now.tv_sec + 1; tm.tv_nsec = now.tv_usec * 1000; - pthread_cond_timedwait( &this->put_cond, &this->put_mutex, &tm ); + pthread_cond_timedwait( &self->put_cond, &self->put_mutex, &tm ); } - if ( this->put_active && this->put == NULL ) - this->put = frame; + if ( self->put_active && self->put == NULL ) + self->put = frame; else mlt_frame_close( frame ); - pthread_cond_broadcast( &this->put_cond ); - pthread_mutex_unlock( &this->put_mutex ); + pthread_cond_broadcast( &self->put_cond ); + pthread_mutex_unlock( &self->put_mutex ); } else { @@ -499,38 +503,38 @@ /** Protected method for consumer to get frames from connected service * * \public \memberof mlt_consumer_s - * \param this a consumer + * \param self a consumer * \return a frame */ -mlt_frame mlt_consumer_get_frame( mlt_consumer this ) +mlt_frame mlt_consumer_get_frame( mlt_consumer self ) { // Frame to return mlt_frame frame = NULL; // Get the service assoicated to the consumer - mlt_service service = MLT_CONSUMER_SERVICE( this ); + mlt_service service = MLT_CONSUMER_SERVICE( self ); // Get the consumer properties - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); + mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); // Get the frame if ( mlt_service_producer( service ) == NULL && mlt_properties_get_int( properties, "put_mode" ) ) { struct timeval now; struct timespec tm; - pthread_mutex_lock( &this->put_mutex ); - while ( this->put_active && this->put == NULL ) + pthread_mutex_lock( &self->put_mutex ); + while ( self->put_active && self->put == NULL ) { gettimeofday( &now, NULL ); tm.tv_sec = now.tv_sec + 1; tm.tv_nsec = now.tv_usec * 1000; - pthread_cond_timedwait( &this->put_cond, &this->put_mutex, &tm ); + pthread_cond_timedwait( &self->put_cond, &self->put_mutex, &tm ); } - frame = this->put; - this->put = NULL; - pthread_cond_broadcast( &this->put_cond ); - pthread_mutex_unlock( &this->put_mutex ); + frame = self->put; + self->put = NULL; + pthread_cond_broadcast( &self->put_cond ); + pthread_mutex_unlock( &self->put_mutex ); if ( frame != NULL ) mlt_service_apply_filters( service, frame, 0 ); } @@ -594,10 +598,10 @@ static void *consumer_read_ahead_thread( void *arg ) { // The argument is the consumer - mlt_consumer this = arg; + mlt_consumer self = arg; // Get the properties of the consumer - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); + mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); // Get the width and height int width = mlt_properties_get_int( properties, "width" ); @@ -637,76 +641,63 @@ int64_t time_frame = 0; int64_t time_process = 0; int skip_next = 0; - mlt_service lock_object = NULL; if ( preview_off && preview_format != 0 ) - this->format = preview_format; + self->format = preview_format; // Get the first frame - frame = mlt_consumer_get_frame( this ); - - // Get the lock object - lock_object = mlt_properties_get_data( MLT_FRAME_PROPERTIES( frame ), "consumer_lock_service", NULL ); - - // Lock it - if ( lock_object ) mlt_service_lock( lock_object ); - - // Get the image of the first frame - if ( !video_off ) - { - mlt_events_fire( MLT_CONSUMER_PROPERTIES( this ), "consumer-frame-render", frame, NULL ); - mlt_frame_get_image( frame, &image, &this->format, &width, &height, 0 ); - } + frame = mlt_consumer_get_frame( self ); - if ( !audio_off ) + if ( frame ) { - samples = mlt_sample_calculator( fps, frequency, counter++ ); - mlt_frame_get_audio( frame, &audio, &afmt, &frequency, &channels, &samples ); - } + // Get the image of the first frame + if ( !video_off ) + { + mlt_events_fire( MLT_CONSUMER_PROPERTIES( self ), "consumer-frame-render", frame, NULL ); + mlt_frame_get_image( frame, &image, &self->format, &width, &height, 0 ); + } - // Unlock the lock object - if ( lock_object ) mlt_service_unlock( lock_object ); + if ( !audio_off ) + { + samples = mlt_sample_calculator( fps, frequency, counter++ ); + mlt_frame_get_audio( frame, &audio, &afmt, &frequency, &channels, &samples ); + } - // Mark as rendered - mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "rendered", 1 ); + // Mark as rendered + mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "rendered", 1 ); + } // Get the starting time (can ignore the times above) gettimeofday( &ante, NULL ); // Continue to read ahead - while ( this->ahead ) + while ( self->ahead ) { // Fetch width/height again width = mlt_properties_get_int( properties, "width" ); height = mlt_properties_get_int( properties, "height" ); // Put the current frame into the queue - pthread_mutex_lock( &this->mutex ); - while( this->ahead && mlt_deque_count( this->queue ) >= buffer ) - pthread_cond_wait( &this->cond, &this->mutex ); - mlt_deque_push_back( this->queue, frame ); - pthread_cond_broadcast( &this->cond ); - pthread_mutex_unlock( &this->mutex ); + pthread_mutex_lock( &self->queue_mutex ); + while( self->ahead && mlt_deque_count( self->queue ) >= buffer ) + pthread_cond_wait( &self->queue_cond, &self->queue_mutex ); + mlt_deque_push_back( self->queue, frame ); + pthread_cond_broadcast( &self->queue_cond ); + pthread_mutex_unlock( &self->queue_mutex ); time_wait += time_difference( &ante ); // Get the next frame - frame = mlt_consumer_get_frame( this ); + frame = mlt_consumer_get_frame( self ); time_frame += time_difference( &ante ); // If there's no frame, we're probably stopped... if ( frame == NULL ) continue; - // Attempt to fetch the lock object - lock_object = mlt_properties_get_data( MLT_FRAME_PROPERTIES( frame ), "consumer_lock_service", NULL ); - // Increment the count count ++; - // Lock if there's a lock object - if ( lock_object ) mlt_service_lock( lock_object ); - // All non normal playback frames should be shown if ( mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "_speed" ) != 1 ) { @@ -722,13 +713,13 @@ } // Get the image - if ( !skip_next || this->real_time == -1 ) + if ( !skip_next || self->real_time == -1 ) { // Get the image, mark as rendered and time it if ( !video_off ) { - mlt_events_fire( MLT_CONSUMER_PROPERTIES( this ), "consumer-frame-render", frame, NULL ); - mlt_frame_get_image( frame, &image, &this->format, &width, &height, 0 ); + mlt_events_fire( MLT_CONSUMER_PROPERTIES( self ), "consumer-frame-render", frame, NULL ); + mlt_frame_get_image( frame, &image, &self->format, &width, &height, 0 ); } mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "rendered", 1 ); } @@ -739,7 +730,7 @@ skip_next = 0; // If we've reached an unacceptable level, reset everything - if ( skipped > 5 ) + if ( skipped > fps * 2 ) { skipped = 0; time_frame = 0; @@ -756,19 +747,16 @@ mlt_frame_get_audio( frame, &audio, &afmt, &frequency, &channels, &samples ); } - // Increment the time take for this frame + // Increment the time take for self frame time_process += time_difference( &ante ); // Determine if the next frame should be skipped - if ( mlt_deque_count( this->queue ) <= 5 ) + if ( mlt_deque_count( self->queue ) <= 5 ) { int frame_duration = mlt_properties_get_int( properties, "frame_duration" ); if ( ( ( time_wait + time_frame + time_process ) / count ) > frame_duration ) skip_next = 1; } - - // Unlock if there's a lock object - if ( lock_object ) mlt_service_unlock( lock_object ); } // Remove the last frame @@ -777,105 +765,449 @@ return NULL; } +/** Locate the first unprocessed frame in the queue. + * + * When playing with realtime behavior, we do not use the true head, but + * rather an adjusted process_head. The process_head is adjusted based on + * the rate of frame-dropping or recovery from frame-dropping. The idea is + * that as the level of frame-dropping increases to move the process_head + * closer to the tail because the frames are not completing processing prior + * to their playout! Then, as frames are not dropped the process_head moves + * back closer to the head of the queue so that worker threads can work + * ahead of the playout point (queue head). + * + * \private \memberof mlt_consumer_s + * \param self a consumer + * \return an index into the queue + */ + +static inline int first_unprocessed_frame( mlt_consumer self ) +{ + int index = self->real_time <= 0 ? 0 : self->process_head; + while ( index < mlt_deque_count( self->queue ) && MLT_FRAME( mlt_deque_peek( self->queue, index ) )->is_processing ) + index++; + return index; +} + +/** The worker thread procedure for parallel processing frames. + * + * \private \memberof mlt_consumer_s + * \param arg a consumer + */ + +static void *consumer_worker_thread( void *arg ) +{ + // The argument is the consumer + mlt_consumer self = arg; + + // Get the properties of the consumer + mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); + + // Get the width and height + int width = mlt_properties_get_int( properties, "width" ); + int height = mlt_properties_get_int( properties, "height" ); + mlt_image_format format = self->format; + + // See if video is turned off + int video_off = mlt_properties_get_int( properties, "video_off" ); + int preview_off = mlt_properties_get_int( properties, "preview_off" ); + int preview_format = mlt_properties_get_int( properties, "preview_format" ); + + // General frame variable + mlt_frame frame = NULL; + uint8_t *image = NULL; + + if ( preview_off && preview_format != 0 ) + format = preview_format; + + // Continue to read ahead + while ( self->ahead ) + { + // Get the next unprocessed frame from the work queue + pthread_mutex_lock( &self->queue_mutex ); + int index = first_unprocessed_frame( self ); + while ( self->ahead && index >= mlt_deque_count( self->queue ) ) + { + mlt_log_debug( MLT_CONSUMER_SERVICE(self), "waiting in worker index = %d queue count = %d\n", + index, mlt_deque_count( self->queue ) ); + pthread_cond_wait( &self->queue_cond, &self->queue_mutex ); + index = first_unprocessed_frame( self ); + } + + // Mark the frame for processing + frame = mlt_deque_peek( self->queue, index ); + if ( frame ) + { + mlt_log_debug( MLT_CONSUMER_SERVICE(self), "worker processing index = %d frame %d queue count = %d\n", + index, mlt_frame_get_position(frame), mlt_deque_count( self->queue ) ); + frame->is_processing = 1; + mlt_properties_inc_ref( MLT_FRAME_PROPERTIES( frame ) ); + } + pthread_mutex_unlock( &self->queue_mutex ); + + // If there's no frame, we're probably stopped... + if ( frame == NULL ) + continue; + +#ifdef DEINTERLACE_ON_NOT_NORMAL_SPEED + // All non normal playback frames should be shown + if ( mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "_speed" ) != 1 ) + mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "consumer_deinterlace", 1 ); +#endif + + // Get the image + if ( !video_off ) + { + // Fetch width/height again + width = mlt_properties_get_int( properties, "width" ); + height = mlt_properties_get_int( properties, "height" ); + mlt_events_fire( MLT_CONSUMER_PROPERTIES( self ), "consumer-frame-render", frame, NULL ); + mlt_frame_get_image( frame, &image, &format, &width, &height, 0 ); + } + mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "rendered", 1 ); + mlt_frame_close( frame ); + + // Tell a waiting thread (non-realtime main consumer thread) that we are done. + pthread_mutex_lock( &self->done_mutex ); + pthread_cond_broadcast( &self->done_cond ); + pthread_mutex_unlock( &self->done_mutex ); + } + + return NULL; +} + /** Start the read/render thread. * * \private \memberof mlt_consumer_s - * \param this a consumer + * \param self a consumer */ -static void consumer_read_ahead_start( mlt_consumer this ) +static void consumer_read_ahead_start( mlt_consumer self ) { // We're running now - this->ahead = 1; + self->ahead = 1; // Create the frame queue - this->queue = mlt_deque_init( ); + self->queue = mlt_deque_init( ); - // Create the mutex - pthread_mutex_init( &this->mutex, NULL ); + // Create the queue mutex + pthread_mutex_init( &self->queue_mutex, NULL ); // Create the condition - pthread_cond_init( &this->cond, NULL ); + pthread_cond_init( &self->queue_cond, NULL ); // Create the read ahead - if ( mlt_properties_get( MLT_CONSUMER_PROPERTIES( this ), "priority" ) ) + if ( mlt_properties_get( MLT_CONSUMER_PROPERTIES( self ), "priority" ) ) { struct sched_param priority; - priority.sched_priority = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( this ), "priority" ); + priority.sched_priority = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( self ), "priority" ); pthread_attr_t thread_attributes; pthread_attr_init( &thread_attributes ); pthread_attr_setschedpolicy( &thread_attributes, SCHED_OTHER ); pthread_attr_setschedparam( &thread_attributes, &priority ); pthread_attr_setinheritsched( &thread_attributes, PTHREAD_EXPLICIT_SCHED ); pthread_attr_setscope( &thread_attributes, PTHREAD_SCOPE_SYSTEM ); - if ( pthread_create( &this->ahead_thread, &thread_attributes, consumer_read_ahead_thread, this ) < 0 ) - pthread_create( &this->ahead_thread, NULL, consumer_read_ahead_thread, this ); + if ( pthread_create( &self->ahead_thread, &thread_attributes, consumer_read_ahead_thread, self ) < 0 ) + pthread_create( &self->ahead_thread, NULL, consumer_read_ahead_thread, self ); pthread_attr_destroy( &thread_attributes ); } else { - pthread_create( &this->ahead_thread, NULL, consumer_read_ahead_thread, this ); + pthread_create( &self->ahead_thread, NULL, consumer_read_ahead_thread, self ); } + self->started = 1; +} + +/** Start the worker threads. + * + * \private \memberof mlt_consumer_s + * \param self a consumer + */ + +static void consumer_work_start( mlt_consumer self ) +{ + int n = abs( self->real_time ); + pthread_t *thread = calloc( 1, sizeof( pthread_t ) * n ); + + // We're running now + self->ahead = 1; + + // These keep track of the accelleration of frame dropping or recovery. + self->consecutive_dropped = 0; + self->consecutive_rendered = 0; + + // This is the position in the queue from which to look for a frame to process. + // If we always start from the head, then we may likely not complete processing + // before the frame is played out. + self->process_head = 0; + + // Create the queues + self->queue = mlt_deque_init(); + self->worker_threads = mlt_deque_init(); + + // Create the mutexes + pthread_mutex_init( &self->queue_mutex, NULL ); + pthread_mutex_init( &self->done_mutex, NULL ); + + // Create the conditions + pthread_cond_init( &self->queue_cond, NULL ); + pthread_cond_init( &self->done_cond, NULL ); + + // Create the read ahead + if ( mlt_properties_get( MLT_CONSUMER_PROPERTIES( self ), "priority" ) ) + { + + struct sched_param priority; + pthread_attr_t thread_attributes; + + priority.sched_priority = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( self ), "priority" ); + pthread_attr_init( &thread_attributes ); + pthread_attr_setschedpolicy( &thread_attributes, SCHED_OTHER ); + pthread_attr_setschedparam( &thread_attributes, &priority ); + pthread_attr_setinheritsched( &thread_attributes, PTHREAD_EXPLICIT_SCHED ); + pthread_attr_setscope( &thread_attributes, PTHREAD_SCOPE_SYSTEM ); + + while ( n-- ) + { + if ( pthread_create( thread, &thread_attributes, consumer_worker_thread, self ) < 0 ) + if ( pthread_create( thread, NULL, consumer_worker_thread, self ) == 0 ) + mlt_deque_push_back( self->worker_threads, thread ); + thread++; + } + pthread_attr_destroy( &thread_attributes ); + } + + else + { + while ( n-- ) + { + if ( pthread_create( thread, NULL, consumer_worker_thread, self ) == 0 ) + mlt_deque_push_back( self->worker_threads, thread ); + thread++; + } + } + self->started = 1; } /** Stop the read/render thread. * * \private \memberof mlt_consumer_s - * \param this a consumer + * \param self a consumer */ -static void consumer_read_ahead_stop( mlt_consumer this ) +static void consumer_read_ahead_stop( mlt_consumer self ) { // Make sure we're running - if ( this->ahead ) + if ( self->started ) { // Inform thread to stop - this->ahead = 0; + self->ahead = 0; // Broadcast to the condition in case it's waiting - pthread_mutex_lock( &this->mutex ); - pthread_cond_broadcast( &this->cond ); - pthread_mutex_unlock( &this->mutex ); + pthread_mutex_lock( &self->queue_mutex ); + pthread_cond_broadcast( &self->queue_cond ); + pthread_mutex_unlock( &self->queue_mutex ); // Broadcast to the put condition in case it's waiting - pthread_mutex_lock( &this->put_mutex ); - pthread_cond_broadcast( &this->put_cond ); - pthread_mutex_unlock( &this->put_mutex ); + pthread_mutex_lock( &self->put_mutex ); + pthread_cond_broadcast( &self->put_cond ); + pthread_mutex_unlock( &self->put_mutex ); // Join the thread - pthread_join( this->ahead_thread, NULL ); + pthread_join( self->ahead_thread, NULL ); + self->started = 0; - // Destroy the mutex - pthread_mutex_destroy( &this->mutex ); + // Destroy the frame queue mutex + pthread_mutex_destroy( &self->queue_mutex ); // Destroy the condition - pthread_cond_destroy( &this->cond ); + pthread_cond_destroy( &self->queue_cond ); // Wipe the queue - while ( mlt_deque_count( this->queue ) ) - mlt_frame_close( mlt_deque_pop_back( this->queue ) ); + while ( mlt_deque_count( self->queue ) ) + mlt_frame_close( mlt_deque_pop_back( self->queue ) ); // Close the queue - mlt_deque_close( this->queue ); + mlt_deque_close( self->queue ); + } +} + +/** Stop the worker threads. + * + * \private \memberof mlt_consumer_s + * \param self a consumer + */ + +static void consumer_work_stop( mlt_consumer self ) +{ + // Make sure we're running + if ( self->started ) + { + // Inform thread to stop + self->ahead = 0; + + // Broadcast to the queue condition in case it's waiting + pthread_mutex_lock( &self->queue_mutex ); + pthread_cond_broadcast( &self->queue_cond ); + pthread_mutex_unlock( &self->queue_mutex ); + + // Broadcast to the put condition in case it's waiting + pthread_mutex_lock( &self->put_mutex ); + pthread_cond_broadcast( &self->put_cond ); + pthread_mutex_unlock( &self->put_mutex ); + + // Broadcast to the done condition in case it's waiting + pthread_mutex_lock( &self->done_mutex ); + pthread_cond_broadcast( &self->done_cond ); + pthread_mutex_unlock( &self->done_mutex ); + + // Join the threads + pthread_t *thread; + while ( ( thread = mlt_deque_pop_back( self->worker_threads ) ) ) + pthread_join( *thread, NULL ); + + // Deallocate the array of threads + if ( thread ) + free( thread ); + + // Indicate that worker threads no longer running + self->started = 0; + + // Destroy the mutexes + pthread_mutex_destroy( &self->queue_mutex ); + pthread_mutex_destroy( &self->done_mutex ); + + // Destroy the conditions + pthread_cond_destroy( &self->queue_cond ); + pthread_cond_destroy( &self->done_cond ); + + // Wipe the queues + while ( mlt_deque_count( self->queue ) ) + mlt_frame_close( mlt_deque_pop_back( self->queue ) ); + + // Close the queues + mlt_deque_close( self->queue ); + mlt_deque_close( self->worker_threads ); } } /** Flush the read/render thread's buffer. * * \public \memberof mlt_consumer_s - * \param this a consumer + * \param self a consumer + */ + +void mlt_consumer_purge( mlt_consumer self ) +{ + if ( self->ahead ) + { + pthread_mutex_lock( &self->queue_mutex ); + while ( mlt_deque_count( self->queue ) ) + mlt_frame_close( mlt_deque_pop_back( self->queue ) ); + pthread_cond_broadcast( &self->queue_cond ); + pthread_mutex_unlock( &self->queue_mutex ); + } +} + +/** Use multiple worker threads and a work queue. */ -void mlt_consumer_purge( mlt_consumer this ) +static mlt_frame worker_get_frame( mlt_consumer self, mlt_properties properties ) { - if ( this->ahead ) + // Frame to return + mlt_frame frame = NULL; + + int size = abs( self->real_time ); + int buffer = mlt_properties_get_int( properties, "buffer" ); + // This is a heuristic to determine a suitable minimum buffer size for the number of threads. + int headroom = 2 + size * size; + buffer = buffer < headroom ? headroom : buffer; + + // Start worker threads if not already started. + if ( ! self->ahead ) + { + int prefill = mlt_properties_get_int( properties, "prefill" ); + prefill = prefill > 0 && prefill < buffer ? prefill : buffer; + + consumer_work_start( self ); + + // Fill the work queue. + int i = buffer; + while ( self->ahead && i-- ) + { + frame = mlt_consumer_get_frame( self ); + if ( frame ) + { + pthread_mutex_lock( &self->queue_mutex ); + mlt_deque_push_back( self->queue, frame ); + pthread_cond_signal( &self->queue_cond ); + pthread_mutex_unlock( &self->queue_mutex ); + } + } + + // Wait for prefill + while ( self->ahead && first_unprocessed_frame( self ) < prefill ) + { + pthread_mutex_lock( &self->done_mutex ); + pthread_cond_wait( &self->done_cond, &self->done_mutex ); + pthread_mutex_unlock( &self->done_mutex ); + } + self->process_head = size; + } + +// mlt_log_verbose( MLT_CONSUMER_SERVICE(self), "size %d done count %d work count %d process_head %d\n", +// size, first_unprocessed_frame( self ), mlt_deque_count( self->queue ), self->process_head ); + + // Feed the work queue + while ( self->ahead && mlt_deque_count( self->queue ) < buffer ) + { + frame = mlt_consumer_get_frame( self ); + if ( ! frame ) + return frame; + pthread_mutex_lock( &self->queue_mutex ); + mlt_deque_push_back( self->queue, frame ); + pthread_cond_signal( &self->queue_cond ); + pthread_mutex_unlock( &self->queue_mutex ); + } + + // Wait if not realtime. + while( self->ahead && self->real_time < 0 && + ! mlt_properties_get_int( MLT_FRAME_PROPERTIES( MLT_FRAME( mlt_deque_peek_front( self->queue ) ) ), "rendered" ) ) { - pthread_mutex_lock( &this->mutex ); - while ( mlt_deque_count( this->queue ) ) - mlt_frame_close( mlt_deque_pop_back( this->queue ) ); - pthread_cond_broadcast( &this->cond ); - pthread_mutex_unlock( &this->mutex ); + pthread_mutex_lock( &self->done_mutex ); + pthread_cond_wait( &self->done_cond, &self->done_mutex ); + pthread_mutex_unlock( &self->done_mutex ); + } + + // Get the frame from the queue. + pthread_mutex_lock( &self->queue_mutex ); + frame = mlt_deque_pop_front( self->queue ); + pthread_mutex_unlock( &self->queue_mutex ); + + // Adapt the worker process head to the runtime conditions. + if ( self->real_time > 0 ) + { + if ( frame && mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "rendered" ) ) + { + self->consecutive_dropped = 0; + if ( self->process_head > size && self->consecutive_rendered >= self->process_head ) + self->process_head--; + else + self->consecutive_rendered++; + } + else + { + self->consecutive_rendered = 0; + if ( self->process_head < buffer - size && self->consecutive_dropped > size ) + self->process_head++; + else + self->consecutive_dropped++; + } +// mlt_log_verbose( MLT_CONSUMER_SERVICE(self), "dropped %d rendered %d process_head %d\n", +// self->consecutive_dropped, self->consecutive_rendered, self->process_head ); } + + return frame; } /** Get the next frame from the producer connected to a consumer. @@ -885,45 +1217,50 @@ * You should close the frame returned from this when you are done with it. * * \public \memberof mlt_consumer_s - * \param this a consumer + * \param self a consumer * \return a frame */ -mlt_frame mlt_consumer_rt_frame( mlt_consumer this ) +mlt_frame mlt_consumer_rt_frame( mlt_consumer self ) { // Frame to return mlt_frame frame = NULL; // Get the properties - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); + mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); // Check if the user has requested real time or not - if ( this->real_time ) + if ( self->real_time > 1 || self->real_time < -1 ) + { + // see above + return worker_get_frame( self, properties ); + } + else if ( self->real_time == 1 || self->real_time == -1 ) { int size = 1; // Is the read ahead running? - if ( this->ahead == 0 ) + if ( self->ahead == 0 ) { int buffer = mlt_properties_get_int( properties, "buffer" ); int prefill = mlt_properties_get_int( properties, "prefill" ); - consumer_read_ahead_start( this ); + consumer_read_ahead_start( self ); if ( buffer > 1 ) size = prefill > 0 && prefill < buffer ? prefill : buffer; } // Get frame from queue - pthread_mutex_lock( &this->mutex ); - while( this->ahead && mlt_deque_count( this->queue ) < size ) - pthread_cond_wait( &this->cond, &this->mutex ); - frame = mlt_deque_pop_front( this->queue ); - pthread_cond_broadcast( &this->cond ); - pthread_mutex_unlock( &this->mutex ); + pthread_mutex_lock( &self->queue_mutex ); + while( self->ahead && mlt_deque_count( self->queue ) < size ) + pthread_cond_wait( &self->queue_cond, &self->queue_mutex ); + frame = mlt_deque_pop_front( self->queue ); + pthread_cond_broadcast( &self->queue_cond ); + pthread_mutex_unlock( &self->queue_mutex ); } - else + else // real_time == 0 { // Get the frame in non real time - frame = mlt_consumer_get_frame( this ); + frame = mlt_consumer_get_frame( self ); // This isn't true, but from the consumers perspective it is if ( frame != NULL ) @@ -936,44 +1273,58 @@ /** Callback for the implementation to indicate a stopped condition. * * \public \memberof mlt_consumer_s - * \param this a consumer + * \param self a consumer */ -void mlt_consumer_stopped( mlt_consumer this ) +void mlt_consumer_stopped( mlt_consumer self ) { - mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( this ), "running", 0 ); - mlt_events_fire( MLT_CONSUMER_PROPERTIES( this ), "consumer-stopped", NULL ); - mlt_event_unblock( this->event_listener ); + mlt_properties_set_int( MLT_CONSUMER_PROPERTIES( self ), "running", 0 ); + mlt_events_fire( MLT_CONSUMER_PROPERTIES( self ), "consumer-stopped", NULL ); + mlt_event_unblock( self->event_listener ); } /** Stop the consumer. * * \public \memberof mlt_consumer_s - * \param this a consumer + * \param self a consumer * \return true if there was an error */ -int mlt_consumer_stop( mlt_consumer this ) +int mlt_consumer_stop( mlt_consumer self ) { // Get the properies - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); + mlt_properties properties = MLT_CONSUMER_PROPERTIES( self ); // Just in case... - mlt_log( MLT_CONSUMER_SERVICE( this ), MLT_LOG_DEBUG, "stopping put waiting\n" ); - pthread_mutex_lock( &this->put_mutex ); - this->put_active = 0; - pthread_cond_broadcast( &this->put_cond ); - pthread_mutex_unlock( &this->put_mutex ); + mlt_log( MLT_CONSUMER_SERVICE( self ), MLT_LOG_DEBUG, "stopping put waiting\n" ); + pthread_mutex_lock( &self->put_mutex ); + self->put_active = 0; + pthread_cond_broadcast( &self->put_cond ); + pthread_mutex_unlock( &self->put_mutex ); // Stop the consumer - mlt_log( MLT_CONSUMER_SERVICE( this ), MLT_LOG_DEBUG, "stopping consumer\n" ); - if ( this->stop != NULL ) - this->stop( this ); + mlt_log( MLT_CONSUMER_SERVICE( self ), MLT_LOG_DEBUG, "stopping consumer\n" ); + + // Cancel the read ahead threads + self->ahead = 0; + if ( self->started ) + { + // Unblock the consumer calling mlt_consumer_rt_frame + pthread_mutex_lock( &self->queue_mutex ); + pthread_cond_broadcast( &self->queue_cond ); + pthread_mutex_unlock( &self->queue_mutex ); + } + + // Invoke the child callback + if ( self->stop != NULL ) + self->stop( self ); // Check if the user has requested real time or not and stop if necessary - mlt_log( MLT_CONSUMER_SERVICE( this ), MLT_LOG_DEBUG, "stopping read_ahead\n" ); - if ( mlt_properties_get_int( properties, "real_time" ) ) - consumer_read_ahead_stop( this ); + mlt_log( MLT_CONSUMER_SERVICE( self ), MLT_LOG_DEBUG, "stopping read_ahead\n" ); + if ( abs( self->real_time ) == 1 ) + consumer_read_ahead_stop( self ); + else if ( abs( self->real_time ) > 1 ) + consumer_work_stop( self ); // Kill the test card mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL ); @@ -981,9 +1332,9 @@ // Check and run a post command if ( mlt_properties_get( properties, "post" ) ) if (system( mlt_properties_get( properties, "post" ) ) == -1 ) - mlt_log( MLT_CONSUMER_SERVICE( this ), MLT_LOG_ERROR, "system(%s) failed!\n", mlt_properties_get( properties, "post" ) ); + mlt_log( MLT_CONSUMER_SERVICE( self ), MLT_LOG_ERROR, "system(%s) failed!\n", mlt_properties_get( properties, "post" ) ); - mlt_log( MLT_CONSUMER_SERVICE( this ), MLT_LOG_DEBUG, "stopped\n" ); + mlt_log( MLT_CONSUMER_SERVICE( self ), MLT_LOG_DEBUG, "stopped\n" ); return 0; } @@ -991,15 +1342,15 @@ /** Determine if the consumer is stopped. * * \public \memberof mlt_consumer_s - * \param this a consumer + * \param self a consumer * \return true if the consumer is stopped */ -int mlt_consumer_is_stopped( mlt_consumer this ) +int mlt_consumer_is_stopped( mlt_consumer self ) { // Check if the consumer is stopped - if ( this->is_stopped != NULL ) - return this->is_stopped( this ); + if ( self->is_stopped != NULL ) + return self->is_stopped( self ); return 0; } @@ -1007,34 +1358,34 @@ /** Close and destroy the consumer. * * \public \memberof mlt_consumer_s - * \param this a consumer + * \param self a consumer */ -void mlt_consumer_close( mlt_consumer this ) +void mlt_consumer_close( mlt_consumer self ) { - if ( this != NULL && mlt_properties_dec_ref( MLT_CONSUMER_PROPERTIES( this ) ) <= 0 ) + if ( self != NULL && mlt_properties_dec_ref( MLT_CONSUMER_PROPERTIES( self ) ) <= 0 ) { // Get the childs close function - void ( *consumer_close )( ) = this->close; + void ( *consumer_close )( ) = self->close; if ( consumer_close ) { // Just in case... - //mlt_consumer_stop( this ); + //mlt_consumer_stop( self ); - this->close = NULL; - consumer_close( this ); + self->close = NULL; + consumer_close( self ); } else { // Make sure it only gets called once - this->parent.close = NULL; + self->parent.close = NULL; // Destroy the push mutex and condition - pthread_mutex_destroy( &this->put_mutex ); - pthread_cond_destroy( &this->put_cond ); + pthread_mutex_destroy( &self->put_mutex ); + pthread_cond_destroy( &self->put_cond ); - mlt_service_close( &this->parent ); + mlt_service_close( &self->parent ); } } } diff -Nru mlt-0.6.2/src/framework/mlt_consumer.h mlt-0.7.2/src/framework/mlt_consumer.h --- mlt-0.6.2/src/framework/mlt_consumer.h 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_consumer.h 2011-05-02 05:59:12.000000000 +0000 @@ -3,8 +3,9 @@ * \brief abstraction for all consumer services * \see mlt_consumer_s * - * Copyright (C) 2003-2009 Ushodaya Enterprises Limited + * Copyright (C) 2003-2010 Ushodaya Enterprises Limited * \author Charles Yates + * \author Dan Dennedy * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -105,14 +106,23 @@ mlt_image_format format; mlt_deque queue; pthread_t ahead_thread; - pthread_mutex_t mutex; - pthread_cond_t cond; + pthread_mutex_t queue_mutex; + pthread_cond_t queue_cond; pthread_mutex_t put_mutex; pthread_cond_t put_cond; mlt_frame put; int put_active; mlt_event event_listener; mlt_position position; + + /* additional fields added for the parallel work queue */ + mlt_deque worker_threads; + pthread_mutex_t done_mutex; + pthread_cond_t done_cond; + int consecutive_dropped; + int consecutive_rendered; + int process_head; + int started; }; #define MLT_CONSUMER_SERVICE( consumer ) ( &( consumer )->parent ) diff -Nru mlt-0.6.2/src/framework/mlt_deque.c mlt-0.7.2/src/framework/mlt_deque.c --- mlt-0.6.2/src/framework/mlt_deque.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_deque.c 2011-05-02 05:59:12.000000000 +0000 @@ -61,59 +61,59 @@ mlt_deque mlt_deque_init( ) { - mlt_deque this = malloc( sizeof( struct mlt_deque_s ) ); - if ( this != NULL ) + mlt_deque self = malloc( sizeof( struct mlt_deque_s ) ); + if ( self != NULL ) { - this->list = NULL; - this->size = 0; - this->count = 0; + self->list = NULL; + self->size = 0; + self->count = 0; } - return this; + return self; } /** Return the number of items in the deque. * * \public \memberof mlt_deque_s - * \param this a deque + * \param self a deque * \return the number of items */ -int mlt_deque_count( mlt_deque this ) +int mlt_deque_count( mlt_deque self ) { - return this->count; + return self->count; } /** Allocate space on the deque. * * \private \memberof mlt_deque_s - * \param this a deque + * \param self a deque * \return true if there was an error */ -static int mlt_deque_allocate( mlt_deque this ) +static int mlt_deque_allocate( mlt_deque self ) { - if ( this->count == this->size ) + if ( self->count == self->size ) { - this->list = realloc( this->list, sizeof( deque_entry ) * ( this->size + 20 ) ); - this->size += 20; + self->list = realloc( self->list, sizeof( deque_entry ) * ( self->size + 20 ) ); + self->size += 20; } - return this->list == NULL; + return self->list == NULL; } /** Push an item to the end. * * \public \memberof mlt_deque_s - * \param this a deque + * \param self a deque * \param item an opaque pointer * \return true if there was an error */ -int mlt_deque_push_back( mlt_deque this, void *item ) +int mlt_deque_push_back( mlt_deque self, void *item ) { - int error = mlt_deque_allocate( this ); + int error = mlt_deque_allocate( self ); if ( error == 0 ) - this->list[ this->count ++ ].addr = item; + self->list[ self->count ++ ].addr = item; return error; } @@ -121,31 +121,31 @@ /** Pop an item. * * \public \memberof mlt_deque_s - * \param this a pointer + * \param self a pointer * \return an opaque pointer */ -void *mlt_deque_pop_back( mlt_deque this ) +void *mlt_deque_pop_back( mlt_deque self ) { - return this->count > 0 ? this->list[ -- this->count ].addr : NULL; + return self->count > 0 ? self->list[ -- self->count ].addr : NULL; } /** Queue an item at the start. * * \public \memberof mlt_deque_s - * \param this a deque + * \param self a deque * \param item an opaque pointer * \return true if there was an error */ -int mlt_deque_push_front( mlt_deque this, void *item ) +int mlt_deque_push_front( mlt_deque self, void *item ) { - int error = mlt_deque_allocate( this ); + int error = mlt_deque_allocate( self ); if ( error == 0 ) { - memmove( &this->list[ 1 ], this->list, ( this->count ++ ) * sizeof( deque_entry ) ); - this->list[ 0 ].addr = item; + memmove( &self->list[ 1 ], self->list, ( self->count ++ ) * sizeof( deque_entry ) ); + self->list[ 0 ].addr = item; } return error; @@ -154,18 +154,18 @@ /** Remove an item from the start. * * \public \memberof mlt_deque_s - * \param this a pointer + * \param self a pointer * \return an opaque pointer */ -void *mlt_deque_pop_front( mlt_deque this ) +void *mlt_deque_pop_front( mlt_deque self ) { void *item = NULL; - if ( this->count > 0 ) + if ( self->count > 0 ) { - item = this->list[ 0 ].addr; - memmove( this->list, &this->list[ 1 ], ( -- this->count ) * sizeof( deque_entry ) ); + item = self->list[ 0 ].addr; + memmove( self->list, &self->list[ 1 ], ( -- self->count ) * sizeof( deque_entry ) ); } return item; @@ -174,41 +174,82 @@ /** Inquire on item at back of deque but don't remove. * * \public \memberof mlt_deque_s - * \param this a deque + * \param self a deque * \return an opaque pointer */ -void *mlt_deque_peek_back( mlt_deque this ) +void *mlt_deque_peek_back( mlt_deque self ) { - return this->count > 0 ? this->list[ this->count - 1 ].addr : NULL; + return self->count > 0 ? self->list[ self->count - 1 ].addr : NULL; } /** Inquire on item at front of deque but don't remove. * * \public \memberof mlt_deque_s - * \param this a deque + * \param self a deque * \return an opaque pointer */ -void *mlt_deque_peek_front( mlt_deque this ) +void *mlt_deque_peek_front( mlt_deque self ) { - return this->count > 0 ? this->list[ 0 ].addr : NULL; + return self->count > 0 ? self->list[ 0 ].addr : NULL; +} + +/** Inquire on item in deque but don't remove. + * + * \public \memberof mlt_deque_s + * \param self a deque + * \param index the position in the deque + * \return an opaque pointer + */ + +void *mlt_deque_peek( mlt_deque self, int index ) +{ + return self->count > index ? self->list[ index ].addr : NULL; +} + +/** Insert an item in a sorted fashion. + * + * Optimized for the equivalent of \p mlt_deque_push_back. + * + * \public \memberof mlt_deque_s + * \param self a deque + * \param item an opaque pointer + * \param cmp a function pointer to the comparison function + * \return true if there was an error + */ + +int mlt_deque_insert( mlt_deque self, void *item, mlt_deque_compare cmp ) +{ + int error = mlt_deque_allocate( self ); + + if ( error == 0 ) + { + int n = self->count + 1; + while ( --n ) + if ( cmp( item, self->list[ n - 1 ].addr ) >= 0 ) + break; + memmove( &self->list[ n + 1 ], &self->list[ n ], ( self->count - n ) * sizeof( deque_entry ) ); + self->list[ n ].addr = item; + self->count++; + } + return error; } /** Push an integer to the end. * * \public \memberof mlt_deque_s - * \param this a deque + * \param self a deque * \param item an integer * \return true if there was an error */ -int mlt_deque_push_back_int( mlt_deque this, int item ) +int mlt_deque_push_back_int( mlt_deque self, int item ) { - int error = mlt_deque_allocate( this ); + int error = mlt_deque_allocate( self ); if ( error == 0 ) - this->list[ this->count ++ ].value = item; + self->list[ self->count ++ ].value = item; return error; } @@ -216,31 +257,31 @@ /** Pop an integer. * * \public \memberof mlt_deque_s - * \param this a deque + * \param self a deque * \return an integer */ -int mlt_deque_pop_back_int( mlt_deque this ) +int mlt_deque_pop_back_int( mlt_deque self ) { - return this->count > 0 ? this->list[ -- this->count ].value : 0; + return self->count > 0 ? self->list[ -- self->count ].value : 0; } /** Queue an integer at the start. * * \public \memberof mlt_deque_s - * \param this a deque + * \param self a deque * \param item an integer * \return true if there was an error */ -int mlt_deque_push_front_int( mlt_deque this, int item ) +int mlt_deque_push_front_int( mlt_deque self, int item ) { - int error = mlt_deque_allocate( this ); + int error = mlt_deque_allocate( self ); if ( error == 0 ) { - memmove( &this->list[ 1 ], this->list, ( this->count ++ ) * sizeof( deque_entry ) ); - this->list[ 0 ].value = item; + memmove( &self->list[ 1 ], self->list, ( self->count ++ ) * sizeof( deque_entry ) ); + self->list[ 0 ].value = item; } return error; @@ -249,18 +290,18 @@ /** Remove an integer from the start. * * \public \memberof mlt_deque_s - * \param this a deque + * \param self a deque * \return an integer */ -int mlt_deque_pop_front_int( mlt_deque this ) +int mlt_deque_pop_front_int( mlt_deque self ) { int item = 0; - if ( this->count > 0 ) + if ( self->count > 0 ) { - item = this->list[ 0 ].value; - memmove( this->list, &this->list[ 1 ], ( -- this->count ) * sizeof( deque_entry ) ); + item = self->list[ 0 ].value; + memmove( self->list, &self->list[ 1 ], ( -- self->count ) * sizeof( deque_entry ) ); } return item; @@ -269,41 +310,41 @@ /** Inquire on an integer at back of deque but don't remove. * * \public \memberof mlt_deque_s - * \param this a deque + * \param self a deque * \return an integer */ -int mlt_deque_peek_back_int( mlt_deque this ) +int mlt_deque_peek_back_int( mlt_deque self ) { - return this->count > 0 ? this->list[ this->count - 1 ].value : 0; + return self->count > 0 ? self->list[ self->count - 1 ].value : 0; } /** Inquire on an integer at front of deque but don't remove. * * \public \memberof mlt_deque_s - * \param this a deque + * \param self a deque * \return an integer */ -int mlt_deque_peek_front_int( mlt_deque this ) +int mlt_deque_peek_front_int( mlt_deque self ) { - return this->count > 0 ? this->list[ 0 ].value : 0; + return self->count > 0 ? self->list[ 0 ].value : 0; } /** Push a double float to the end. * * \public \memberof mlt_deque_s - * \param this a deque + * \param self a deque * \param item a double float * \return true if there was an error */ -int mlt_deque_push_back_double( mlt_deque this, double item ) +int mlt_deque_push_back_double( mlt_deque self, double item ) { - int error = mlt_deque_allocate( this ); + int error = mlt_deque_allocate( self ); if ( error == 0 ) - this->list[ this->count ++ ].floating = item; + self->list[ self->count ++ ].floating = item; return error; } @@ -311,31 +352,31 @@ /** Pop a double float. * * \public \memberof mlt_deque_s - * \param this a deque + * \param self a deque * \return a double float */ -double mlt_deque_pop_back_double( mlt_deque this ) +double mlt_deque_pop_back_double( mlt_deque self ) { - return this->count > 0 ? this->list[ -- this->count ].floating : 0; + return self->count > 0 ? self->list[ -- self->count ].floating : 0; } /** Queue a double float at the start. * * \public \memberof mlt_deque_s - * \param this a deque + * \param self a deque * \param item a double float * \return true if there was an error */ -int mlt_deque_push_front_double( mlt_deque this, double item ) +int mlt_deque_push_front_double( mlt_deque self, double item ) { - int error = mlt_deque_allocate( this ); + int error = mlt_deque_allocate( self ); if ( error == 0 ) { - memmove( &this->list[ 1 ], this->list, ( this->count ++ ) * sizeof( deque_entry ) ); - this->list[ 0 ].floating = item; + memmove( &self->list[ 1 ], self->list, ( self->count ++ ) * sizeof( deque_entry ) ); + self->list[ 0 ].floating = item; } return error; @@ -344,18 +385,18 @@ /** Remove a double float from the start. * * \public \memberof mlt_deque_s - * \param this a deque + * \param self a deque * \return a double float */ -double mlt_deque_pop_front_double( mlt_deque this ) +double mlt_deque_pop_front_double( mlt_deque self ) { double item = 0; - if ( this->count > 0 ) + if ( self->count > 0 ) { - item = this->list[ 0 ].floating; - memmove( this->list, &this->list[ 1 ], ( -- this->count ) * sizeof( deque_entry ) ); + item = self->list[ 0 ].floating; + memmove( self->list, &self->list[ 1 ], ( -- self->count ) * sizeof( deque_entry ) ); } return item; @@ -364,35 +405,35 @@ /** Inquire on a double float at back of deque but don't remove. * * \public \memberof mlt_deque_s - * \param this a deque + * \param self a deque * \return a double float */ -double mlt_deque_peek_back_double( mlt_deque this ) +double mlt_deque_peek_back_double( mlt_deque self ) { - return this->count > 0 ? this->list[ this->count - 1 ].floating : 0; + return self->count > 0 ? self->list[ self->count - 1 ].floating : 0; } /** Inquire on a double float at front of deque but don't remove. * * \public \memberof mlt_deque_s - * \param this a deque + * \param self a deque * \return a double float */ -double mlt_deque_peek_front_double( mlt_deque this ) +double mlt_deque_peek_front_double( mlt_deque self ) { - return this->count > 0 ? this->list[ 0 ].floating : 0; + return self->count > 0 ? self->list[ 0 ].floating : 0; } /** Destroy the queue. * * \public \memberof mlt_deque_s - * \param this a deque + * \param self a deque */ -void mlt_deque_close( mlt_deque this ) +void mlt_deque_close( mlt_deque self ) { - free( this->list ); - free( this ); + free( self->list ); + free( self ); } diff -Nru mlt-0.6.2/src/framework/mlt_deque.h mlt-0.7.2/src/framework/mlt_deque.h --- mlt-0.6.2/src/framework/mlt_deque.h 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_deque.h 2011-05-02 05:59:12.000000000 +0000 @@ -26,6 +26,15 @@ #include "mlt_types.h" +/** The callback function used to compare items for insert sort. + * + * \public \memberof mlt_deque_s + * \param a the first object + * \param b the second object + * \returns 0 if equal, < 0 if a < b, or > 0 if a > b +*/ +typedef int ( *mlt_deque_compare )( void *a, void *b ); + extern mlt_deque mlt_deque_init( ); extern int mlt_deque_count( mlt_deque self ); extern int mlt_deque_push_back( mlt_deque self, void *item ); @@ -34,6 +43,8 @@ extern void *mlt_deque_pop_front( mlt_deque self ); extern void *mlt_deque_peek_back( mlt_deque self ); extern void *mlt_deque_peek_front( mlt_deque self ); +extern void *mlt_deque_peek( mlt_deque self, int index ); +extern int mlt_deque_insert( mlt_deque self, void *item, mlt_deque_compare ); extern int mlt_deque_push_back_int( mlt_deque self, int item ); extern int mlt_deque_pop_back_int( mlt_deque self ); diff -Nru mlt-0.6.2/src/framework/mlt_events.c mlt-0.7.2/src/framework/mlt_events.c --- mlt-0.6.2/src/framework/mlt_events.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_events.c 2011-05-02 05:59:12.000000000 +0000 @@ -67,60 +67,60 @@ void *service; }; -/** Increment the reference count on this event. +/** Increment the reference count on self event. * * \public \memberof mlt_event_struct - * \param this an event + * \param self an event */ -void mlt_event_inc_ref( mlt_event this ) +void mlt_event_inc_ref( mlt_event self ) { - if ( this != NULL ) - this->ref_count ++; + if ( self != NULL ) + self->ref_count ++; } -/** Increment the block count on this event. +/** Increment the block count on self event. * * \public \memberof mlt_event_struct - * \param this an event + * \param self an event */ -void mlt_event_block( mlt_event this ) +void mlt_event_block( mlt_event self ) { - if ( this != NULL && this->owner != NULL ) - this->block_count ++; + if ( self != NULL && self->owner != NULL ) + self->block_count ++; } -/** Decrement the block count on this event. +/** Decrement the block count on self event. * * \public \memberof mlt_event_struct - * \param this an event + * \param self an event */ -void mlt_event_unblock( mlt_event this ) +void mlt_event_unblock( mlt_event self ) { - if ( this != NULL && this->owner != NULL ) - this->block_count --; + if ( self != NULL && self->owner != NULL ) + self->block_count --; } -/** Close this event. +/** Close self event. * * \public \memberof mlt_event_struct - * \param this an event + * \param self an event */ -void mlt_event_close( mlt_event this ) +void mlt_event_close( mlt_event self ) { - if ( this != NULL ) + if ( self != NULL ) { - if ( -- this->ref_count == 1 ) - this->owner = NULL; - if ( this->ref_count <= 0 ) + if ( -- self->ref_count == 1 ) + self->owner = NULL; + if ( self->ref_count <= 0 ) { #ifdef _MLT_EVENT_CHECKS_ mlt_log( NULL, MLT_LOG_DEBUG, "Events created %d, destroyed %d\n", events_created, ++events_destroyed ); #endif - free( this ); + free( self ); } } } @@ -135,33 +135,33 @@ /** Initialise the events structure. * * \public \memberof mlt_events_struct - * \param this a properties list + * \param self a properties list */ -void mlt_events_init( mlt_properties this ) +void mlt_events_init( mlt_properties self ) { - mlt_events events = mlt_events_fetch( this ); + mlt_events events = mlt_events_fetch( self ); if ( events == NULL ) { events = malloc( sizeof( struct mlt_events_struct ) ); events->list = mlt_properties_new( ); - mlt_events_store( this, events ); + mlt_events_store( self, events ); } } /** Register an event and transmitter. * * \public \memberof mlt_events_struct - * \param this a properties list + * \param self a properties list * \param id the name of an event * \param transmitter the callback function to send an event message * \return true if there was an error */ -int mlt_events_register( mlt_properties this, const char *id, mlt_transmitter transmitter ) +int mlt_events_register( mlt_properties self, const char *id, mlt_transmitter transmitter ) { int error = 1; - mlt_events events = mlt_events_fetch( this ); + mlt_events events = mlt_events_fetch( self ); if ( events != NULL ) { mlt_properties list = events->list; @@ -179,13 +179,13 @@ * This takes a variable number of arguments to supply to the listener. * \public \memberof mlt_events_struct - * \param this a properties list + * \param self a properties list * \param id the name of an event */ -void mlt_events_fire( mlt_properties this, const char *id, ... ) +void mlt_events_fire( mlt_properties self, const char *id, ... ) { - mlt_events events = mlt_events_fetch( this ); + mlt_events events = mlt_events_fetch( self ); if ( events != NULL ) { int i = 0; @@ -224,17 +224,17 @@ /** Register a listener. * * \public \memberof mlt_events_struct - * \param this a properties list + * \param self a properties list * \param service an opaque pointer * \param id the name of the event to listen for * \param listener the callback to receive an event message * \return */ -mlt_event mlt_events_listen( mlt_properties this, void *service, const char *id, mlt_listener listener ) +mlt_event mlt_events_listen( mlt_properties self, void *service, const char *id, mlt_listener listener ) { mlt_event event = NULL; - mlt_events events = mlt_events_fetch( this ); + mlt_events events = mlt_events_fetch( self ); if ( events != NULL ) { mlt_properties list = events->list; @@ -287,13 +287,13 @@ /** Block all events for a given service. * * \public \memberof mlt_events_struct - * \param this a properties list + * \param self a properties list * \param service an opaque pointer */ -void mlt_events_block( mlt_properties this, void *service ) +void mlt_events_block( mlt_properties self, void *service ) { - mlt_events events = mlt_events_fetch( this ); + mlt_events events = mlt_events_fetch( self ); if ( events != NULL ) { int i = 0, j = 0; @@ -318,13 +318,13 @@ /** Unblock all events for a given service. * * \public \memberof mlt_events_struct - * \param this a properties list + * \param self a properties list * \param service an opaque pointer */ -void mlt_events_unblock( mlt_properties this, void *service ) +void mlt_events_unblock( mlt_properties self, void *service ) { - mlt_events events = mlt_events_fetch( this ); + mlt_events events = mlt_events_fetch( self ); if ( events != NULL ) { int i = 0, j = 0; @@ -349,13 +349,13 @@ /** Disconnect all events for a given service. * * \public \memberof mlt_events_struct - * \param this a properties list + * \param self a properties list * \param service an opaque pointer */ -void mlt_events_disconnect( mlt_properties this, void *service ) +void mlt_events_disconnect( mlt_properties self, void *service ) { - mlt_events events = mlt_events_fetch( this ); + mlt_events events = mlt_events_fetch( self ); if ( events != NULL ) { int i = 0, j = 0; @@ -391,11 +391,11 @@ /** The event listener callback for the wait functions. * * \private \memberof mlt_events_struct - * \param this a properties list + * \param self a properties list * \param pair a condition pair */ -static void mlt_events_listen_for( mlt_properties this, condition_pair *pair ) +static void mlt_events_listen_for( mlt_properties self, condition_pair *pair ) { pthread_mutex_lock( &pair->mutex ); if ( pair->done == 0 ) @@ -408,29 +408,29 @@ /** Prepare to wait for an event. * * \public \memberof mlt_events_struct - * \param this a properties list + * \param self a properties list * \param id the name of the event to wait for * \return an event */ -mlt_event mlt_events_setup_wait_for( mlt_properties this, const char *id ) +mlt_event mlt_events_setup_wait_for( mlt_properties self, const char *id ) { condition_pair *pair = malloc( sizeof( condition_pair ) ); pair->done = 0; pthread_cond_init( &pair->cond, NULL ); pthread_mutex_init( &pair->mutex, NULL ); pthread_mutex_lock( &pair->mutex ); - return mlt_events_listen( this, pair, id, ( mlt_listener )mlt_events_listen_for ); + return mlt_events_listen( self, pair, id, ( mlt_listener )mlt_events_listen_for ); } /** Wait for an event. * * \public \memberof mlt_events_struct - * \param this a properties list + * \param self a properties list * \param event an event */ -void mlt_events_wait_for( mlt_properties this, mlt_event event ) +void mlt_events_wait_for( mlt_properties self, mlt_event event ) { if ( event != NULL ) { @@ -442,11 +442,11 @@ /** Cleanup after waiting for an event. * * \public \memberof mlt_events_struct - * \param this a properties list + * \param self a properties list * \param event an event */ -void mlt_events_close_wait_for( mlt_properties this, mlt_event event ) +void mlt_events_close_wait_for( mlt_properties self, mlt_event event ) { if ( event != NULL ) { @@ -462,29 +462,29 @@ /** Fetch the events object. * * \private \memberof mlt_events_struct - * \param this a properties list + * \param self a properties list * \return an events object */ -static mlt_events mlt_events_fetch( mlt_properties this ) +static mlt_events mlt_events_fetch( mlt_properties self ) { mlt_events events = NULL; - if ( this != NULL ) - events = mlt_properties_get_data( this, "_events", NULL ); + if ( self != NULL ) + events = mlt_properties_get_data( self, "_events", NULL ); return events; } /** Store the events object. * * \private \memberof mlt_events_struct - * \param this a properties list + * \param self a properties list * \param events an events object */ -static void mlt_events_store( mlt_properties this, mlt_events events ) +static void mlt_events_store( mlt_properties self, mlt_events events ) { - if ( this != NULL && events != NULL ) - mlt_properties_set_data( this, "_events", events, 0, ( mlt_destructor )mlt_events_close, NULL ); + if ( self != NULL && events != NULL ) + mlt_properties_set_data( self, "_events", events, 0, ( mlt_destructor )mlt_events_close, NULL ); } /** Close the events object. diff -Nru mlt-0.6.2/src/framework/mlt_factory.c mlt-0.7.2/src/framework/mlt_factory.c --- mlt-0.6.2/src/framework/mlt_factory.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_factory.c 2011-05-02 05:59:12.000000000 +0000 @@ -27,11 +27,18 @@ #include #include +#ifdef WIN32 +#include +/** the default subdirectory of the libdir for holding modules (plugins) */ +#define PREFIX_LIB "lib\\mlt" +/** the default subdirectory of the install prefix for holding module (plugin) data */ +#define PREFIX_DATA "share\\mlt" +#else /** the default subdirectory of the libdir for holding modules (plugins) */ #define PREFIX_LIB LIBDIR "/mlt" /** the default subdirectory of the install prefix for holding module (plugin) data */ #define PREFIX_DATA PREFIX "/share/mlt" - +#endif /** holds the full path to the modules directory - initialized and retained for the entire session */ static char *mlt_directory = NULL; @@ -50,28 +57,28 @@ * * \param listener * \param owner - * \param this + * \param self * \param args */ -static void mlt_factory_create_request( mlt_listener listener, mlt_properties owner, mlt_service this, void **args ) +static void mlt_factory_create_request( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ) { if ( listener != NULL ) - listener( owner, this, ( char * )args[ 0 ], ( char * )args[ 1 ], ( mlt_service * )args[ 2 ] ); + listener( owner, self, ( char * )args[ 0 ], ( char * )args[ 1 ], ( mlt_service * )args[ 2 ] ); } /** the -create-done event transmitter * * \param listener * \param owner - * \param this + * \param self * \param args */ -static void mlt_factory_create_done( mlt_listener listener, mlt_properties owner, mlt_service this, void **args ) +static void mlt_factory_create_done( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ) { if ( listener != NULL ) - listener( owner, this, ( char * )args[ 0 ], ( char * )args[ 1 ], ( mlt_service )args[ 2 ] ); + listener( owner, self, ( char * )args[ 0 ], ( char * )args[ 1 ], ( mlt_service )args[ 2 ] ); } /** Construct the repository and factories. @@ -106,6 +113,7 @@ mlt_properties_set_or_default( global_properties, "MLT_CONSUMER", getenv( "MLT_CONSUMER" ), "sdl" ); mlt_properties_set( global_properties, "MLT_TEST_CARD", getenv( "MLT_TEST_CARD" ) ); mlt_properties_set_or_default( global_properties, "MLT_PROFILE", getenv( "MLT_PROFILE" ), "dv_pal" ); + mlt_properties_set_or_default( global_properties, "MLT_DATA", getenv( "MLT_DATA" ), PREFIX_DATA ); } @@ -363,8 +371,14 @@ if ( mlt_directory != NULL ) { mlt_properties_close( event_object ); + event_object = NULL; mlt_properties_close( global_properties ); - mlt_repository_close( repository ); + global_properties = NULL; + if ( repository ) + { + mlt_repository_close( repository ); + repository = NULL; + } free( mlt_directory ); mlt_directory = NULL; mlt_pool_close( ); diff -Nru mlt-0.6.2/src/framework/mlt_field.c mlt-0.7.2/src/framework/mlt_field.c --- mlt-0.6.2/src/framework/mlt_field.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_field.c 2011-05-02 05:59:12.000000000 +0000 @@ -57,26 +57,26 @@ mlt_field mlt_field_init( ) { // Initialise the field - mlt_field this = calloc( sizeof( struct mlt_field_s ), 1 ); + mlt_field self = calloc( sizeof( struct mlt_field_s ), 1 ); // Initialise it - if ( this != NULL ) + if ( self != NULL ) { // Construct a multitrack - this->multitrack = mlt_multitrack_init( ); + self->multitrack = mlt_multitrack_init( ); // Construct a tractor - this->tractor = mlt_tractor_init( ); + self->tractor = mlt_tractor_init( ); // The first plant will be connected to the mulitrack - this->producer = MLT_MULTITRACK_SERVICE( this->multitrack ); + self->producer = MLT_MULTITRACK_SERVICE( self->multitrack ); // Connect the tractor to the multitrack - mlt_tractor_connect( this->tractor, this->producer ); + mlt_tractor_connect( self->tractor, self->producer ); } - // Return this - return this; + // Return self + return self; } /** Construct a field and initialize with supplied multitrack and tractor. @@ -90,101 +90,101 @@ mlt_field mlt_field_new( mlt_multitrack multitrack, mlt_tractor tractor ) { // Initialise the field - mlt_field this = calloc( sizeof( struct mlt_field_s ), 1 ); + mlt_field self = calloc( sizeof( struct mlt_field_s ), 1 ); // Initialise it - if ( this != NULL ) + if ( self != NULL ) { // Construct a multitrack - this->multitrack = multitrack; + self->multitrack = multitrack; // Construct a tractor - this->tractor = tractor; + self->tractor = tractor; // The first plant will be connected to the mulitrack - this->producer = MLT_MULTITRACK_SERVICE( this->multitrack ); + self->producer = MLT_MULTITRACK_SERVICE( self->multitrack ); // Connect the tractor to the multitrack - mlt_tractor_connect( this->tractor, this->producer ); + mlt_tractor_connect( self->tractor, self->producer ); } - // Return this - return this; + // Return self + return self; } /** Get the service associated to this field. * * \public \memberof mlt_field_s - * \param this a field + * \param self a field * \return the tractor as a service */ -mlt_service mlt_field_service( mlt_field this ) +mlt_service mlt_field_service( mlt_field self ) { - return MLT_TRACTOR_SERVICE( this->tractor ); + return MLT_TRACTOR_SERVICE( self->tractor ); } /** Get the multitrack. * * \public \memberof mlt_field_s - * \param this a field + * \param self a field * \return the multitrack */ -mlt_multitrack mlt_field_multitrack( mlt_field this ) +mlt_multitrack mlt_field_multitrack( mlt_field self ) { - return this != NULL ? this->multitrack : NULL; + return self != NULL ? self->multitrack : NULL; } /** Get the tractor. * * \public \memberof mlt_field_s - * \param this a field + * \param self a field * \return the tractor */ -mlt_tractor mlt_field_tractor( mlt_field this ) +mlt_tractor mlt_field_tractor( mlt_field self ) { - return this != NULL ? this->tractor : NULL; + return self != NULL ? self->tractor : NULL; } /** Get the properties associated to this field. * * \public \memberof mlt_field_s - * \param this a field + * \param self a field * \return a properties list */ -mlt_properties mlt_field_properties( mlt_field this ) +mlt_properties mlt_field_properties( mlt_field self ) { - return MLT_SERVICE_PROPERTIES( mlt_field_service( this ) ); + return MLT_SERVICE_PROPERTIES( mlt_field_service( self ) ); } /** Plant a filter. * * \public \memberof mlt_field_s - * \param this a field + * \param self a field * \param that a filter * \param track the track index * \return true if there was an error */ -int mlt_field_plant_filter( mlt_field this, mlt_filter that, int track ) +int mlt_field_plant_filter( mlt_field self, mlt_filter that, int track ) { // Connect the filter to the last producer - int result = mlt_filter_connect( that, this->producer, track ); + int result = mlt_filter_connect( that, self->producer, track ); // If sucessful, then we'll use this for connecting in the future if ( result == 0 ) { // This is now the new producer - this->producer = MLT_FILTER_SERVICE( that ); + self->producer = MLT_FILTER_SERVICE( that ); // Reconnect tractor to new producer - mlt_tractor_connect( this->tractor, this->producer ); + mlt_tractor_connect( self->tractor, self->producer ); // Fire an event - mlt_events_fire( mlt_field_properties( this ), "service-changed", NULL ); + mlt_events_fire( mlt_field_properties( self ), "service-changed", NULL ); } return result; @@ -193,29 +193,29 @@ /** Plant a transition. * * \public \memberof mlt_field_s - * \param this a field + * \param self a field * \param that a transition * \param a_track input A's track index * \param b_track input B's track index * \return true if there was an error */ -int mlt_field_plant_transition( mlt_field this, mlt_transition that, int a_track, int b_track ) +int mlt_field_plant_transition( mlt_field self, mlt_transition that, int a_track, int b_track ) { // Connect the transition to the last producer - int result = mlt_transition_connect( that, this->producer, a_track, b_track ); + int result = mlt_transition_connect( that, self->producer, a_track, b_track ); - // If sucessful, then we'll use this for connecting in the future + // If sucessful, then we'll use self for connecting in the future if ( result == 0 ) { // This is now the new producer - this->producer = MLT_TRANSITION_SERVICE( that ); + self->producer = MLT_TRANSITION_SERVICE( that ); // Reconnect tractor to new producer - mlt_tractor_connect( this->tractor, this->producer ); + mlt_tractor_connect( self->tractor, self->producer ); // Fire an event - mlt_events_fire( mlt_field_properties( this ), "service-changed", NULL ); + mlt_events_fire( mlt_field_properties( self ), "service-changed", NULL ); } return 0; @@ -224,16 +224,16 @@ /** Close the field. * * \public \memberof mlt_field_s - * \param this a field + * \param self a field */ -void mlt_field_close( mlt_field this ) +void mlt_field_close( mlt_field self ) { - if ( this != NULL && mlt_properties_dec_ref( mlt_field_properties( this ) ) <= 0 ) + if ( self != NULL && mlt_properties_dec_ref( mlt_field_properties( self ) ) <= 0 ) { - //mlt_tractor_close( this->tractor ); - //mlt_multitrack_close( this->multitrack ); - free( this ); + //mlt_tractor_close( self->tractor ); + //mlt_multitrack_close( self->multitrack ); + free( self ); } } diff -Nru mlt-0.6.2/src/framework/mlt_filter.c mlt-0.7.2/src/framework/mlt_filter.c --- mlt-0.6.2/src/framework/mlt_filter.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_filter.c 2011-05-02 05:59:12.000000000 +0000 @@ -23,27 +23,28 @@ #include "mlt_filter.h" #include "mlt_frame.h" +#include "mlt_producer.h" #include #include #include -static int filter_get_frame( mlt_service this, mlt_frame_ptr frame, int index ); +static int filter_get_frame( mlt_service self, mlt_frame_ptr frame, int index ); /** Initialize a new filter. * * \public \memberof mlt_filter_s - * \param this a filter + * \param self a filter * \param child the object of a subclass * \return true if there was an error */ -int mlt_filter_init( mlt_filter this, void *child ) +int mlt_filter_init( mlt_filter self, void *child ) { - mlt_service service = &this->parent; - memset( this, 0, sizeof( struct mlt_filter_s ) ); - this->child = child; - if ( mlt_service_init( service, this ) == 0 ) + mlt_service service = &self->parent; + memset( self, 0, sizeof( struct mlt_filter_s ) ); + self->child = child; + if ( mlt_service_init( service, self ) == 0 ) { mlt_properties properties = MLT_SERVICE_PROPERTIES( service ); @@ -52,7 +53,7 @@ // Define the destructor service->close = ( mlt_destructor )mlt_filter_close; - service->close_object = this; + service->close_object = self; // Default in, out, track properties mlt_properties_set_position( properties, "in", 0 ); @@ -72,55 +73,55 @@ mlt_filter mlt_filter_new( ) { - mlt_filter this = calloc( 1, sizeof( struct mlt_filter_s ) ); - if ( this != NULL ) - mlt_filter_init( this, NULL ); - return this; + mlt_filter self = calloc( 1, sizeof( struct mlt_filter_s ) ); + if ( self != NULL ) + mlt_filter_init( self, NULL ); + return self; } /** Get the service class interface. * * \public \memberof mlt_filter_s - * \param this a filter + * \param self a filter * \return the service parent class * \see MLT_FILTER_SERVICE */ -mlt_service mlt_filter_service( mlt_filter this ) +mlt_service mlt_filter_service( mlt_filter self ) { - return this != NULL ? &this->parent : NULL; + return self != NULL ? &self->parent : NULL; } /** Get the filter properties. * * \public \memberof mlt_filter_s - * \param this a filter + * \param self a filter * \return the properties list for the filter * \see MLT_FILTER_PROPERTIES */ -mlt_properties mlt_filter_properties( mlt_filter this ) +mlt_properties mlt_filter_properties( mlt_filter self ) { - return MLT_SERVICE_PROPERTIES( MLT_FILTER_SERVICE( this ) ); + return MLT_SERVICE_PROPERTIES( MLT_FILTER_SERVICE( self ) ); } /** Connect this filter to a producers track. Note that a filter only operates * on a single track, and by default it operates on the entirety of that track. * * \public \memberof mlt_filter_s - * \param this a filter + * \param self a filter * \param producer the producer to which to connect this filter * \param index which of potentially multiple producers to this service (0 based) */ -int mlt_filter_connect( mlt_filter this, mlt_service producer, int index ) +int mlt_filter_connect( mlt_filter self, mlt_service producer, int index ) { - int ret = mlt_service_connect_producer( &this->parent, producer, index ); + int ret = mlt_service_connect_producer( &self->parent, producer, index ); // If the connection was successful, grab the producer, track and reset in/out if ( ret == 0 ) { - mlt_properties properties = MLT_SERVICE_PROPERTIES( &this->parent ); + mlt_properties properties = MLT_SERVICE_PROPERTIES( &self->parent ); mlt_properties_set_position( properties, "in", 0 ); mlt_properties_set_position( properties, "out", 0 ); mlt_properties_set_int( properties, "track", index ); @@ -132,15 +133,15 @@ /** Set the starting and ending time. * * \public \memberof mlt_filter_s - * \param this a filter + * \param self a filter * \param in the time relative to the producer at which start applying the filter * \param out the time relative to the producer at which to stop applying the filter */ -void mlt_filter_set_in_and_out( mlt_filter this, mlt_position in, mlt_position out ) +void mlt_filter_set_in_and_out( mlt_filter self, mlt_position in, mlt_position out ) { - mlt_properties properties = MLT_SERVICE_PROPERTIES( &this->parent ); + mlt_properties properties = MLT_SERVICE_PROPERTIES( &self->parent ); mlt_properties_set_position( properties, "in", in ); mlt_properties_set_position( properties, "out", out ); } @@ -148,61 +149,151 @@ /** Return the track that this filter is operating on. * * \public \memberof mlt_filter_s - * \param this a filter + * \param self a filter * \return true on error */ -int mlt_filter_get_track( mlt_filter this ) +int mlt_filter_get_track( mlt_filter self ) { - mlt_properties properties = MLT_SERVICE_PROPERTIES( &this->parent ); + mlt_properties properties = MLT_SERVICE_PROPERTIES( &self->parent ); return mlt_properties_get_int( properties, "track" ); } /** Get the in point. * * \public \memberof mlt_filter_s - * \param this a filter + * \param self a filter * \return the start time for the filter relative to the producer */ -mlt_position mlt_filter_get_in( mlt_filter this ) +mlt_position mlt_filter_get_in( mlt_filter self ) { - mlt_properties properties = MLT_SERVICE_PROPERTIES( &this->parent ); + mlt_properties properties = MLT_SERVICE_PROPERTIES( &self->parent ); return mlt_properties_get_position( properties, "in" ); } /** Get the out point. * * \public \memberof mlt_filter_s - * \param this a filter + * \param self a filter * \return the ending time for the filter relative to the producer */ -mlt_position mlt_filter_get_out( mlt_filter this ) +mlt_position mlt_filter_get_out( mlt_filter self ) { - mlt_properties properties = MLT_SERVICE_PROPERTIES( &this->parent ); + mlt_properties properties = MLT_SERVICE_PROPERTIES( &self->parent ); return mlt_properties_get_position( properties, "out" ); } +/** Get the duration. + * + * \public \memberof mlt_filter_s + * \param self a filter + * \return the duration or zero if unlimited + */ + +mlt_position mlt_filter_get_length( mlt_filter self ) +{ + mlt_properties properties = MLT_SERVICE_PROPERTIES( &self->parent ); + mlt_position in = mlt_properties_get_position( properties, "in" ); + mlt_position out = mlt_properties_get_position( properties, "out" ); + return ( out > 0 ) ? ( out - in + 1 ) : 0; +} + +/** Get the position within the filter. + * + * The position is relative to the in point. + * This will only be valid once mlt_filter_process is called. + * + * \public \memberof mlt_filter_s + * \param self a filter + * \param frame a frame + * \return the position + */ + +mlt_position mlt_filter_get_position( mlt_filter self, mlt_frame frame ) +{ + mlt_properties properties = MLT_FILTER_PROPERTIES( self ); + mlt_position in = mlt_properties_get_position( properties, "in" ); + const char *unique_id = mlt_properties_get( properties, "_unique_id" ); + char name[20]; + + // Make the properties key from unique id + strcpy( name, "pos." ); + strcat( name, unique_id ); + + return mlt_properties_get_position( MLT_FRAME_PROPERTIES( frame ), name ) - in; +} + +/** Get the percent complete. + * + * This will only be valid once mlt_filter_process is called. + * + * \public \memberof mlt_filter_s + * \param self a filter + * \param frame a frame + * \return the progress in the range 0.0 to 1.0 + */ + +double mlt_filter_get_progress( mlt_filter self, mlt_frame frame ) +{ + double progress = 0; + mlt_position in = mlt_filter_get_in( self ); + mlt_position out = mlt_filter_get_out( self ); + + if ( out == 0 ) + { + // If always active, use the frame's producer + mlt_producer producer = mlt_frame_get_original_producer( frame ); + if ( producer ) + { + in = mlt_producer_get_in( producer ); + out = mlt_producer_get_out( producer ); + } + } + if ( out != 0 ) + { + mlt_position position = mlt_filter_get_position( self, frame ); + progress = ( double ) position / ( double ) ( out - in + 1 ); + } + return progress; +} + /** Process the frame. * + * When fetching the frame position in a subclass process method, the frame's + * position is relative to the filter's producer - not the filter's in point + * or timeline. + * * \public \memberof mlt_filter_s - * \param this a filter + * \param self a filter * \param frame a frame * \return a frame */ -mlt_frame mlt_filter_process( mlt_filter this, mlt_frame frame ) +mlt_frame mlt_filter_process( mlt_filter self, mlt_frame frame ) { - int disable = mlt_properties_get_int( MLT_FILTER_PROPERTIES( this ), "disable" ); - if ( disable || this->process == NULL ) + mlt_properties properties = MLT_FILTER_PROPERTIES( self ); + int disable = mlt_properties_get_int( properties, "disable" ); + const char *unique_id = mlt_properties_get( properties, "_unique_id" ); + mlt_position position = mlt_frame_get_position( frame ); + char name[20]; + + // Make the properties key from unique id + strcpy( name, "pos." ); + strcat( name, unique_id ); + + // Save the position on the frame + mlt_properties_set_position( MLT_FRAME_PROPERTIES( frame ), name, position ); + + if ( disable || self->process == NULL ) return frame; else - return this->process( this, frame ); + return self->process( self, frame ); } /** Get a frame from this filter. @@ -217,15 +308,15 @@ static int filter_get_frame( mlt_service service, mlt_frame_ptr frame, int index ) { - mlt_filter this = service->child; + mlt_filter self = service->child; // Get coords in/out/track - int track = mlt_filter_get_track( this ); - int in = mlt_filter_get_in( this ); - int out = mlt_filter_get_out( this ); + int track = mlt_filter_get_track( self ); + int in = mlt_filter_get_in( self ); + int out = mlt_filter_get_out( self ); // Get the producer this is connected to - mlt_service producer = mlt_service_producer( &this->parent ); + mlt_service producer = mlt_service_producer( &self->parent ); // If the frame request is for this filters track, we need to process it if ( index == track || track == -1 ) @@ -235,7 +326,7 @@ { mlt_position position = mlt_frame_get_position( *frame ); if ( position >= in && ( out == 0 || position <= out ) ) - *frame = mlt_filter_process( this, *frame ); + *frame = mlt_filter_process( self, *frame ); return 0; } else @@ -253,23 +344,23 @@ /** Close and destroy the filter. * * \public \memberof mlt_filter_s - * \param this a filter + * \param self a filter */ -void mlt_filter_close( mlt_filter this ) +void mlt_filter_close( mlt_filter self ) { - if ( this != NULL && mlt_properties_dec_ref( MLT_FILTER_PROPERTIES( this ) ) <= 0 ) + if ( self != NULL && mlt_properties_dec_ref( MLT_FILTER_PROPERTIES( self ) ) <= 0 ) { - if ( this->close != NULL ) + if ( self->close != NULL ) { - this->close( this ); + self->close( self ); } else { - this->parent.close = NULL; - mlt_service_close( &this->parent ); + self->parent.close = NULL; + mlt_service_close( &self->parent ); } - free( this ); + free( self ); } } diff -Nru mlt-0.6.2/src/framework/mlt_filter.h mlt-0.7.2/src/framework/mlt_filter.h --- mlt-0.6.2/src/framework/mlt_filter.h 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_filter.h 2011-05-02 05:59:12.000000000 +0000 @@ -64,6 +64,9 @@ extern int mlt_filter_get_track( mlt_filter self ); extern mlt_position mlt_filter_get_in( mlt_filter self ); extern mlt_position mlt_filter_get_out( mlt_filter self ); +extern mlt_position mlt_filter_get_length( mlt_filter self ); +extern mlt_position mlt_filter_get_position( mlt_filter self, mlt_frame frame ); +extern double mlt_filter_get_progress( mlt_filter self, mlt_frame frame ); extern void mlt_filter_close( mlt_filter ); #endif diff -Nru mlt-0.6.2/src/framework/mlt_frame.c mlt-0.7.2/src/framework/mlt_frame.c --- mlt-0.6.2/src/framework/mlt_frame.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_frame.c 2011-05-02 05:59:12.000000000 +0000 @@ -41,15 +41,15 @@ mlt_frame mlt_frame_init( mlt_service service ) { // Allocate a frame - mlt_frame this = calloc( sizeof( struct mlt_frame_s ), 1 ); + mlt_frame self = calloc( sizeof( struct mlt_frame_s ), 1 ); - if ( this != NULL ) + if ( self != NULL ) { mlt_profile profile = mlt_service_profile( service ); // Initialise the properties - mlt_properties properties = &this->parent; - mlt_properties_init( properties, this ); + mlt_properties properties = &self->parent; + mlt_properties_init( properties, self ); // Set default properties on the frame mlt_properties_set_position( properties, "_position", 0.0 ); @@ -63,236 +63,266 @@ mlt_properties_set_data( properties, "alpha", NULL, 0, NULL, NULL ); // Construct stacks for frames and methods - this->stack_image = mlt_deque_init( ); - this->stack_audio = mlt_deque_init( ); - this->stack_service = mlt_deque_init( ); + self->stack_image = mlt_deque_init( ); + self->stack_audio = mlt_deque_init( ); + self->stack_service = mlt_deque_init( ); } - return this; + return self; } /** Get a frame's properties. * * \public \memberof mlt_frame_s - * \param this a frame + * \param self a frame * \return the frame's properties or NULL if an invalid frame is supplied */ -mlt_properties mlt_frame_properties( mlt_frame this ) +mlt_properties mlt_frame_properties( mlt_frame self ) { - return this != NULL ? &this->parent : NULL; + return self != NULL ? &self->parent : NULL; } /** Determine if the frame will produce a test card image. * * \public \memberof mlt_frame_s - * \param this a frame + * \param self a frame * \return true (non-zero) if this will produce from a test card */ -int mlt_frame_is_test_card( mlt_frame this ) +int mlt_frame_is_test_card( mlt_frame self ) { - return mlt_deque_count( this->stack_image ) == 0 || mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "test_image" ); + return mlt_deque_count( self->stack_image ) == 0 || mlt_properties_get_int( MLT_FRAME_PROPERTIES( self ), "test_image" ); } /** Determine if the frame will produce audio from a test card. * * \public \memberof mlt_frame_s - * \param this a frame + * \param self a frame * \return true (non-zero) if this will produce from a test card */ -int mlt_frame_is_test_audio( mlt_frame this ) +int mlt_frame_is_test_audio( mlt_frame self ) { - return mlt_deque_count( this->stack_audio ) == 0 || mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "test_audio" ); + return mlt_deque_count( self->stack_audio ) == 0 || mlt_properties_get_int( MLT_FRAME_PROPERTIES( self ), "test_audio" ); } /** Get the sample aspect ratio of the frame. * * \public \memberof mlt_frame_s - * \param this a frame + * \param self a frame * \return the aspect ratio */ -double mlt_frame_get_aspect_ratio( mlt_frame this ) +double mlt_frame_get_aspect_ratio( mlt_frame self ) { - return mlt_properties_get_double( MLT_FRAME_PROPERTIES( this ), "aspect_ratio" ); + return mlt_properties_get_double( MLT_FRAME_PROPERTIES( self ), "aspect_ratio" ); } /** Set the sample aspect ratio of the frame. * * \public \memberof mlt_frame_s - * \param this a frame + * \param self a frame * \param value the new image sample aspect ratio * \return true if error */ -int mlt_frame_set_aspect_ratio( mlt_frame this, double value ) +int mlt_frame_set_aspect_ratio( mlt_frame self, double value ) { - return mlt_properties_set_double( MLT_FRAME_PROPERTIES( this ), "aspect_ratio", value ); + return mlt_properties_set_double( MLT_FRAME_PROPERTIES( self ), "aspect_ratio", value ); } /** Get the time position of this frame. * * \public \memberof mlt_frame_s - * \param this a frame + * \param self a frame * \return the position */ -mlt_position mlt_frame_get_position( mlt_frame this ) +mlt_position mlt_frame_get_position( mlt_frame self ) { - int pos = mlt_properties_get_position( MLT_FRAME_PROPERTIES( this ), "_position" ); + int pos = mlt_properties_get_position( MLT_FRAME_PROPERTIES( self ), "_position" ); return pos < 0 ? 0 : pos; } /** Set the time position of this frame. * * \public \memberof mlt_frame_s - * \param this a frame + * \param self a frame * \param value the position * \return true if error */ -int mlt_frame_set_position( mlt_frame this, mlt_position value ) +int mlt_frame_set_position( mlt_frame self, mlt_position value ) { - return mlt_properties_set_position( MLT_FRAME_PROPERTIES( this ), "_position", value ); + return mlt_properties_set_position( MLT_FRAME_PROPERTIES( self ), "_position", value ); } /** Stack a get_image callback. * * \public \memberof mlt_frame_s - * \param this a frame + * \param self a frame * \param the get_image callback * \return true if error */ -int mlt_frame_push_get_image( mlt_frame this, mlt_get_image get_image ) +int mlt_frame_push_get_image( mlt_frame self, mlt_get_image get_image ) { - return mlt_deque_push_back( this->stack_image, get_image ); + return mlt_deque_push_back( self->stack_image, get_image ); } /** Pop a get_image callback. * * \public \memberof mlt_frame_s - * \param this a frame + * \param self a frame * \return the get_image callback */ -mlt_get_image mlt_frame_pop_get_image( mlt_frame this ) +mlt_get_image mlt_frame_pop_get_image( mlt_frame self ) { - return mlt_deque_pop_back( this->stack_image ); + return mlt_deque_pop_back( self->stack_image ); } /** Push a frame. * * \public \memberof mlt_frame_s - * \param this a frame - * \param that the frame to push onto \p this + * \param self a frame + * \param that the frame to push onto \p self * \return true if error */ -int mlt_frame_push_frame( mlt_frame this, mlt_frame that ) +int mlt_frame_push_frame( mlt_frame self, mlt_frame that ) { - return mlt_deque_push_back( this->stack_image, that ); + return mlt_deque_push_back( self->stack_image, that ); } /** Pop a frame. * * \public \memberof mlt_frame_s - * \param this a frame + * \param self a frame * \return a frame that was previously pushed */ -mlt_frame mlt_frame_pop_frame( mlt_frame this ) +mlt_frame mlt_frame_pop_frame( mlt_frame self ) { - return mlt_deque_pop_back( this->stack_image ); + return mlt_deque_pop_back( self->stack_image ); } /** Push a service. * * \public \memberof mlt_frame_s - * \param this a frame + * \param self a frame * \param that an opaque pointer * \return true if error */ -int mlt_frame_push_service( mlt_frame this, void *that ) +int mlt_frame_push_service( mlt_frame self, void *that ) { - return mlt_deque_push_back( this->stack_image, that ); + return mlt_deque_push_back( self->stack_image, that ); } /** Pop a service. * * \public \memberof mlt_frame_s - * \param this a frame + * \param self a frame * \return an opaque pointer to something previously pushed */ -void *mlt_frame_pop_service( mlt_frame this ) +void *mlt_frame_pop_service( mlt_frame self ) { - return mlt_deque_pop_back( this->stack_image ); + return mlt_deque_pop_back( self->stack_image ); } /** Push a number. * * \public \memberof mlt_frame_s - * \param this a frame + * \param self a frame * \param that an integer * \return true if error */ -int mlt_frame_push_service_int( mlt_frame this, int that ) +int mlt_frame_push_service_int( mlt_frame self, int that ) { - return mlt_deque_push_back_int( this->stack_image, that ); + return mlt_deque_push_back_int( self->stack_image, that ); } /** Pop a number. * * \public \memberof mlt_frame_s - * \param this a frame + * \param self a frame * \return an integer that was previously pushed */ -int mlt_frame_pop_service_int( mlt_frame this ) +int mlt_frame_pop_service_int( mlt_frame self ) { - return mlt_deque_pop_back_int( this->stack_image ); + return mlt_deque_pop_back_int( self->stack_image ); } /** Push an audio item on the stack. * * \public \memberof mlt_frame_s - * \param this a frame + * \param self a frame * \param that an opaque pointer * \return true if error */ -int mlt_frame_push_audio( mlt_frame this, void *that ) +int mlt_frame_push_audio( mlt_frame self, void *that ) { - return mlt_deque_push_back( this->stack_audio, that ); + return mlt_deque_push_back( self->stack_audio, that ); } /** Pop an audio item from the stack * * \public \memberof mlt_frame_s - * \param this a frame + * \param self a frame * \return an opaque pointer to something that was pushed onto the frame's audio stack */ -void *mlt_frame_pop_audio( mlt_frame this ) +void *mlt_frame_pop_audio( mlt_frame self ) { - return mlt_deque_pop_back( this->stack_audio ); + return mlt_deque_pop_back( self->stack_audio ); } /** Return the service stack * * \public \memberof mlt_frame_s - * \param this a frame + * \param self a frame * \return the service stack */ -mlt_deque mlt_frame_service_stack( mlt_frame this ) +mlt_deque mlt_frame_service_stack( mlt_frame self ) { - return this->stack_service; + return self->stack_service; +} + +/** Set a new image on the frame. + * + * \public \memberof mlt_frame_s + * \param self a frame + * \param image a pointer to the raw image data + * \param size the size of the image data in bytes (optional) + * \param destroy a function to deallocate \p image when the frame is closed (optional) + * \return true if error + */ + +int mlt_frame_set_image( mlt_frame self, uint8_t *image, int size, mlt_destructor destroy ) +{ + return mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "image", image, size, destroy, NULL ); +} + +/** Set a new alpha channel on the frame. + * + * \public \memberof mlt_frame_s + * \param self a frame + * \param alpha a pointer to the alpha channel + * \param size the size of the alpha channel in bytes (optional) + * \param destroy a function to deallocate \p alpha when the frame is closed (optional) + * \return true if error + */ + +int mlt_frame_set_alpha( mlt_frame self, uint8_t *alpha, int size, mlt_destructor destroy ) +{ + return mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "alpha", alpha, size, destroy, NULL ); } /** Replace image stack with the information provided. @@ -314,24 +344,24 @@ * and the upper tracks should simply not be invited to stack... * * \public \memberof mlt_frame_s - * \param this a frame + * \param self a frame * \param image a new image * \param format the image format * \param width the width of the new image * \param height the height of the new image */ -void mlt_frame_replace_image( mlt_frame this, uint8_t *image, mlt_image_format format, int width, int height ) +void mlt_frame_replace_image( mlt_frame self, uint8_t *image, mlt_image_format format, int width, int height ) { // Remove all items from the stack - while( mlt_deque_pop_back( this->stack_image ) ) ; + while( mlt_deque_pop_back( self->stack_image ) ) ; // Update the information - mlt_properties_set_data( MLT_FRAME_PROPERTIES( this ), "image", image, 0, NULL, NULL ); - mlt_properties_set_int( MLT_FRAME_PROPERTIES( this ), "width", width ); - mlt_properties_set_int( MLT_FRAME_PROPERTIES( this ), "height", height ); - mlt_properties_set_int( MLT_FRAME_PROPERTIES( this ), "format", format ); - this->get_alpha_mask = NULL; + mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "image", image, 0, NULL, NULL ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "width", width ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "height", height ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "format", format ); + self->get_alpha_mask = NULL; } /** Get the short name for an image format. @@ -355,6 +385,40 @@ return "invalid"; } +/** Get the number of bytes needed for an image. + * + * \public \memberof mlt_frame_s + * \param format the image format + * \param width width of the image in pixels + * \param height height of the image in pixels + * \param[out] bpp the number of bytes per pixel (optional) + * \return the number of bytes + */ +int mlt_image_format_size( mlt_image_format format, int width, int height, int *bpp ) +{ + height += 1; + switch ( format ) + { + case mlt_image_none: + if ( bpp ) *bpp = 0; + return 0; + case mlt_image_rgb24: + if ( bpp ) *bpp = 3; + return width * height * 3; + case mlt_image_opengl: + case mlt_image_rgb24a: + if ( bpp ) *bpp = 4; + return width * height * 4; + case mlt_image_yuv422: + if ( bpp ) *bpp = 2; + return width * height * 2; + case mlt_image_yuv420p: + if ( bpp ) *bpp = 3 / 2; + return width * height * 3 / 2; + } + return 0; +} + /** Get the image associated to the frame. * * You should express the desired format, width, and height as inputs. As long @@ -365,7 +429,7 @@ * buffer, but you should always supply the desired image format. * * \public \memberof mlt_frame_s - * \param this a frame + * \param self a frame * \param[out] buffer an image buffer * \param[in,out] format the image format * \param[in,out] width the horizontal size in pixels @@ -375,10 +439,10 @@ * \todo Better describe the width and height as inputs. */ -int mlt_frame_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) +int mlt_frame_get_image( mlt_frame self, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { - mlt_properties properties = MLT_FRAME_PROPERTIES( this ); - mlt_get_image get_image = mlt_frame_pop_get_image( this ); + mlt_properties properties = MLT_FRAME_PROPERTIES( self ); + mlt_get_image get_image = mlt_frame_pop_get_image( self ); mlt_producer producer = mlt_properties_get_data( properties, "test_card_producer", NULL ); mlt_image_format requested_format = *format; int error = 0; @@ -386,19 +450,19 @@ if ( get_image ) { mlt_properties_set_int( properties, "image_count", mlt_properties_get_int( properties, "image_count" ) - 1 ); - error = get_image( this, buffer, format, width, height, writable ); + error = get_image( self, buffer, format, width, height, writable ); if ( !error && *buffer ) { mlt_properties_set_int( properties, "width", *width ); mlt_properties_set_int( properties, "height", *height ); + if ( self->convert_image && *buffer ) + self->convert_image( self, buffer, format, requested_format ); mlt_properties_set_int( properties, "format", *format ); - if ( this->convert_image ) - this->convert_image( this, buffer, format, requested_format ); } else { // Cause the image to be loaded from test card or fallback (white) below. - mlt_frame_get_image( this, buffer, format, width, height, writable ); + mlt_frame_get_image( self, buffer, format, width, height, writable ); } } else if ( mlt_properties_get_data( properties, "image", NULL ) ) @@ -407,8 +471,11 @@ *buffer = mlt_properties_get_data( properties, "image", NULL ); *width = mlt_properties_get_int( properties, "width" ); *height = mlt_properties_get_int( properties, "height" ); - if ( this->convert_image && *buffer ) - this->convert_image( this, buffer, format, requested_format ); + if ( self->convert_image && *buffer ) + { + self->convert_image( self, buffer, format, requested_format ); + mlt_properties_set_int( properties, "format", *format ); + } } else if ( producer ) { @@ -430,7 +497,7 @@ else { mlt_properties_set_data( properties, "test_card_producer", NULL, 0, NULL, NULL ); - mlt_frame_get_image( this, buffer, format, width, height, writable ); + mlt_frame_get_image( self, buffer, format, width, height, writable ); } } else @@ -499,25 +566,25 @@ /** Get the alpha channel associated to the frame. * * \public \memberof mlt_frame_s - * \param this a frame + * \param self a frame * \return the alpha channel */ -uint8_t *mlt_frame_get_alpha_mask( mlt_frame this ) +uint8_t *mlt_frame_get_alpha_mask( mlt_frame self ) { uint8_t *alpha = NULL; - if ( this != NULL ) + if ( self != NULL ) { - if ( this->get_alpha_mask != NULL ) - alpha = this->get_alpha_mask( this ); + if ( self->get_alpha_mask != NULL ) + alpha = self->get_alpha_mask( self ); if ( alpha == NULL ) - alpha = mlt_properties_get_data( &this->parent, "alpha", NULL ); + alpha = mlt_properties_get_data( &self->parent, "alpha", NULL ); if ( alpha == NULL ) { - int size = mlt_properties_get_int( &this->parent, "width" ) * mlt_properties_get_int( &this->parent, "height" ); + int size = mlt_properties_get_int( &self->parent, "width" ) * mlt_properties_get_int( &self->parent, "height" ); alpha = mlt_pool_alloc( size ); memset( alpha, 255, size ); - mlt_properties_set_data( &this->parent, "alpha", alpha, size, mlt_pool_release, NULL ); + mlt_properties_set_data( &self->parent, "alpha", alpha, size, mlt_pool_release, NULL ); } } return alpha; @@ -527,8 +594,7 @@ * * You do not need to deallocate the returned string. * \public \memberof mlt_frame_s - * \param this a frame - * \param format an image format enum + * \param format an audio format enum * \return a string for the name of the image format */ @@ -544,6 +610,27 @@ return "invalid"; } +/** Get the amount of bytes needed for a block of audio. + * + * \public \memberof mlt_frame_s + * \param format an audio format enum + * \param samples the number of samples per channel + * \param channels the number of channels + * \return the number of bytes + */ + +int mlt_audio_format_size( mlt_audio_format format, int samples, int channels ) +{ + switch ( format ) + { + case mlt_audio_none: return 0; + case mlt_audio_s16: return samples * channels * sizeof( int16_t ); + case mlt_audio_s32: return samples * channels * sizeof( int32_t ); + case mlt_audio_float: return samples * channels * sizeof( float ); + } + return 0; +} + /** Get the audio associated to the frame. * * You should express the desired format, frequency, channels, and samples as inputs. As long @@ -556,7 +643,7 @@ * You should use the \p mlt_sample_calculator to determine the number of samples you want. * * \public \memberof mlt_frame_s - * \param this a frame + * \param self a frame * \param[out] buffer an audio buffer * \param[in,out] format the audio format * \param[in,out] frequency the sample rate @@ -565,22 +652,22 @@ * \return true if error */ -int mlt_frame_get_audio( mlt_frame this, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) +int mlt_frame_get_audio( mlt_frame self, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { - mlt_get_audio get_audio = mlt_frame_pop_audio( this ); - mlt_properties properties = MLT_FRAME_PROPERTIES( this ); + mlt_get_audio get_audio = mlt_frame_pop_audio( self ); + mlt_properties properties = MLT_FRAME_PROPERTIES( self ); int hide = mlt_properties_get_int( properties, "test_audio" ); mlt_audio_format requested_format = *format; if ( hide == 0 && get_audio != NULL ) { - get_audio( this, buffer, format, frequency, channels, samples ); + get_audio( self, buffer, format, frequency, channels, samples ); mlt_properties_set_int( properties, "audio_frequency", *frequency ); mlt_properties_set_int( properties, "audio_channels", *channels ); mlt_properties_set_int( properties, "audio_samples", *samples ); mlt_properties_set_int( properties, "audio_format", *format ); - if ( this->convert_audio ) - this->convert_audio( this, buffer, format, requested_format ); + if ( self->convert_audio ) + self->convert_audio( self, buffer, format, requested_format ); } else if ( mlt_properties_get_data( properties, "audio", NULL ) ) { @@ -589,8 +676,8 @@ *frequency = mlt_properties_get_int( properties, "audio_frequency" ); *channels = mlt_properties_get_int( properties, "audio_channels" ); *samples = mlt_properties_get_int( properties, "audio_samples" ); - if ( this->convert_audio ) - this->convert_audio( this, buffer, format, requested_format ); + if ( self->convert_audio ) + self->convert_audio( self, buffer, format, requested_format ); } else { @@ -656,7 +743,7 @@ /** Set the audio on a frame. * * \public \memberof mlt_frame_s - * \param this a frame + * \param self a frame * \param buffer an buffer containing audio samples * \param format the format of the audio in the \p buffer * \param size the total size of the buffer (optional) @@ -664,10 +751,10 @@ * \return true if error */ -int mlt_frame_set_audio( mlt_frame this, void *buffer, mlt_audio_format format, int size, mlt_destructor destructor ) +int mlt_frame_set_audio( mlt_frame self, void *buffer, mlt_audio_format format, int size, mlt_destructor destructor ) { - mlt_properties_set_int( MLT_FRAME_PROPERTIES( this ), "audio_format", format ); - return mlt_properties_set_data( MLT_FRAME_PROPERTIES( this ), "audio", buffer, size, destructor, NULL ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES( self ), "audio_format", format ); + return mlt_properties_set_data( MLT_FRAME_PROPERTIES( self ), "audio", buffer, size, destructor, NULL ); } /** Get audio on a frame as a waveform image. @@ -678,32 +765,32 @@ * value with \p mlt_pool_release. * * \public \memberof mlt_frame_s - * \param this a frame + * \param self a frame * \param w the width of the image * \param h the height of the image to create * \return a pointer to a new bitmap */ -unsigned char *mlt_frame_get_waveform( mlt_frame this, int w, int h ) +unsigned char *mlt_frame_get_waveform( mlt_frame self, int w, int h ) { int16_t *pcm = NULL; - mlt_properties properties = MLT_FRAME_PROPERTIES( this ); + mlt_properties properties = MLT_FRAME_PROPERTIES( self ); mlt_audio_format format = mlt_audio_s16; int frequency = 16000; int channels = 2; - mlt_producer producer = mlt_frame_get_original_producer( this ); + mlt_producer producer = mlt_frame_get_original_producer( self ); double fps = mlt_producer_get_fps( mlt_producer_cut_parent( producer ) ); - int samples = mlt_sample_calculator( fps, frequency, mlt_frame_get_position( this ) ); + int samples = mlt_sample_calculator( fps, frequency, mlt_frame_get_position( self ) ); // Increase audio resolution proportional to requested image size while ( samples < w ) { frequency += 16000; - samples = mlt_sample_calculator( fps, frequency, mlt_frame_get_position( this ) ); + samples = mlt_sample_calculator( fps, frequency, mlt_frame_get_position( self ) ); } // Get the pcm data - mlt_frame_get_audio( this, (void**)&pcm, &format, &frequency, &channels, &samples ); + mlt_frame_get_audio( self, (void**)&pcm, &format, &frequency, &channels, &samples ); // Make an 8-bit buffer large enough to hold rendering int size = w * h; @@ -747,40 +834,40 @@ return bitmap; } -/** Get the end service that produced this frame. +/** Get the end service that produced self frame. * * This fetches the first producer of the frame and not any producers that * encapsulate it. * * \public \memberof mlt_frame_s - * \param this a frame + * \param self a frame * \return a producer */ -mlt_producer mlt_frame_get_original_producer( mlt_frame this ) +mlt_producer mlt_frame_get_original_producer( mlt_frame self ) { - if ( this != NULL ) - return mlt_properties_get_data( MLT_FRAME_PROPERTIES( this ), "_producer", NULL ); + if ( self != NULL ) + return mlt_properties_get_data( MLT_FRAME_PROPERTIES( self ), "_producer", NULL ); return NULL; } /** Destroy the frame. * * \public \memberof mlt_frame_s - * \param this a frame + * \param self a frame */ -void mlt_frame_close( mlt_frame this ) +void mlt_frame_close( mlt_frame self ) { - if ( this != NULL && mlt_properties_dec_ref( MLT_FRAME_PROPERTIES( this ) ) <= 0 ) + if ( self != NULL && mlt_properties_dec_ref( MLT_FRAME_PROPERTIES( self ) ) <= 0 ) { - mlt_deque_close( this->stack_image ); - mlt_deque_close( this->stack_audio ); - while( mlt_deque_peek_back( this->stack_service ) ) - mlt_service_close( mlt_deque_pop_back( this->stack_service ) ); - mlt_deque_close( this->stack_service ); - mlt_properties_close( &this->parent ); - free( this ); + mlt_deque_close( self->stack_image ); + mlt_deque_close( self->stack_audio ); + while( mlt_deque_peek_back( self->stack_service ) ) + mlt_service_close( mlt_deque_pop_back( self->stack_service ) ); + mlt_deque_close( self->stack_service ); + mlt_properties_close( &self->parent ); + free( self ); } } @@ -852,3 +939,35 @@ fclose( file ); } } + +/** Get or create a properties object unique to this service instance. + * + * Use this function to hold a service's processing parameters for this + * particular frame. Set the parameters in the service's process function. + * Then, get the parameters in the function it pushes to the frame's audio + * or image stack. This makes the service more parallel by reducing race + * conditions and less sensitive to multiple instances (by not setting a + * non-unique property on the frame). Creation and destruction of the + * properties object is handled automatically. + * + * \public \memberof mlt_frame_s + * \param self a frame + * \param service a service + * \return a properties object + */ + +mlt_properties mlt_frame_unique_properties( mlt_frame self, mlt_service service ) +{ + mlt_properties frame_props = MLT_FRAME_PROPERTIES( self ); + mlt_properties service_props = MLT_SERVICE_PROPERTIES( service ); + char *unique = mlt_properties_get( service_props, "_unique_id" ); + mlt_properties instance_props = mlt_properties_get_data( frame_props, unique, NULL ); + + if ( !instance_props ) + { + instance_props = mlt_properties_new(); + mlt_properties_set_data( frame_props, unique, instance_props, 0, (mlt_destructor) mlt_properties_close, NULL ); + } + + return instance_props; +} diff -Nru mlt-0.6.2/src/framework/mlt_frame.h mlt-0.7.2/src/framework/mlt_frame.h --- mlt-0.6.2/src/framework/mlt_frame.h 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_frame.h 2011-05-02 05:59:12.000000000 +0000 @@ -92,6 +92,7 @@ mlt_deque stack_image; /**< \private the image processing stack of operations and data */ mlt_deque stack_audio; /**< \private the audio processing stack of operations and data */ mlt_deque stack_service; /**< \private a general purpose data stack */ + int is_processing; /**< \private indicates if a frame is or was processed by the parallel consumer */ }; #define MLT_FRAME_PROPERTIES( frame ) ( &( frame )->parent ) @@ -107,6 +108,8 @@ extern int mlt_frame_set_aspect_ratio( mlt_frame self, double value ); extern mlt_position mlt_frame_get_position( mlt_frame self ); extern int mlt_frame_set_position( mlt_frame self, mlt_position value ); +extern int mlt_frame_set_image( mlt_frame self, uint8_t *image, int size, mlt_destructor destroy ); +extern int mlt_frame_set_alpha( mlt_frame self, uint8_t *alpha, int size, mlt_destructor destroy ); extern void mlt_frame_replace_image( mlt_frame self, uint8_t *image, mlt_image_format format, int width, int height ); extern int mlt_frame_get_image( mlt_frame self, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ); extern uint8_t *mlt_frame_get_alpha_mask( mlt_frame self ); @@ -126,12 +129,15 @@ extern mlt_deque mlt_frame_service_stack( mlt_frame self ); extern mlt_producer mlt_frame_get_original_producer( mlt_frame self ); extern void mlt_frame_close( mlt_frame self ); +extern mlt_properties mlt_frame_unique_properties( mlt_frame self, mlt_service service ); /* convenience functions */ extern int mlt_sample_calculator( float fps, int frequency, int64_t position ); extern int64_t mlt_sample_calculator_to_now( float fps, int frequency, int64_t position ); extern const char * mlt_image_format_name( mlt_image_format format ); +extern int mlt_image_format_size( mlt_image_format format, int width, int height, int *bpp ); extern const char * mlt_audio_format_name( mlt_audio_format format ); +extern int mlt_audio_format_size( mlt_audio_format format, int samples, int channels ); extern void mlt_frame_write_ppm( mlt_frame frame ); /** This macro scales RGB into the YUV gamut - y is scaled by 219/255 and uv by 224/255. */ diff -Nru mlt-0.6.2/src/framework/mlt_geometry.c mlt-0.7.2/src/framework/mlt_geometry.c --- mlt-0.6.2/src/framework/mlt_geometry.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_geometry.c 2011-05-02 05:59:12.000000000 +0000 @@ -47,23 +47,23 @@ // Create a new geometry structure mlt_geometry mlt_geometry_init( ) { - mlt_geometry this = calloc( 1, sizeof( struct mlt_geometry_s ) ); - if ( this != NULL ) + mlt_geometry self = calloc( 1, sizeof( struct mlt_geometry_s ) ); + if ( self != NULL ) { - this->local = calloc( 1, sizeof( geometry_s ) ); - if ( this->local != NULL ) + self->local = calloc( 1, sizeof( geometry_s ) ); + if ( self->local != NULL ) { - geometry self = this->local; - self->nw = 720; - self->nh = 576; + geometry g = self->local; + g->nw = 720; + g->nh = 576; } else { - free( this ); - this = NULL; + free( self ); + self = NULL; } } - return this; + return self; } /** A linear step @@ -75,17 +75,17 @@ return start + position * o; } -static void mlt_geometry_virtual_refresh( mlt_geometry this ) +static void mlt_geometry_virtual_refresh( mlt_geometry self ) { - geometry self = this->local; + geometry g = self->local; // Parse of all items to ensure unspecified keys are calculated correctly - if ( self->item != NULL ) + if ( g->item != NULL ) { int i = 0; for ( i = 0; i < 5; i ++ ) { - geometry_item current = self->item; + geometry_item current = g->item; while( current != NULL ) { int fixed = current->data.f[ i ]; @@ -150,23 +150,23 @@ } } -static int mlt_geometry_drop( mlt_geometry this, geometry_item item ) +static int mlt_geometry_drop( mlt_geometry self, geometry_item item ) { - geometry self = this->local; + geometry g = self->local; - if ( item == self->item ) + if ( item == g->item ) { - self->item = item->next; - if ( self->item != NULL ) - self->item->prev = NULL; + g->item = item->next; + if ( g->item != NULL ) + g->item->prev = NULL; // To ensure correct seeding, ensure all values are fixed - if ( self->item != NULL ) + if ( g->item != NULL ) { - self->item->data.f[0] = 1; - self->item->data.f[1] = 1; - self->item->data.f[2] = 1; - self->item->data.f[3] = 1; - self->item->data.f[4] = 1; + g->item->data.f[0] = 1; + g->item->data.f[1] = 1; + g->item->data.f[2] = 1; + g->item->data.f[3] = 1; + g->item->data.f[4] = 1; } } else if ( item->next != NULL && item->prev != NULL ) @@ -188,19 +188,19 @@ return 0; } -static void mlt_geometry_clean( mlt_geometry this ) +static void mlt_geometry_clean( mlt_geometry self ) { - geometry self = this->local; - free( self->data ); - self->data = NULL; - while( self->item ) - mlt_geometry_drop( this, self->item ); + geometry g = self->local; + free( g->data ); + g->data = NULL; + while( g->item ) + mlt_geometry_drop( self, g->item ); } // Parse the geometry specification for a given length and normalised width/height (-1 for default) // data is constructed as: [frame=]X,Y:WxH[:mix][;[frame=]X,Y:WxH[:mix]]* // and X, Y, W and H can have trailing % chars to indicate percentage of normalised size -int mlt_geometry_parse( mlt_geometry this, char *data, int length, int nw, int nh ) +int mlt_geometry_parse( mlt_geometry self, char *data, int length, int nw, int nh ) { int i = 0; @@ -208,20 +208,20 @@ mlt_tokeniser tokens = mlt_tokeniser_init( ); // Get the local/private structure - geometry self = this->local; + geometry g = self->local; // Clean the existing geometry - mlt_geometry_clean( this ); + mlt_geometry_clean( self ); // Update the info on the data if ( length != -1 ) - self->length = length; + g->length = length; if ( nw != -1 ) - self->nw = nw; + g->nw = nw; if ( nh != -1 ) - self->nh = nh; + g->nh = nh; if ( data != NULL ) - self->data = strdup( data ); + g->data = strdup( data ); // Tokenise if ( data != NULL ) @@ -237,10 +237,10 @@ memset( &item, 0, sizeof( struct mlt_geometry_item_s ) ); // Now parse the item - mlt_geometry_parse_item( this, &item, value ); + mlt_geometry_parse_item( self, &item, value ); // Now insert into place - mlt_geometry_insert( this, &item ); + mlt_geometry_insert( self, &item ); } // Remove the tokeniser @@ -251,42 +251,42 @@ } // Conditionally refresh in case of a change -int mlt_geometry_refresh( mlt_geometry this, char *data, int length, int nw, int nh ) +int mlt_geometry_refresh( mlt_geometry self, char *data, int length, int nw, int nh ) { - geometry self = this->local; - int changed = ( length != -1 && length != self->length ); - changed = changed || ( nw != -1 && nw != self->nw ); - changed = changed || ( nh != -1 && nh != self->nh ); - changed = changed || ( data != NULL && ( self->data == NULL || strcmp( data, self->data ) ) ); + geometry g = self->local; + int changed = ( length != -1 && length != g->length ); + changed = changed || ( nw != -1 && nw != g->nw ); + changed = changed || ( nh != -1 && nh != g->nh ); + changed = changed || ( data != NULL && ( g->data == NULL || strcmp( data, g->data ) ) ); if ( changed ) - return mlt_geometry_parse( this, data, length, nw, nh ); + return mlt_geometry_parse( self, data, length, nw, nh ); return -1; } -int mlt_geometry_get_length( mlt_geometry this ) +int mlt_geometry_get_length( mlt_geometry self ) { // Get the local/private structure - geometry self = this->local; + geometry g = self->local; // return the length - return self->length; + return g->length; } -void mlt_geometry_set_length( mlt_geometry this, int length ) +void mlt_geometry_set_length( mlt_geometry self, int length ) { // Get the local/private structure - geometry self = this->local; + geometry g = self->local; // set the length - self->length = length; + g->length = length; } -int mlt_geometry_parse_item( mlt_geometry this, mlt_geometry_item item, char *value ) +int mlt_geometry_parse_item( mlt_geometry self, mlt_geometry_item item, char *value ) { int ret = 0; // Get the local/private structure - geometry self = this->local; + geometry g = self->local; if ( value != NULL && strcmp( value, "" ) ) { @@ -299,7 +299,7 @@ { temp = atof( value ); if ( temp > -1 && temp < 1 ) - item->frame = temp * self->length; + item->frame = temp * g->length; else item->frame = temp; value = p + 1; @@ -307,11 +307,11 @@ // Special case - frame < 0 if ( item->frame < 0 ) - item->frame += self->length; + item->frame += g->length; - // Obtain the current value at this position - this allows new + // Obtain the current value at this position - self allows new // frames to be created which don't specify all values - mlt_geometry_fetch( this, item, item->frame ); + mlt_geometry_fetch( self, item, item->frame ); // Special case - when an empty string is specified, all values are fixed // TODO: Check if this is logical - it's convenient, but it's also odd... @@ -337,9 +337,9 @@ if ( *p == '%' ) { if ( count == 0 || count == 2 ) - temp *= self->nw / 100.0; + temp *= g->nw / 100.0; else if ( count == 1 || count == 3 ) - temp *= self->nh / 100.0; + temp *= g->nh / 100.0; p ++; } @@ -382,13 +382,13 @@ } // Fetch a geometry item for an absolute position -int mlt_geometry_fetch( mlt_geometry this, mlt_geometry_item item, float position ) +int mlt_geometry_fetch( mlt_geometry self, mlt_geometry_item item, float position ) { // Get the local geometry - geometry self = this->local; + geometry g = self->local; // Need to find the nearest key to the position specifed - geometry_item key = self->item; + geometry_item key = g->item; // Iterate through the keys until we reach last or have while( key != NULL && key->next != NULL && position >= key->next->data.frame ) @@ -446,21 +446,21 @@ } // Specify a geometry item at an absolute position -int mlt_geometry_insert( mlt_geometry this, mlt_geometry_item item ) +int mlt_geometry_insert( mlt_geometry self, mlt_geometry_item item ) { // Get the local/private geometry structure - geometry self = this->local; + geometry g = self->local; - // Create a new local item (this may be removed if a key already exists at this position) - geometry_item new = calloc( 1, sizeof( struct geometry_item_s ) ); - memcpy( &new->data, item, sizeof( struct mlt_geometry_item_s ) ); - new->data.key = 1; + // Create a new local item (this may be removed if a key already exists at self position) + geometry_item gi = calloc( 1, sizeof( struct geometry_item_s ) ); + memcpy( &gi->data, item, sizeof( struct mlt_geometry_item_s ) ); + gi->data.key = 1; // Determine if we need to insert or append to the list, or if it's a new list - if ( self->item != NULL ) + if ( g->item != NULL ) { // Get the first item - geometry_item place = self->item; + geometry_item place = g->item; // Locate an existing nearby item while ( place->next != NULL && item->frame > place->data.frame ) @@ -468,79 +468,79 @@ if ( item->frame < place->data.frame ) { - if ( place == self->item ) - self->item = new; + if ( place == g->item ) + g->item = gi; if ( place->prev ) - place->prev->next = new; - new->next = place; - new->prev = place->prev; - place->prev = new; + place->prev->next = gi; + gi->next = place; + gi->prev = place->prev; + place->prev = gi; } else if ( item->frame > place->data.frame ) { if ( place->next ) - place->next->prev = new; - new->next = place->next; - new->prev = place; - place->next = new; + place->next->prev = gi; + gi->next = place->next; + gi->prev = place; + place->next = gi; } else { - memcpy( &place->data, &new->data, sizeof( struct mlt_geometry_item_s ) ); - free( new ); + memcpy( &place->data, &gi->data, sizeof( struct mlt_geometry_item_s ) ); + free( gi ); } } else { // Set the first item - self->item = new; + g->item = gi; // To ensure correct seeding, ensure all values are fixed - self->item->data.f[0] = 1; - self->item->data.f[1] = 1; - self->item->data.f[2] = 1; - self->item->data.f[3] = 1; - self->item->data.f[4] = 1; + g->item->data.f[0] = 1; + g->item->data.f[1] = 1; + g->item->data.f[2] = 1; + g->item->data.f[3] = 1; + g->item->data.f[4] = 1; } // Refresh all geometries - mlt_geometry_virtual_refresh( this ); + mlt_geometry_virtual_refresh( self ); // TODO: Error checking return 0; } // Remove the key at the specified position -int mlt_geometry_remove( mlt_geometry this, int position ) +int mlt_geometry_remove( mlt_geometry self, int position ) { int ret = 1; // Get the local/private geometry structure - geometry self = this->local; + geometry g = self->local; // Get the first item - geometry_item place = self->item; + geometry_item place = g->item; while( place != NULL && position != place->data.frame ) place = place->next; if ( place != NULL && position == place->data.frame ) - ret = mlt_geometry_drop( this, place ); + ret = mlt_geometry_drop( self, place ); // Refresh all geometries - mlt_geometry_virtual_refresh( this ); + mlt_geometry_virtual_refresh( self ); return ret; } // Get the key at the position or the next following -int mlt_geometry_next_key( mlt_geometry this, mlt_geometry_item item, int position ) +int mlt_geometry_next_key( mlt_geometry self, mlt_geometry_item item, int position ) { // Get the local/private geometry structure - geometry self = this->local; + geometry g = self->local; // Get the first item - geometry_item place = self->item; + geometry_item place = g->item; while( place != NULL && position > place->data.frame ) place = place->next; @@ -552,13 +552,13 @@ } // Get the key at the position or the previous key -int mlt_geometry_prev_key( mlt_geometry this, mlt_geometry_item item, int position ) +int mlt_geometry_prev_key( mlt_geometry self, mlt_geometry_item item, int position ) { // Get the local/private geometry structure - geometry self = this->local; + geometry g = self->local; // Get the first item - geometry_item place = self->item; + geometry_item place = g->item; while( place != NULL && place->next != NULL && position >= place->next->data.frame ) place = place->next; @@ -569,9 +569,9 @@ return place == NULL; } -char *mlt_geometry_serialise_cut( mlt_geometry this, int in, int out ) +char *mlt_geometry_serialise_cut( mlt_geometry self, int in, int out ) { - geometry self = this->local; + geometry g = self->local; struct mlt_geometry_item_s item; char *ret = malloc( 1000 ); int used = 0; @@ -580,7 +580,7 @@ if ( in == -1 ) in = 0; if ( out == -1 ) - out = mlt_geometry_get_length( this ); + out = mlt_geometry_get_length( self ); if ( ret != NULL ) { @@ -597,12 +597,12 @@ // If it's the first frame, then it's not necessarily a key if ( item.frame == in ) { - if ( mlt_geometry_fetch( this, &item, item.frame ) ) + if ( mlt_geometry_fetch( self, &item, item.frame ) ) break; // If the first key is larger than the current position // then do nothing here - if ( self->item->data.frame > item.frame ) + if ( g->item->data.frame > item.frame ) { item.frame ++; continue; @@ -618,12 +618,12 @@ // Typically, we move from key to key else if ( item.frame < out ) { - if ( mlt_geometry_next_key( this, &item, item.frame ) ) + if ( mlt_geometry_next_key( self, &item, item.frame ) ) break; // Special case - crop at the out point if ( item.frame > out ) - mlt_geometry_fetch( this, &item, out ); + mlt_geometry_fetch( self, &item, out ); } // We've handled the last key else @@ -673,26 +673,26 @@ } // Serialise the current geometry -char *mlt_geometry_serialise( mlt_geometry this ) +char *mlt_geometry_serialise( mlt_geometry self ) { - geometry self = this->local; - char *ret = mlt_geometry_serialise_cut( this, 0, self->length ); + geometry g = self->local; + char *ret = mlt_geometry_serialise_cut( self, 0, g->length ); if ( ret ) { - free( self->data ); - self->data = ret; + free( g->data ); + g->data = ret; } return ret; } // Close the geometry -void mlt_geometry_close( mlt_geometry this ) +void mlt_geometry_close( mlt_geometry self ) { - if ( this != NULL ) + if ( self != NULL ) { - mlt_geometry_clean( this ); - free( this->local ); - free( this ); + mlt_geometry_clean( self ); + free( self->local ); + free( self ); } } diff -Nru mlt-0.6.2/src/framework/mlt_multitrack.c mlt-0.7.2/src/framework/mlt_multitrack.c --- mlt-0.6.2/src/framework/mlt_multitrack.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_multitrack.c 2011-05-02 05:59:12.000000000 +0000 @@ -43,16 +43,16 @@ mlt_multitrack mlt_multitrack_init( ) { // Allocate the multitrack object - mlt_multitrack this = calloc( sizeof( struct mlt_multitrack_s ), 1 ); + mlt_multitrack self = calloc( sizeof( struct mlt_multitrack_s ), 1 ); - if ( this != NULL ) + if ( self != NULL ) { - mlt_producer producer = &this->parent; - if ( mlt_producer_init( producer, this ) == 0 ) + mlt_producer producer = &self->parent; + if ( mlt_producer_init( producer, self ) == 0 ) { - mlt_properties properties = MLT_MULTITRACK_PROPERTIES( this ); + mlt_properties properties = MLT_MULTITRACK_PROPERTIES( self ); producer->get_frame = producer_get_frame; - mlt_properties_set_data( properties, "multitrack", this, 0, NULL, NULL ); + mlt_properties_set_data( properties, "multitrack", self, 0, NULL, NULL ); mlt_properties_set( properties, "log_id", "multitrack" ); mlt_properties_set( properties, "resource", "" ); mlt_properties_set_int( properties, "in", 0 ); @@ -62,81 +62,81 @@ } else { - free( this ); - this = NULL; + free( self ); + self = NULL; } } - return this; + return self; } /** Get the producer associated to this multitrack. * * \public \memberof mlt_multitrack_s - * \param this a multitrack + * \param self a multitrack * \return the producer object * \see MLT_MULTITRACK_PRODUCER */ -mlt_producer mlt_multitrack_producer( mlt_multitrack this ) +mlt_producer mlt_multitrack_producer( mlt_multitrack self ) { - return this != NULL ? &this->parent : NULL; + return self != NULL ? &self->parent : NULL; } /** Get the service associated this multitrack. * * \public \memberof mlt_multitrack_s - * \param this a multitrack + * \param self a multitrack * \return the service object * \see MLT_MULTITRACK_SERVICE */ -mlt_service mlt_multitrack_service( mlt_multitrack this ) +mlt_service mlt_multitrack_service( mlt_multitrack self ) { - return MLT_MULTITRACK_SERVICE( this ); + return MLT_MULTITRACK_SERVICE( self ); } /** Get the properties associated this multitrack. * * \public \memberof mlt_multitrack_s - * \param this a multitrack + * \param self a multitrack * \return the multitrack's property list * \see MLT_MULTITRACK_PROPERTIES */ -mlt_properties mlt_multitrack_properties( mlt_multitrack this ) +mlt_properties mlt_multitrack_properties( mlt_multitrack self ) { - return MLT_MULTITRACK_PROPERTIES( this ); + return MLT_MULTITRACK_PROPERTIES( self ); } /** Initialize position related information. * * \public \memberof mlt_multitrack_s - * \param this a multitrack + * \param self a multitrack */ -void mlt_multitrack_refresh( mlt_multitrack this ) +void mlt_multitrack_refresh( mlt_multitrack self ) { int i = 0; // Obtain the properties of this multitrack - mlt_properties properties = MLT_MULTITRACK_PROPERTIES( this ); + mlt_properties properties = MLT_MULTITRACK_PROPERTIES( self ); // We need to ensure that the multitrack reports the longest track as its length mlt_position length = 0; // Obtain stats on all connected services - for ( i = 0; i < this->count; i ++ ) + for ( i = 0; i < self->count; i ++ ) { // Get the producer from this index - mlt_track track = this->list[ i ]; + mlt_track track = self->list[ i ]; mlt_producer producer = track->producer; // If it's allocated then, update our stats if ( producer != NULL ) { // If we have more than 1 track, we must be in continue mode - if ( this->count > 1 ) + if ( self->count > 1 ) mlt_properties_set( MLT_PRODUCER_PROPERTIES( producer ), "eof", "continue" ); // Determine the longest length @@ -156,12 +156,12 @@ * * \private \memberof mlt_multitrack_s * \param producer a producer - * \param this a multitrack + * \param self a multitrack */ -static void mlt_multitrack_listener( mlt_producer producer, mlt_multitrack this ) +static void mlt_multitrack_listener( mlt_producer producer, mlt_multitrack self ) { - mlt_multitrack_refresh( this ); + mlt_multitrack_refresh( self ); } /** Connect a producer to a given track. @@ -170,52 +170,52 @@ * of playlist in clip point determination below. * * \public \memberof mlt_multitrack_s - * \param this a multitrack + * \param self a multitrack * \param producer the producer to connect to the multitrack producer * \param track the 0-based index of the track on which to connect the multitrack * \return true on error */ -int mlt_multitrack_connect( mlt_multitrack this, mlt_producer producer, int track ) +int mlt_multitrack_connect( mlt_multitrack self, mlt_producer producer, int track ) { // Connect to the producer to ourselves at the specified track - int result = mlt_service_connect_producer( MLT_MULTITRACK_SERVICE( this ), MLT_PRODUCER_SERVICE( producer ), track ); + int result = mlt_service_connect_producer( MLT_MULTITRACK_SERVICE( self ), MLT_PRODUCER_SERVICE( producer ), track ); if ( result == 0 ) { // Resize the producer list if need be - if ( track >= this->size ) + if ( track >= self->size ) { int i; - this->list = realloc( this->list, ( track + 10 ) * sizeof( mlt_track ) ); - for ( i = this->size; i < track + 10; i ++ ) - this->list[ i ] = NULL; - this->size = track + 10; + self->list = realloc( self->list, ( track + 10 ) * sizeof( mlt_track ) ); + for ( i = self->size; i < track + 10; i ++ ) + self->list[ i ] = NULL; + self->size = track + 10; } - if ( this->list[ track ] != NULL ) + if ( self->list[ track ] != NULL ) { - mlt_event_close( this->list[ track ]->event ); - mlt_producer_close( this->list[ track ]->producer ); + mlt_event_close( self->list[ track ]->event ); + mlt_producer_close( self->list[ track ]->producer ); } else { - this->list[ track ] = malloc( sizeof( struct mlt_track_s ) ); + self->list[ track ] = malloc( sizeof( struct mlt_track_s ) ); } // Assign the track in our list here - this->list[ track ]->producer = producer; - this->list[ track ]->event = mlt_events_listen( MLT_PRODUCER_PROPERTIES( producer ), this, + self->list[ track ]->producer = producer; + self->list[ track ]->event = mlt_events_listen( MLT_PRODUCER_PROPERTIES( producer ), self, "producer-changed", ( mlt_listener )mlt_multitrack_listener ); mlt_properties_inc_ref( MLT_PRODUCER_PROPERTIES( producer ) ); - mlt_event_inc_ref( this->list[ track ]->event ); + mlt_event_inc_ref( self->list[ track ]->event ); // Increment the track count if need be - if ( track >= this->count ) - this->count = track + 1; + if ( track >= self->count ) + self->count = track + 1; // Refresh our stats - mlt_multitrack_refresh( this ); + mlt_multitrack_refresh( self ); } return result; @@ -224,29 +224,29 @@ /** Get the number of tracks. * * \public \memberof mlt_multitrack_s - * \param this a multitrack + * \param self a multitrack * \return the number of tracks */ -int mlt_multitrack_count( mlt_multitrack this ) +int mlt_multitrack_count( mlt_multitrack self ) { - return this->count; + return self->count; } /** Get an individual track as a producer. * * \public \memberof mlt_multitrack_s - * \param this a multitrack + * \param self a multitrack * \param track the 0-based index of the producer to get * \return the producer or NULL if not valid */ -mlt_producer mlt_multitrack_track( mlt_multitrack this, int track ) +mlt_producer mlt_multitrack_track( mlt_multitrack self, int track ) { mlt_producer producer = NULL; - if ( this->list != NULL && track < this->count ) - producer = this->list[ track ]->producer; + if ( self->list != NULL && track < self->count ) + producer = self->list[ track ]->producer; return producer; } @@ -306,13 +306,13 @@ * * * \public \memberof mlt_multitrack_s - * \param this a multitrack + * \param self a multitrack * \param whence from where to extract * \param index the 0-based index of which clip to extract * \return the position of clip \p index relative to \p whence */ -mlt_position mlt_multitrack_clip( mlt_multitrack this, mlt_whence whence, int index ) +mlt_position mlt_multitrack_clip( mlt_multitrack self, mlt_whence whence, int index ) { mlt_position position = 0; int i = 0; @@ -320,10 +320,10 @@ mlt_position *map = malloc( 1000 * sizeof( mlt_position ) ); int count = 0; - for ( i = 0; i < this->count; i ++ ) + for ( i = 0; i < self->count; i ++ ) { // Get the producer for this track - mlt_producer producer = this->list[ i ]->producer; + mlt_producer producer = self->list[ i ]->producer; // If it's assigned and not a hidden track if ( producer != NULL ) @@ -363,7 +363,7 @@ break; case mlt_whence_relative_current: - position = mlt_producer_position( MLT_MULTITRACK_PRODUCER( this ) ); + position = mlt_producer_position( MLT_MULTITRACK_PRODUCER( self ) ); for ( i = 0; i < count - 2; i ++ ) if ( position >= map[ i ] && position < map[ i + 1 ] ) break; @@ -426,13 +426,13 @@ static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int index ) { // Get the mutiltrack object - mlt_multitrack this = parent->child; + mlt_multitrack self = parent->child; // Check if we have a track for this index - if ( index < this->count && this->list[ index ] != NULL ) + if ( index < self->count && self->list[ index ] != NULL ) { // Get the producer for this track - mlt_producer producer = this->list[ index ]->producer; + mlt_producer producer = self->list[ index ]->producer; // Get the track hide property int hide = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( mlt_producer_cut_parent( producer ) ), "hide" ); @@ -467,7 +467,7 @@ mlt_frame_set_position( *frame, mlt_producer_position( parent ) ); // Move on to the next frame - if ( index >= this->count ) + if ( index >= self->count ) { // Let tractor know if we've reached the end mlt_properties_set_int( MLT_FRAME_PROPERTIES( *frame ), "last_track", 1 ); @@ -483,32 +483,32 @@ /** Close this instance and free its resources. * * \public \memberof mlt_multitrack_s - * \param this a multitrack + * \param self a multitrack */ -void mlt_multitrack_close( mlt_multitrack this ) +void mlt_multitrack_close( mlt_multitrack self ) { - if ( this != NULL && mlt_properties_dec_ref( MLT_MULTITRACK_PROPERTIES( this ) ) <= 0 ) + if ( self != NULL && mlt_properties_dec_ref( MLT_MULTITRACK_PROPERTIES( self ) ) <= 0 ) { int i = 0; - for ( i = 0; i < this->count; i ++ ) + for ( i = 0; i < self->count; i ++ ) { - if ( this->list[ i ] != NULL ) + if ( self->list[ i ] != NULL ) { - mlt_event_close( this->list[ i ]->event ); - mlt_producer_close( this->list[ i ]->producer ); - free( this->list[ i ] ); + mlt_event_close( self->list[ i ]->event ); + mlt_producer_close( self->list[ i ]->producer ); + free( self->list[ i ] ); } } // Close the producer - this->parent.close = NULL; - mlt_producer_close( &this->parent ); + self->parent.close = NULL; + mlt_producer_close( &self->parent ); // Free the list - free( this->list ); + free( self->list ); // Free the object - free( this ); + free( self ); } } diff -Nru mlt-0.6.2/src/framework/mlt_parser.c mlt-0.7.2/src/framework/mlt_parser.c --- mlt-0.6.2/src/framework/mlt_parser.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_parser.c 2011-05-02 05:59:12.000000000 +0000 @@ -24,206 +24,206 @@ #include "mlt.h" #include -static int on_invalid( mlt_parser this, mlt_service object ) +static int on_invalid( mlt_parser self, mlt_service object ) { return 0; } -static int on_unknown( mlt_parser this, mlt_service object ) +static int on_unknown( mlt_parser self, mlt_service object ) { return 0; } -static int on_start_producer( mlt_parser this, mlt_producer object ) +static int on_start_producer( mlt_parser self, mlt_producer object ) { return 0; } -static int on_end_producer( mlt_parser this, mlt_producer object ) +static int on_end_producer( mlt_parser self, mlt_producer object ) { return 0; } -static int on_start_playlist( mlt_parser this, mlt_playlist object ) +static int on_start_playlist( mlt_parser self, mlt_playlist object ) { return 0; } -static int on_end_playlist( mlt_parser this, mlt_playlist object ) +static int on_end_playlist( mlt_parser self, mlt_playlist object ) { return 0; } -static int on_start_tractor( mlt_parser this, mlt_tractor object ) +static int on_start_tractor( mlt_parser self, mlt_tractor object ) { return 0; } -static int on_end_tractor( mlt_parser this, mlt_tractor object ) +static int on_end_tractor( mlt_parser self, mlt_tractor object ) { return 0; } -static int on_start_multitrack( mlt_parser this, mlt_multitrack object ) +static int on_start_multitrack( mlt_parser self, mlt_multitrack object ) { return 0; } -static int on_end_multitrack( mlt_parser this, mlt_multitrack object ) +static int on_end_multitrack( mlt_parser self, mlt_multitrack object ) { return 0; } -static int on_start_track( mlt_parser this ) +static int on_start_track( mlt_parser self ) { return 0; } -static int on_end_track( mlt_parser this ) +static int on_end_track( mlt_parser self ) { return 0; } -static int on_start_filter( mlt_parser this, mlt_filter object ) +static int on_start_filter( mlt_parser self, mlt_filter object ) { return 0; } -static int on_end_filter( mlt_parser this, mlt_filter object ) +static int on_end_filter( mlt_parser self, mlt_filter object ) { return 0; } -static int on_start_transition( mlt_parser this, mlt_transition object ) +static int on_start_transition( mlt_parser self, mlt_transition object ) { return 0; } -static int on_end_transition( mlt_parser this, mlt_transition object ) +static int on_end_transition( mlt_parser self, mlt_transition object ) { return 0; } mlt_parser mlt_parser_new( ) { - mlt_parser this = calloc( 1, sizeof( struct mlt_parser_s ) ); - if ( this != NULL && mlt_properties_init( &this->parent, this ) == 0 ) + mlt_parser self = calloc( 1, sizeof( struct mlt_parser_s ) ); + if ( self != NULL && mlt_properties_init( &self->parent, self ) == 0 ) { - this->on_invalid = on_invalid; - this->on_unknown = on_unknown; - this->on_start_producer = on_start_producer; - this->on_end_producer = on_end_producer; - this->on_start_playlist = on_start_playlist; - this->on_end_playlist = on_end_playlist; - this->on_start_tractor = on_start_tractor; - this->on_end_tractor = on_end_tractor; - this->on_start_multitrack = on_start_multitrack; - this->on_end_multitrack = on_end_multitrack; - this->on_start_track = on_start_track; - this->on_end_track = on_end_track; - this->on_start_filter = on_start_filter; - this->on_end_filter = on_end_filter; - this->on_start_transition = on_start_transition; - this->on_end_transition = on_end_transition; + self->on_invalid = on_invalid; + self->on_unknown = on_unknown; + self->on_start_producer = on_start_producer; + self->on_end_producer = on_end_producer; + self->on_start_playlist = on_start_playlist; + self->on_end_playlist = on_end_playlist; + self->on_start_tractor = on_start_tractor; + self->on_end_tractor = on_end_tractor; + self->on_start_multitrack = on_start_multitrack; + self->on_end_multitrack = on_end_multitrack; + self->on_start_track = on_start_track; + self->on_end_track = on_end_track; + self->on_start_filter = on_start_filter; + self->on_end_filter = on_end_filter; + self->on_start_transition = on_start_transition; + self->on_end_transition = on_end_transition; } - return this; + return self; } -mlt_properties mlt_parser_properties( mlt_parser this ) +mlt_properties mlt_parser_properties( mlt_parser self ) { - return &this->parent; + return &self->parent; } -int mlt_parser_start( mlt_parser this, mlt_service object ) +int mlt_parser_start( mlt_parser self, mlt_service object ) { int error = 0; mlt_service_type type = mlt_service_identify( object ); switch( type ) { case invalid_type: - error = this->on_invalid( this, object ); + error = self->on_invalid( self, object ); break; case unknown_type: - error = this->on_unknown( this, object ); + error = self->on_unknown( self, object ); break; case producer_type: if ( mlt_producer_is_cut( ( mlt_producer )object ) ) - error = mlt_parser_start( this, ( mlt_service )mlt_producer_cut_parent( ( mlt_producer )object ) ); - error = this->on_start_producer( this, ( mlt_producer )object ); + error = mlt_parser_start( self, ( mlt_service )mlt_producer_cut_parent( ( mlt_producer )object ) ); + error = self->on_start_producer( self, ( mlt_producer )object ); if ( error == 0 ) { int i = 0; while ( error == 0 && mlt_producer_filter( ( mlt_producer )object, i ) != NULL ) - error = mlt_parser_start( this, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); + error = mlt_parser_start( self, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); } - error = this->on_end_producer( this, ( mlt_producer )object ); + error = self->on_end_producer( self, ( mlt_producer )object ); break; case playlist_type: - error = this->on_start_playlist( this, ( mlt_playlist )object ); + error = self->on_start_playlist( self, ( mlt_playlist )object ); if ( error == 0 ) { int i = 0; while ( error == 0 && i < mlt_playlist_count( ( mlt_playlist )object ) ) - mlt_parser_start( this, ( mlt_service )mlt_playlist_get_clip( ( mlt_playlist )object, i ++ ) ); + mlt_parser_start( self, ( mlt_service )mlt_playlist_get_clip( ( mlt_playlist )object, i ++ ) ); i = 0; while ( error == 0 && mlt_producer_filter( ( mlt_producer )object, i ) != NULL ) - error = mlt_parser_start( this, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); + error = mlt_parser_start( self, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); } - error = this->on_end_playlist( this, ( mlt_playlist )object ); + error = self->on_end_playlist( self, ( mlt_playlist )object ); break; case tractor_type: - error = this->on_start_tractor( this, ( mlt_tractor )object ); + error = self->on_start_tractor( self, ( mlt_tractor )object ); if ( error == 0 ) { int i = 0; mlt_service next = mlt_service_producer( object ); - mlt_parser_start( this, ( mlt_service )mlt_tractor_multitrack( ( mlt_tractor )object ) ); + mlt_parser_start( self, ( mlt_service )mlt_tractor_multitrack( ( mlt_tractor )object ) ); while ( next != ( mlt_service )mlt_tractor_multitrack( ( mlt_tractor )object ) ) { - mlt_parser_start( this, next ); + mlt_parser_start( self, next ); next = mlt_service_producer( next ); } while ( error == 0 && mlt_producer_filter( ( mlt_producer )object, i ) != NULL ) - error = mlt_parser_start( this, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); + error = mlt_parser_start( self, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); } - error = this->on_end_tractor( this, ( mlt_tractor )object ); + error = self->on_end_tractor( self, ( mlt_tractor )object ); break; case multitrack_type: - error = this->on_start_multitrack( this, ( mlt_multitrack )object ); + error = self->on_start_multitrack( self, ( mlt_multitrack )object ); if ( error == 0 ) { int i = 0; while ( i < mlt_multitrack_count( ( mlt_multitrack )object ) ) { - this->on_start_track( this ); - mlt_parser_start( this, ( mlt_service )mlt_multitrack_track( ( mlt_multitrack )object , i ++ ) ); - this->on_end_track( this ); + self->on_start_track( self ); + mlt_parser_start( self, ( mlt_service )mlt_multitrack_track( ( mlt_multitrack )object , i ++ ) ); + self->on_end_track( self ); } i = 0; while ( error == 0 && mlt_producer_filter( ( mlt_producer )object, i ) != NULL ) - error = mlt_parser_start( this, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); + error = mlt_parser_start( self, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); } - error = this->on_end_multitrack( this, ( mlt_multitrack )object ); + error = self->on_end_multitrack( self, ( mlt_multitrack )object ); break; case filter_type: - error = this->on_start_filter( this, ( mlt_filter )object ); + error = self->on_start_filter( self, ( mlt_filter )object ); if ( error == 0 ) { int i = 0; while ( error == 0 && mlt_producer_filter( ( mlt_producer )object, i ) != NULL ) - error = mlt_parser_start( this, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); + error = mlt_parser_start( self, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); } - error = this->on_end_filter( this, ( mlt_filter )object ); + error = self->on_end_filter( self, ( mlt_filter )object ); break; case transition_type: - error = this->on_start_transition( this, ( mlt_transition )object ); + error = self->on_start_transition( self, ( mlt_transition )object ); if ( error == 0 ) { int i = 0; while ( error == 0 && mlt_producer_filter( ( mlt_producer )object, i ) != NULL ) - error = mlt_parser_start( this, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); + error = mlt_parser_start( self, ( mlt_service )mlt_producer_filter( ( mlt_producer )object, i ++ ) ); } - error = this->on_end_transition( this, ( mlt_transition )object ); + error = self->on_end_transition( self, ( mlt_transition )object ); break; case field_type: break; @@ -233,12 +233,12 @@ return error; } -void mlt_parser_close( mlt_parser this ) +void mlt_parser_close( mlt_parser self ) { - if ( this != NULL ) + if ( self != NULL ) { - mlt_properties_close( &this->parent ); - free( this ); + mlt_properties_close( &self->parent ); + free( self ); } } diff -Nru mlt-0.6.2/src/framework/mlt_playlist.c mlt-0.7.2/src/framework/mlt_playlist.c --- mlt-0.6.2/src/framework/mlt_playlist.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_playlist.c 2011-05-02 05:59:12.000000000 +0000 @@ -51,8 +51,8 @@ */ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ); -static int mlt_playlist_unmix( mlt_playlist this, int clip ); -static int mlt_playlist_resize_mix( mlt_playlist this, int clip, int in, int out ); +static int mlt_playlist_unmix( mlt_playlist self, int clip ); +static int mlt_playlist_resize_mix( mlt_playlist self, int clip, int in, int out ); /** Construct a playlist. * @@ -64,133 +64,133 @@ mlt_playlist mlt_playlist_init( ) { - mlt_playlist this = calloc( sizeof( struct mlt_playlist_s ), 1 ); - if ( this != NULL ) + mlt_playlist self = calloc( sizeof( struct mlt_playlist_s ), 1 ); + if ( self != NULL ) { - mlt_producer producer = &this->parent; + mlt_producer producer = &self->parent; // Construct the producer - mlt_producer_init( producer, this ); + mlt_producer_init( producer, self ); // Override the producer get_frame producer->get_frame = producer_get_frame; // Define the destructor producer->close = ( mlt_destructor )mlt_playlist_close; - producer->close_object = this; + producer->close_object = self; // Initialise blank - mlt_producer_init( &this->blank, NULL ); - mlt_properties_set( MLT_PRODUCER_PROPERTIES( &this->blank ), "mlt_service", "blank" ); - mlt_properties_set( MLT_PRODUCER_PROPERTIES( &this->blank ), "resource", "blank" ); + mlt_producer_init( &self->blank, NULL ); + mlt_properties_set( MLT_PRODUCER_PROPERTIES( &self->blank ), "mlt_service", "blank" ); + mlt_properties_set( MLT_PRODUCER_PROPERTIES( &self->blank ), "resource", "blank" ); // Indicate that this producer is a playlist - mlt_properties_set_data( MLT_PLAYLIST_PROPERTIES( this ), "playlist", this, 0, NULL, NULL ); + mlt_properties_set_data( MLT_PLAYLIST_PROPERTIES( self ), "playlist", self, 0, NULL, NULL ); // Specify the eof condition - mlt_properties_set( MLT_PLAYLIST_PROPERTIES( this ), "eof", "pause" ); - mlt_properties_set( MLT_PLAYLIST_PROPERTIES( this ), "resource", "" ); - mlt_properties_set( MLT_PLAYLIST_PROPERTIES( this ), "mlt_type", "mlt_producer" ); - mlt_properties_set_position( MLT_PLAYLIST_PROPERTIES( this ), "in", 0 ); - mlt_properties_set_position( MLT_PLAYLIST_PROPERTIES( this ), "out", -1 ); - mlt_properties_set_position( MLT_PLAYLIST_PROPERTIES( this ), "length", 0 ); + mlt_properties_set( MLT_PLAYLIST_PROPERTIES( self ), "eof", "pause" ); + mlt_properties_set( MLT_PLAYLIST_PROPERTIES( self ), "resource", "" ); + mlt_properties_set( MLT_PLAYLIST_PROPERTIES( self ), "mlt_type", "mlt_producer" ); + mlt_properties_set_position( MLT_PLAYLIST_PROPERTIES( self ), "in", 0 ); + mlt_properties_set_position( MLT_PLAYLIST_PROPERTIES( self ), "out", -1 ); + mlt_properties_set_position( MLT_PLAYLIST_PROPERTIES( self ), "length", 0 ); - this->size = 10; - this->list = malloc( this->size * sizeof( playlist_entry * ) ); + self->size = 10; + self->list = malloc( self->size * sizeof( playlist_entry * ) ); } - return this; + return self; } /** Get the producer associated to this playlist. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \return the producer interface * \see MLT_PLAYLIST_PRODUCER */ -mlt_producer mlt_playlist_producer( mlt_playlist this ) +mlt_producer mlt_playlist_producer( mlt_playlist self ) { - return this != NULL ? &this->parent : NULL; + return self != NULL ? &self->parent : NULL; } /** Get the service associated to this playlist. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \return the service interface * \see MLT_PLAYLIST_SERVICE */ -mlt_service mlt_playlist_service( mlt_playlist this ) +mlt_service mlt_playlist_service( mlt_playlist self ) { - return MLT_PRODUCER_SERVICE( &this->parent ); + return MLT_PRODUCER_SERVICE( &self->parent ); } /** Get the properties associated to this playlist. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \return the playlist's properties list * \see MLT_PLAYLIST_PROPERTIES */ -mlt_properties mlt_playlist_properties( mlt_playlist this ) +mlt_properties mlt_playlist_properties( mlt_playlist self ) { - return MLT_PRODUCER_PROPERTIES( &this->parent ); + return MLT_PRODUCER_PROPERTIES( &self->parent ); } /** Refresh the playlist after a clip has been changed. * * \private \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \return false */ -static int mlt_playlist_virtual_refresh( mlt_playlist this ) +static int mlt_playlist_virtual_refresh( mlt_playlist self ) { // Obtain the properties - mlt_properties properties = MLT_PLAYLIST_PROPERTIES( this ); + mlt_properties properties = MLT_PLAYLIST_PROPERTIES( self ); int i = 0; mlt_position frame_count = 0; - for ( i = 0; i < this->count; i ++ ) + for ( i = 0; i < self->count; i ++ ) { // Get the producer - mlt_producer producer = this->list[ i ]->producer; + mlt_producer producer = self->list[ i ]->producer; if ( producer ) { - int current_length = mlt_producer_get_out( producer ) - mlt_producer_get_in( producer ) + 1; + int current_length = mlt_producer_get_playtime( producer ); // Check if the length of the producer has changed - if ( this->list[ i ]->frame_in != mlt_producer_get_in( producer ) || - this->list[ i ]->frame_out != mlt_producer_get_out( producer ) ) + if ( self->list[ i ]->frame_in != mlt_producer_get_in( producer ) || + self->list[ i ]->frame_out != mlt_producer_get_out( producer ) ) { // This clip should be removed... if ( current_length < 1 ) { - this->list[ i ]->frame_in = 0; - this->list[ i ]->frame_out = -1; - this->list[ i ]->frame_count = 0; + self->list[ i ]->frame_in = 0; + self->list[ i ]->frame_out = -1; + self->list[ i ]->frame_count = 0; } else { - this->list[ i ]->frame_in = mlt_producer_get_in( producer ); - this->list[ i ]->frame_out = mlt_producer_get_out( producer ); - this->list[ i ]->frame_count = current_length; + self->list[ i ]->frame_in = mlt_producer_get_in( producer ); + self->list[ i ]->frame_out = mlt_producer_get_out( producer ); + self->list[ i ]->frame_count = current_length; } // Update the producer_length - this->list[ i ]->producer_length = current_length; + self->list[ i ]->producer_length = current_length; } } // Calculate the frame_count - this->list[ i ]->frame_count = ( this->list[ i ]->frame_out - this->list[ i ]->frame_in + 1 ) * this->list[ i ]->repeat; + self->list[ i ]->frame_count = ( self->list[ i ]->frame_out - self->list[ i ]->frame_in + 1 ) * self->list[ i ]->repeat; - // Update the frame_count for this clip - frame_count += this->list[ i ]->frame_count; + // Update the frame_count for self clip + frame_count += self->list[ i ]->frame_count; } // Refresh all properties @@ -207,25 +207,25 @@ * Refreshes the playlist whenever an entry receives producer-changed. * \private \memberof mlt_playlist_s * \param producer a producer - * \param this a playlist + * \param self a playlist */ -static void mlt_playlist_listener( mlt_producer producer, mlt_playlist this ) +static void mlt_playlist_listener( mlt_producer producer, mlt_playlist self ) { - mlt_playlist_virtual_refresh( this ); + mlt_playlist_virtual_refresh( self ); } /** Append to the virtual playlist. * * \private \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param source a producer * \param in the producer's starting time * \param out the producer's ending time * \return true if there was an error */ -static int mlt_playlist_virtual_append( mlt_playlist this, mlt_producer source, mlt_position in, mlt_position out ) +static int mlt_playlist_virtual_append( mlt_playlist self, mlt_producer source, mlt_position in, mlt_position out ) { mlt_producer producer = NULL; mlt_properties properties = NULL; @@ -235,22 +235,22 @@ if ( mlt_producer_is_blank( source ) ) { // Make sure the blank is long enough to accomodate the length specified - if ( out - in + 1 > mlt_producer_get_length( &this->blank ) ) + if ( out - in + 1 > mlt_producer_get_length( &self->blank ) ) { - mlt_properties blank_props = MLT_PRODUCER_PROPERTIES( &this->blank ); + mlt_properties blank_props = MLT_PRODUCER_PROPERTIES( &self->blank ); mlt_events_block( blank_props, blank_props ); - mlt_producer_set_in_and_out( &this->blank, in, out ); + mlt_producer_set_in_and_out( &self->blank, in, out ); mlt_events_unblock( blank_props, blank_props ); } - // Now make sure the cut comes from this this->blank + // Now make sure the cut comes from this self->blank if ( source == NULL ) { - producer = mlt_producer_cut( &this->blank, in, out ); + producer = mlt_producer_cut( &self->blank, in, out ); } - else if ( !mlt_producer_is_cut( source ) || mlt_producer_cut_parent( source ) != &this->blank ) + else if ( !mlt_producer_is_cut( source ) || mlt_producer_cut_parent( source ) != &self->blank ) { - producer = mlt_producer_cut( &this->blank, in, out ); + producer = mlt_producer_cut( &self->blank, in, out ); } else { @@ -297,67 +297,67 @@ } // Check that we have room - if ( this->count >= this->size ) + if ( self->count >= self->size ) { int i; - this->list = realloc( this->list, ( this->size + 10 ) * sizeof( playlist_entry * ) ); - for ( i = this->size; i < this->size + 10; i ++ ) this->list[ i ] = NULL; - this->size += 10; + self->list = realloc( self->list, ( self->size + 10 ) * sizeof( playlist_entry * ) ); + for ( i = self->size; i < self->size + 10; i ++ ) self->list[ i ] = NULL; + self->size += 10; } // Create the entry - this->list[ this->count ] = calloc( sizeof( playlist_entry ), 1 ); - if ( this->list[ this->count ] != NULL ) + self->list[ self->count ] = calloc( sizeof( playlist_entry ), 1 ); + if ( self->list[ self->count ] != NULL ) { - this->list[ this->count ]->producer = producer; - this->list[ this->count ]->frame_in = in; - this->list[ this->count ]->frame_out = out; - this->list[ this->count ]->frame_count = out - in + 1; - this->list[ this->count ]->repeat = 1; - this->list[ this->count ]->producer_length = mlt_producer_get_out( producer ) - mlt_producer_get_in( producer ) + 1; - this->list[ this->count ]->event = mlt_events_listen( parent, this, "producer-changed", ( mlt_listener )mlt_playlist_listener ); - mlt_event_inc_ref( this->list[ this->count ]->event ); + self->list[ self->count ]->producer = producer; + self->list[ self->count ]->frame_in = in; + self->list[ self->count ]->frame_out = out; + self->list[ self->count ]->frame_count = out - in + 1; + self->list[ self->count ]->repeat = 1; + self->list[ self->count ]->producer_length = mlt_producer_get_playtime( producer ); + self->list[ self->count ]->event = mlt_events_listen( parent, self, "producer-changed", ( mlt_listener )mlt_playlist_listener ); + mlt_event_inc_ref( self->list[ self->count ]->event ); mlt_properties_set( properties, "eof", "pause" ); mlt_producer_set_speed( producer, 0 ); - this->count ++; + self->count ++; } - return mlt_playlist_virtual_refresh( this ); + return mlt_playlist_virtual_refresh( self ); } /** Locate a producer by index. * * \private \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param[in, out] position the time at which to locate the producer, returns the time relative to the producer's starting point * \param[out] clip the index of the playlist entry * \param[out] total the duration of the playlist up to and including this producer * \return a producer or NULL if not found */ -static mlt_producer mlt_playlist_locate( mlt_playlist this, mlt_position *position, int *clip, int *total ) +static mlt_producer mlt_playlist_locate( mlt_playlist self, mlt_position *position, int *clip, int *total ) { // Default producer to NULL mlt_producer producer = NULL; // Loop for each producer until found - for ( *clip = 0; *clip < this->count; *clip += 1 ) + for ( *clip = 0; *clip < self->count; *clip += 1 ) { // Increment the total - *total += this->list[ *clip ]->frame_count; + *total += self->list[ *clip ]->frame_count; // Check if the position indicates that we have found the clip // Note that 0 length clips get skipped automatically - if ( *position < this->list[ *clip ]->frame_count ) + if ( *position < self->list[ *clip ]->frame_count ) { // Found it, now break - producer = this->list[ *clip ]->producer; + producer = self->list[ *clip ]->producer; break; } else { - // Decrement position by length of this entry - *position -= this->list[ *clip ]->frame_count; + // Decrement position by length of self entry + *position -= self->list[ *clip ]->frame_count; } } @@ -371,16 +371,16 @@ * closing producers previous to the preceding playlist if the autoclose * property is set. * \private \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param[out] progressive true if the producer should be displayed progressively * \return the service interface of the producer at the play head * \see producer_get_frame */ -static mlt_service mlt_playlist_virtual_seek( mlt_playlist this, int *progressive ) +static mlt_service mlt_playlist_virtual_seek( mlt_playlist self, int *progressive ) { // Map playlist position to real producer in virtual playlist - mlt_position position = mlt_producer_frame( &this->parent ); + mlt_position position = mlt_producer_frame( &self->parent ); // Keep the original position since we change it while iterating through the list mlt_position original = position; @@ -390,10 +390,10 @@ int total = 0; // Locate the producer for the position - mlt_producer producer = mlt_playlist_locate( this, &position, &i, &total ); + mlt_producer producer = mlt_playlist_locate( self, &position, &i, &total ); // Get the properties - mlt_properties properties = MLT_PLAYLIST_PROPERTIES( this ); + mlt_properties properties = MLT_PLAYLIST_PROPERTIES( self ); // Automatically close previous producers if requested if ( i > 1 // keep immediate previous in case app wants to get info about what just finished @@ -404,11 +404,11 @@ // They might have jumped ahead! for ( j = 0; j < i - 1; j++ ) { - mlt_service_lock( MLT_PRODUCER_SERVICE( this->list[ j ]->producer ) ); - mlt_producer p = this->list[ j ]->producer; + mlt_service_lock( MLT_PRODUCER_SERVICE( self->list[ j ]->producer ) ); + mlt_producer p = self->list[ j ]->producer; if ( p ) { - this->list[ j ]->producer = NULL; + self->list[ j ]->producer = NULL; mlt_service_unlock( MLT_PRODUCER_SERVICE( p ) ); mlt_producer_close( p ); } @@ -422,33 +422,33 @@ // Seek in real producer to relative position if ( producer != NULL ) { - int count = this->list[ i ]->frame_count / this->list[ i ]->repeat; + int count = self->list[ i ]->frame_count / self->list[ i ]->repeat; *progressive = count == 1; mlt_producer_seek( producer, (int)position % count ); } else if ( !strcmp( eof, "pause" ) && total > 0 ) { - playlist_entry *entry = this->list[ this->count - 1 ]; + playlist_entry *entry = self->list[ self->count - 1 ]; int count = entry->frame_count / entry->repeat; - mlt_producer this_producer = MLT_PLAYLIST_PRODUCER( this ); - mlt_producer_seek( this_producer, original - 1 ); + mlt_producer self_producer = MLT_PLAYLIST_PRODUCER( self ); + mlt_producer_seek( self_producer, original - 1 ); producer = entry->producer; mlt_producer_seek( producer, (int)entry->frame_out % count ); - mlt_producer_set_speed( this_producer, 0 ); + mlt_producer_set_speed( self_producer, 0 ); mlt_producer_set_speed( producer, 0 ); *progressive = count == 1; } else if ( !strcmp( eof, "loop" ) && total > 0 ) { - playlist_entry *entry = this->list[ 0 ]; - mlt_producer this_producer = MLT_PLAYLIST_PRODUCER( this ); - mlt_producer_seek( this_producer, 0 ); + playlist_entry *entry = self->list[ 0 ]; + mlt_producer self_producer = MLT_PLAYLIST_PRODUCER( self ); + mlt_producer_seek( self_producer, 0 ); producer = entry->producer; mlt_producer_seek( producer, 0 ); } else { - producer = &this->blank; + producer = &self->blank; } return MLT_PRODUCER_SERVICE( producer ); @@ -457,46 +457,46 @@ /** Invoked when a producer indicates that it has prematurely reached its end. * * \private \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \return a producer * \see producer_get_frame */ -static mlt_producer mlt_playlist_virtual_set_out( mlt_playlist this ) +static mlt_producer mlt_playlist_virtual_set_out( mlt_playlist self ) { // Default producer to blank - mlt_producer producer = &this->blank; + mlt_producer producer = &self->blank; // Map playlist position to real producer in virtual playlist - mlt_position position = mlt_producer_frame( &this->parent ); + mlt_position position = mlt_producer_frame( &self->parent ); // Loop through the virtual playlist int i = 0; - for ( i = 0; i < this->count; i ++ ) + for ( i = 0; i < self->count; i ++ ) { - if ( position < this->list[ i ]->frame_count ) + if ( position < self->list[ i ]->frame_count ) { // Found it, now break - producer = this->list[ i ]->producer; + producer = self->list[ i ]->producer; break; } else { // Decrement position by length of this entry - position -= this->list[ i ]->frame_count; + position -= self->list[ i ]->frame_count; } } // Seek in real producer to relative position - if ( i < this->count && this->list[ i ]->frame_out != position ) + if ( i < self->count && self->list[ i ]->frame_out != position ) { // Update the frame_count for the changed clip (hmmm) - this->list[ i ]->frame_out = position; - this->list[ i ]->frame_count = this->list[ i ]->frame_out - this->list[ i ]->frame_in + 1; + self->list[ i ]->frame_out = position; + self->list[ i ]->frame_count = self->list[ i ]->frame_out - self->list[ i ]->frame_in + 1; // Refresh the playlist - mlt_playlist_virtual_refresh( this ); + mlt_playlist_virtual_refresh( self ); } return producer; @@ -505,21 +505,21 @@ /** Obtain the current clips index. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \return the index of the playlist entry at the current position */ -int mlt_playlist_current_clip( mlt_playlist this ) +int mlt_playlist_current_clip( mlt_playlist self ) { // Map playlist position to real producer in virtual playlist - mlt_position position = mlt_producer_frame( &this->parent ); + mlt_position position = mlt_producer_frame( &self->parent ); // Loop through the virtual playlist int i = 0; - for ( i = 0; i < this->count; i ++ ) + for ( i = 0; i < self->count; i ++ ) { - if ( position < this->list[ i ]->frame_count ) + if ( position < self->list[ i ]->frame_count ) { // Found it, now break break; @@ -527,7 +527,7 @@ else { // Decrement position by length of this entry - position -= this->list[ i ]->frame_count; + position -= self->list[ i ]->frame_count; } } @@ -537,30 +537,30 @@ /** Obtain the current clips producer. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \return the producer at the current position */ -mlt_producer mlt_playlist_current( mlt_playlist this ) +mlt_producer mlt_playlist_current( mlt_playlist self ) { - int i = mlt_playlist_current_clip( this ); - if ( i < this->count ) - return this->list[ i ]->producer; + int i = mlt_playlist_current_clip( self ); + if ( i < self->count ) + return self->list[ i ]->producer; else - return &this->blank; + return &self->blank; } /** Get the position which corresponds to the start of the next clip. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param whence the location from which to make the index relative: * start of playlist, end of playlist, or current position * \param index the playlist entry index relative to whence * \return the time at which the referenced clip starts */ -mlt_position mlt_playlist_clip( mlt_playlist this, mlt_whence whence, int index ) +mlt_position mlt_playlist_clip( mlt_playlist self, mlt_whence whence, int index ) { mlt_position position = 0; int absolute_clip = index; @@ -574,23 +574,23 @@ break; case mlt_whence_relative_current: - absolute_clip = mlt_playlist_current_clip( this ) + index; + absolute_clip = mlt_playlist_current_clip( self ) + index; break; case mlt_whence_relative_end: - absolute_clip = this->count - index; + absolute_clip = self->count - index; break; } // Check that we're in a valid range if ( absolute_clip < 0 ) absolute_clip = 0; - else if ( absolute_clip > this->count ) - absolute_clip = this->count; + else if ( absolute_clip > self->count ) + absolute_clip = self->count; // Now determine the position for ( i = 0; i < absolute_clip; i ++ ) - position += this->list[ i ]->frame_count; + position += self->list[ i ]->frame_count; return position; } @@ -598,29 +598,29 @@ /** Get all the info about the clip specified. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param info a clip info struct * \param index a playlist entry index * \return true if there was an error */ -int mlt_playlist_get_clip_info( mlt_playlist this, mlt_playlist_clip_info *info, int index ) +int mlt_playlist_get_clip_info( mlt_playlist self, mlt_playlist_clip_info *info, int index ) { - int error = index < 0 || index >= this->count || this->list[ index ]->producer == NULL; + int error = index < 0 || index >= self->count || self->list[ index ]->producer == NULL; memset( info, 0, sizeof( mlt_playlist_clip_info ) ); if ( !error ) { - mlt_producer producer = mlt_producer_cut_parent( this->list[ index ]->producer ); + mlt_producer producer = mlt_producer_cut_parent( self->list[ index ]->producer ); mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); info->clip = index; info->producer = producer; - info->cut = this->list[ index ]->producer; - info->start = mlt_playlist_clip( this, mlt_whence_relative_start, index ); + info->cut = self->list[ index ]->producer; + info->start = mlt_playlist_clip( self, mlt_whence_relative_start, index ); info->resource = mlt_properties_get( properties, "resource" ); - info->frame_in = this->list[ index ]->frame_in; - info->frame_out = this->list[ index ]->frame_out; - info->frame_count = this->list[ index ]->frame_count; - info->repeat = this->list[ index ]->repeat; + info->frame_in = self->list[ index ]->frame_in; + info->frame_out = self->list[ index ]->frame_out; + info->frame_count = self->list[ index ]->frame_count; + info->repeat = self->list[ index ]->repeat; info->length = mlt_producer_get_length( producer ); info->fps = mlt_producer_get_fps( producer ); } @@ -631,80 +631,80 @@ /** Get number of clips in the playlist. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \return the number of playlist entries */ -int mlt_playlist_count( mlt_playlist this ) +int mlt_playlist_count( mlt_playlist self ) { - return this->count; + return self->count; } /** Clear the playlist. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \return true if there was an error */ -int mlt_playlist_clear( mlt_playlist this ) +int mlt_playlist_clear( mlt_playlist self ) { int i; - for ( i = 0; i < this->count; i ++ ) + for ( i = 0; i < self->count; i ++ ) { - mlt_event_close( this->list[ i ]->event ); - mlt_producer_close( this->list[ i ]->producer ); + mlt_event_close( self->list[ i ]->event ); + mlt_producer_close( self->list[ i ]->producer ); } - this->count = 0; - return mlt_playlist_virtual_refresh( this ); + self->count = 0; + return mlt_playlist_virtual_refresh( self ); } /** Append a producer to the playlist. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param producer the producer to append * \return true if there was an error */ -int mlt_playlist_append( mlt_playlist this, mlt_producer producer ) +int mlt_playlist_append( mlt_playlist self, mlt_producer producer ) { // Append to virtual list - return mlt_playlist_virtual_append( this, producer, 0, mlt_producer_get_playtime( producer ) - 1 ); + return mlt_playlist_virtual_append( self, producer, 0, mlt_producer_get_playtime( producer ) - 1 ); } /** Append a producer to the playlist with in/out points. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param producer the producer to append * \param in the starting point on the producer; a negative value is the same as 0 * \param out the ending point on the producer; a negative value is the same as producer length - 1 * \return true if there was an error */ -int mlt_playlist_append_io( mlt_playlist this, mlt_producer producer, mlt_position in, mlt_position out ) +int mlt_playlist_append_io( mlt_playlist self, mlt_producer producer, mlt_position in, mlt_position out ) { // Append to virtual list if ( in < 0 && out < 0 ) - return mlt_playlist_append( this, producer ); + return mlt_playlist_append( self, producer ); else - return mlt_playlist_virtual_append( this, producer, in, out ); + return mlt_playlist_virtual_append( self, producer, in, out ); } /** Append a blank to the playlist of a given length. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param length the ending time of the blank entry, not its duration * \return true if there was an error */ -int mlt_playlist_blank( mlt_playlist this, mlt_position length ) +int mlt_playlist_blank( mlt_playlist self, mlt_position length ) { // Append to the virtual list if (length >= 0) - return mlt_playlist_virtual_append( this, &this->blank, 0, length ); + return mlt_playlist_virtual_append( self, &self->blank, 0, length ); else return 1; } @@ -712,7 +712,7 @@ /** Insert a producer into the playlist. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param producer the producer to insert * \param where the producer's playlist entry index * \param in the starting point on the producer @@ -720,57 +720,57 @@ * \return true if there was an error */ -int mlt_playlist_insert( mlt_playlist this, mlt_producer producer, int where, mlt_position in, mlt_position out ) +int mlt_playlist_insert( mlt_playlist self, mlt_producer producer, int where, mlt_position in, mlt_position out ) { // Append to end - mlt_events_block( MLT_PLAYLIST_PROPERTIES( this ), this ); - mlt_playlist_append_io( this, producer, in, out ); + mlt_events_block( MLT_PLAYLIST_PROPERTIES( self ), self ); + mlt_playlist_append_io( self, producer, in, out ); // Move to the position specified - mlt_playlist_move( this, this->count - 1, where ); - mlt_events_unblock( MLT_PLAYLIST_PROPERTIES( this ), this ); + mlt_playlist_move( self, self->count - 1, where ); + mlt_events_unblock( MLT_PLAYLIST_PROPERTIES( self ), self ); - return mlt_playlist_virtual_refresh( this ); + return mlt_playlist_virtual_refresh( self ); } /** Remove an entry in the playlist. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param where the playlist entry index * \return true if there was an error */ -int mlt_playlist_remove( mlt_playlist this, int where ) +int mlt_playlist_remove( mlt_playlist self, int where ) { - int error = where < 0 || where >= this->count; - if ( error == 0 && mlt_playlist_unmix( this, where ) != 0 ) + int error = where < 0 || where >= self->count; + if ( error == 0 && mlt_playlist_unmix( self, where ) != 0 ) { // We need to know the current clip and the position within the playlist - int current = mlt_playlist_current_clip( this ); - mlt_position position = mlt_producer_position( MLT_PLAYLIST_PRODUCER( this ) ); + int current = mlt_playlist_current_clip( self ); + mlt_position position = mlt_producer_position( MLT_PLAYLIST_PRODUCER( self ) ); // We need all the details about the clip we're removing mlt_playlist_clip_info where_info; - playlist_entry *entry = this->list[ where ]; + playlist_entry *entry = self->list[ where ]; mlt_properties properties = MLT_PRODUCER_PROPERTIES( entry->producer ); // Loop variable int i = 0; // Get the clip info - mlt_playlist_get_clip_info( this, &where_info, where ); + mlt_playlist_get_clip_info( self, &where_info, where ); // Make sure the clip to be removed is valid and correct if necessary if ( where < 0 ) where = 0; - if ( where >= this->count ) - where = this->count - 1; + if ( where >= self->count ) + where = self->count - 1; // Reorganise the list - for ( i = where + 1; i < this->count; i ++ ) - this->list[ i - 1 ] = this->list[ i ]; - this->count --; + for ( i = where + 1; i < self->count; i ++ ) + self->list[ i - 1 ] = self->list[ i ]; + self->count --; if ( entry->preservation_hack == 0 ) { @@ -796,17 +796,17 @@ // Correct position if ( where == current ) - mlt_producer_seek( MLT_PLAYLIST_PRODUCER( this ), where_info.start ); - else if ( where < current && this->count > 0 ) - mlt_producer_seek( MLT_PLAYLIST_PRODUCER( this ), position - where_info.frame_count ); - else if ( this->count == 0 ) - mlt_producer_seek( MLT_PLAYLIST_PRODUCER( this ), 0 ); + mlt_producer_seek( MLT_PLAYLIST_PRODUCER( self ), where_info.start ); + else if ( where < current && self->count > 0 ) + mlt_producer_seek( MLT_PLAYLIST_PRODUCER( self ), position - where_info.frame_count ); + else if ( self->count == 0 ) + mlt_producer_seek( MLT_PLAYLIST_PRODUCER( self ), 0 ); // Free the entry free( entry ); // Refresh the playlist - mlt_playlist_virtual_refresh( this ); + mlt_playlist_virtual_refresh( self ); } return error; @@ -815,37 +815,37 @@ /** Move an entry in the playlist. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param src an entry index * \param dest an entry index * \return false */ -int mlt_playlist_move( mlt_playlist this, int src, int dest ) +int mlt_playlist_move( mlt_playlist self, int src, int dest ) { int i; /* We need to ensure that the requested indexes are valid and correct it as necessary */ if ( src < 0 ) src = 0; - if ( src >= this->count ) - src = this->count - 1; + if ( src >= self->count ) + src = self->count - 1; if ( dest < 0 ) dest = 0; - if ( dest >= this->count ) - dest = this->count - 1; + if ( dest >= self->count ) + dest = self->count - 1; - if ( src != dest && this->count > 1 ) + if ( src != dest && self->count > 1 ) { - int current = mlt_playlist_current_clip( this ); - mlt_position position = mlt_producer_position( MLT_PLAYLIST_PRODUCER( this ) ); + int current = mlt_playlist_current_clip( self ); + mlt_position position = mlt_producer_position( MLT_PLAYLIST_PRODUCER( self ) ); playlist_entry *src_entry = NULL; // We need all the details about the current clip mlt_playlist_clip_info current_info; - mlt_playlist_get_clip_info( this, ¤t_info, current ); + mlt_playlist_get_clip_info( self, ¤t_info, current ); position -= current_info.start; if ( current == src ) @@ -855,22 +855,22 @@ else if ( current == dest ) current = src; - src_entry = this->list[ src ]; + src_entry = self->list[ src ]; if ( src > dest ) { for ( i = src; i > dest; i -- ) - this->list[ i ] = this->list[ i - 1 ]; + self->list[ i ] = self->list[ i - 1 ]; } else { for ( i = src; i < dest; i ++ ) - this->list[ i ] = this->list[ i + 1 ]; + self->list[ i ] = self->list[ i + 1 ]; } - this->list[ dest ] = src_entry; + self->list[ dest ] = src_entry; - mlt_playlist_get_clip_info( this, ¤t_info, current ); - mlt_producer_seek( MLT_PLAYLIST_PRODUCER( this ), current_info.start + position ); - mlt_playlist_virtual_refresh( this ); + mlt_playlist_get_clip_info( self, ¤t_info, current ); + mlt_producer_seek( MLT_PLAYLIST_PRODUCER( self ), current_info.start + position ); + mlt_playlist_virtual_refresh( self ); } return 0; @@ -879,20 +879,20 @@ /** Repeat the specified clip n times. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param clip a playlist entry index * \param repeat the number of times to repeat the clip * \return true if there was an error */ -int mlt_playlist_repeat_clip( mlt_playlist this, int clip, int repeat ) +int mlt_playlist_repeat_clip( mlt_playlist self, int clip, int repeat ) { - int error = repeat < 1 || clip < 0 || clip >= this->count; + int error = repeat < 1 || clip < 0 || clip >= self->count; if ( error == 0 ) { - playlist_entry *entry = this->list[ clip ]; + playlist_entry *entry = self->list[ clip ]; entry->repeat = repeat; - mlt_playlist_virtual_refresh( this ); + mlt_playlist_virtual_refresh( self ); } return error; } @@ -900,33 +900,33 @@ /** Resize the specified clip. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param clip the index of the playlist entry * \param in the new starting time on the clip's producer; a negative value is the same as 0 * \param out the new ending time on the clip's producer; a negative value is the same as length - 1 * \return true if there was an error */ -int mlt_playlist_resize_clip( mlt_playlist this, int clip, mlt_position in, mlt_position out ) +int mlt_playlist_resize_clip( mlt_playlist self, int clip, mlt_position in, mlt_position out ) { - int error = clip < 0 || clip >= this->count; - if ( error == 0 && mlt_playlist_resize_mix( this, clip, in, out ) != 0 ) + int error = clip < 0 || clip >= self->count; + if ( error == 0 && mlt_playlist_resize_mix( self, clip, in, out ) != 0 ) { - playlist_entry *entry = this->list[ clip ]; + playlist_entry *entry = self->list[ clip ]; mlt_producer producer = entry->producer; - mlt_properties properties = MLT_PLAYLIST_PROPERTIES( this ); + mlt_properties properties = MLT_PLAYLIST_PROPERTIES( self ); mlt_events_block( properties, properties ); if ( mlt_producer_is_blank( producer ) ) { // Make sure the blank is long enough to accomodate the length specified - if ( out - in + 1 > mlt_producer_get_length( &this->blank ) ) + if ( out - in + 1 > mlt_producer_get_length( &self->blank ) ) { - mlt_properties blank_props = MLT_PRODUCER_PROPERTIES( &this->blank ); + mlt_properties blank_props = MLT_PRODUCER_PROPERTIES( &self->blank ); mlt_properties_set_int( blank_props, "length", out - in + 1 ); mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( producer ), "length", out - in + 1 ); - mlt_producer_set_in_and_out( &this->blank, 0, out - in ); + mlt_producer_set_in_and_out( &self->blank, 0, out - in ); } } @@ -944,7 +944,7 @@ mlt_producer_set_in_and_out( producer, in, out ); mlt_events_unblock( properties, properties ); - mlt_playlist_virtual_refresh( this ); + mlt_playlist_virtual_refresh( self ); } return error; } @@ -953,46 +953,48 @@ * * This splits after the specified frame. * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param clip the index of the playlist entry * \param position the time at which to split relative to the beginning of the clip or its end if negative * \return true if there was an error */ -int mlt_playlist_split( mlt_playlist this, int clip, mlt_position position ) +int mlt_playlist_split( mlt_playlist self, int clip, mlt_position position ) { - int error = clip < 0 || clip >= this->count; + int error = clip < 0 || clip >= self->count; if ( error == 0 ) { - playlist_entry *entry = this->list[ clip ]; + playlist_entry *entry = self->list[ clip ]; position = position < 0 ? entry->frame_count + position - 1 : position; if ( position >= 0 && position < entry->frame_count - 1 ) { int in = entry->frame_in; int out = entry->frame_out; - mlt_events_block( MLT_PLAYLIST_PROPERTIES( this ), this ); - mlt_playlist_resize_clip( this, clip, in, in + position ); + mlt_events_block( MLT_PLAYLIST_PROPERTIES( self ), self ); + mlt_playlist_resize_clip( self, clip, in, in + position ); if ( !mlt_producer_is_blank( entry->producer ) ) { int i = 0; mlt_properties entry_properties = MLT_PRODUCER_PROPERTIES( entry->producer ); mlt_producer split = mlt_producer_cut( entry->producer, in + position + 1, out ); mlt_properties split_properties = MLT_PRODUCER_PROPERTIES( split ); - mlt_playlist_insert( this, split, clip + 1, 0, -1 ); + mlt_playlist_insert( self, split, clip + 1, 0, -1 ); + mlt_properties_lock( entry_properties ); for ( i = 0; i < mlt_properties_count( entry_properties ); i ++ ) { char *name = mlt_properties_get_name( entry_properties, i ); if ( name != NULL && !strncmp( name, "meta.", 5 ) ) mlt_properties_set( split_properties, name, mlt_properties_get_value( entry_properties, i ) ); } + mlt_properties_unlock( entry_properties ); mlt_producer_close( split ); } else { - mlt_playlist_insert( this, &this->blank, clip + 1, 0, out - position - 1 ); + mlt_playlist_insert( self, &self->blank, clip + 1, 0, out - position - 1 ); } - mlt_events_unblock( MLT_PLAYLIST_PROPERTIES( this ), this ); - mlt_playlist_virtual_refresh( this ); + mlt_events_unblock( MLT_PLAYLIST_PROPERTIES( self ), self ); + mlt_playlist_virtual_refresh( self ); } else { @@ -1005,26 +1007,26 @@ /** Split the playlist at the absolute position. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param position the time at which to split relative to the beginning of the clip * \param left true to split before the frame starting at position * \return true if there was an error */ -int mlt_playlist_split_at( mlt_playlist this, mlt_position position, int left ) +int mlt_playlist_split_at( mlt_playlist self, mlt_position position, int left ) { - int result = this == NULL ? -1 : 0; + int result = self == NULL ? -1 : 0; if ( !result ) { - if ( position >= 0 && position < mlt_producer_get_playtime( MLT_PLAYLIST_PRODUCER( this ) ) ) + if ( position >= 0 && position < mlt_producer_get_playtime( MLT_PLAYLIST_PRODUCER( self ) ) ) { - int clip = mlt_playlist_get_clip_index_at( this, position ); + int clip = mlt_playlist_get_clip_index_at( self, position ); mlt_playlist_clip_info info; - mlt_playlist_get_clip_info( this, &info, clip ); + mlt_playlist_get_clip_info( self, &info, clip ); if ( left && position != info.start ) - mlt_playlist_split( this, clip, position - info.start - 1 ); + mlt_playlist_split( self, clip, position - info.start - 1 ); else if ( !left ) - mlt_playlist_split( this, clip, position - info.start ); + mlt_playlist_split( self, clip, position - info.start ); result = position; } else if ( position <= 0 ) @@ -1033,7 +1035,7 @@ } else { - result = mlt_producer_get_playtime( MLT_PLAYLIST_PRODUCER( this ) ); + result = mlt_producer_get_playtime( MLT_PLAYLIST_PRODUCER( self ) ); } } return result; @@ -1042,33 +1044,33 @@ /** Join 1 or more consecutive clips. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param clip the starting playlist entry index * \param count the number of entries to merge * \param merge ignored * \return true if there was an error */ -int mlt_playlist_join( mlt_playlist this, int clip, int count, int merge ) +int mlt_playlist_join( mlt_playlist self, int clip, int count, int merge ) { - int error = clip < 0 || clip >= this->count; + int error = clip < 0 || clip >= self->count; if ( error == 0 ) { int i = clip; mlt_playlist new_clip = mlt_playlist_init( ); - mlt_events_block( MLT_PLAYLIST_PROPERTIES( this ), this ); - if ( clip + count >= this->count ) - count = this->count - clip - 1; + mlt_events_block( MLT_PLAYLIST_PROPERTIES( self ), self ); + if ( clip + count >= self->count ) + count = self->count - clip - 1; for ( i = 0; i <= count; i ++ ) { - playlist_entry *entry = this->list[ clip ]; + playlist_entry *entry = self->list[ clip ]; mlt_playlist_append( new_clip, entry->producer ); mlt_playlist_repeat_clip( new_clip, i, entry->repeat ); entry->preservation_hack = 1; - mlt_playlist_remove( this, clip ); + mlt_playlist_remove( self, clip ); } - mlt_events_unblock( MLT_PLAYLIST_PROPERTIES( this ), this ); - mlt_playlist_insert( this, MLT_PLAYLIST_PRODUCER( new_clip ), clip, 0, -1 ); + mlt_events_unblock( MLT_PLAYLIST_PROPERTIES( self ), self ); + mlt_playlist_insert( self, MLT_PLAYLIST_PRODUCER( new_clip ), clip, 0, -1 ); mlt_playlist_close( new_clip ); } return error; @@ -1077,24 +1079,24 @@ /** Mix consecutive clips for a specified length and apply transition if specified. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param clip the index of the playlist entry * \param length the number of frames over which to create the mix * \param transition the transition to use for the mix * \return true if there was an error */ -int mlt_playlist_mix( mlt_playlist this, int clip, int length, mlt_transition transition ) +int mlt_playlist_mix( mlt_playlist self, int clip, int length, mlt_transition transition ) { - int error = ( clip < 0 || clip + 1 >= this->count ); + int error = ( clip < 0 || clip + 1 >= self->count ); if ( error == 0 ) { - playlist_entry *clip_a = this->list[ clip ]; - playlist_entry *clip_b = this->list[ clip + 1 ]; + playlist_entry *clip_a = self->list[ clip ]; + playlist_entry *clip_b = self->list[ clip + 1 ]; mlt_producer track_a = NULL; mlt_producer track_b = NULL; mlt_tractor tractor = mlt_tractor_new( ); - mlt_events_block( MLT_PLAYLIST_PROPERTIES( this ), this ); + mlt_events_block( MLT_PLAYLIST_PROPERTIES( self ), self ); // Check length is valid for both clips and resize if necessary. int max_size = clip_a->frame_count > clip_b->frame_count ? clip_a->frame_count : clip_b->frame_count; @@ -1116,7 +1118,7 @@ mlt_tractor_set_track( tractor, track_b, 1 ); // Insert the mix object into the playlist - mlt_playlist_insert( this, MLT_TRACTOR_PRODUCER( tractor ), clip + 1, -1, -1 ); + mlt_playlist_insert( self, MLT_TRACTOR_PRODUCER( tractor ), clip + 1, -1, -1 ); mlt_properties_set_data( MLT_TRACTOR_PROPERTIES( tractor ), "mlt_mix", tractor, 0, NULL, NULL ); // Attach the transition @@ -1137,41 +1139,41 @@ if ( track_b == clip_b->producer ) { clip_b->preservation_hack = 1; - mlt_playlist_remove( this, clip + 2 ); + mlt_playlist_remove( self, clip + 2 ); } else if ( clip_b->frame_out - clip_b->frame_in > length ) { - mlt_playlist_resize_clip( this, clip + 2, clip_b->frame_in + length, clip_b->frame_out ); + mlt_playlist_resize_clip( self, clip + 2, clip_b->frame_in + length, clip_b->frame_out ); mlt_properties_set_data( MLT_PRODUCER_PROPERTIES( clip_b->producer ), "mix_in", tractor, 0, NULL, NULL ); mlt_properties_set_data( MLT_TRACTOR_PROPERTIES( tractor ), "mix_out", clip_b->producer, 0, NULL, NULL ); } else { mlt_producer_clear( clip_b->producer ); - mlt_playlist_remove( this, clip + 2 ); + mlt_playlist_remove( self, clip + 2 ); } // Check if we have anything left on the left hand clip if ( track_a == clip_a->producer ) { clip_a->preservation_hack = 1; - mlt_playlist_remove( this, clip ); + mlt_playlist_remove( self, clip ); } else if ( clip_a->frame_out - clip_a->frame_in > length ) { - mlt_playlist_resize_clip( this, clip, clip_a->frame_in, clip_a->frame_out - length ); + mlt_playlist_resize_clip( self, clip, clip_a->frame_in, clip_a->frame_out - length ); mlt_properties_set_data( MLT_PRODUCER_PROPERTIES( clip_a->producer ), "mix_out", tractor, 0, NULL, NULL ); mlt_properties_set_data( MLT_TRACTOR_PROPERTIES( tractor ), "mix_in", clip_a->producer, 0, NULL, NULL ); } else { mlt_producer_clear( clip_a->producer ); - mlt_playlist_remove( this, clip ); + mlt_playlist_remove( self, clip ); } // Unblock and force a fire off of change events to listeners - mlt_events_unblock( MLT_PLAYLIST_PROPERTIES( this ), this ); - mlt_playlist_virtual_refresh( this ); + mlt_events_unblock( MLT_PLAYLIST_PROPERTIES( self ), self ); + mlt_playlist_virtual_refresh( self ); mlt_tractor_close( tractor ); } return error; @@ -1180,15 +1182,15 @@ /** Add a transition to an existing mix. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param clip the index of the playlist entry * \param transition a transition * \return true if there was an error */ -int mlt_playlist_mix_add( mlt_playlist this, int clip, mlt_transition transition ) +int mlt_playlist_mix_add( mlt_playlist self, int clip, mlt_transition transition ) { - mlt_producer producer = mlt_producer_cut_parent( mlt_playlist_get_clip( this, clip ) ); + mlt_producer producer = mlt_producer_cut_parent( mlt_playlist_get_clip( self, clip ) ); mlt_properties properties = producer != NULL ? MLT_PRODUCER_PROPERTIES( producer ) : NULL; mlt_tractor tractor = properties != NULL ? mlt_properties_get_data( properties, "mlt_mix", NULL ) : NULL; int error = transition == NULL || tractor == NULL; @@ -1196,7 +1198,7 @@ { mlt_field field = mlt_tractor_field( tractor ); mlt_field_plant_transition( field, transition, 0, 1 ); - mlt_transition_set_in_and_out( transition, 0, this->list[ clip ]->frame_count - 1 ); + mlt_transition_set_in_and_out( transition, 0, self->list[ clip ]->frame_count - 1 ); } return error; } @@ -1204,58 +1206,58 @@ /** Return the clip at the clip index. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param clip the index of a playlist entry * \return a producer or NULL if there was an error */ -mlt_producer mlt_playlist_get_clip( mlt_playlist this, int clip ) +mlt_producer mlt_playlist_get_clip( mlt_playlist self, int clip ) { - if ( clip >= 0 && clip < this->count ) - return this->list[ clip ]->producer; + if ( clip >= 0 && clip < self->count ) + return self->list[ clip ]->producer; return NULL; } /** Return the clip at the specified position. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param position a time relative to the beginning of the playlist * \return a producer or NULL if not found */ -mlt_producer mlt_playlist_get_clip_at( mlt_playlist this, mlt_position position ) +mlt_producer mlt_playlist_get_clip_at( mlt_playlist self, mlt_position position ) { int index = 0, total = 0; - return mlt_playlist_locate( this, &position, &index, &total ); + return mlt_playlist_locate( self, &position, &index, &total ); } /** Return the clip index of the specified position. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param position a time relative to the beginning of the playlist * \return the index of the playlist entry */ -int mlt_playlist_get_clip_index_at( mlt_playlist this, mlt_position position ) +int mlt_playlist_get_clip_index_at( mlt_playlist self, mlt_position position ) { int index = 0, total = 0; - mlt_playlist_locate( this, &position, &index, &total ); + mlt_playlist_locate( self, &position, &index, &total ); return index; } /** Determine if the clip is a mix. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param clip the index of the playlist entry * \return true if the producer is a mix */ -int mlt_playlist_clip_is_mix( mlt_playlist this, int clip ) +int mlt_playlist_clip_is_mix( mlt_playlist self, int clip ) { - mlt_producer producer = mlt_producer_cut_parent( mlt_playlist_get_clip( this, clip ) ); + mlt_producer producer = mlt_producer_cut_parent( mlt_playlist_get_clip( self, clip ) ); mlt_properties properties = producer != NULL ? MLT_PRODUCER_PROPERTIES( producer ) : NULL; mlt_tractor tractor = properties != NULL ? mlt_properties_get_data( properties, "mlt_mix", NULL ) : NULL; return tractor != NULL; @@ -1265,33 +1267,33 @@ * back correctly on to the playlist. * * \private \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param clip the index of the playlist entry * \return true if there was an error */ -static int mlt_playlist_unmix( mlt_playlist this, int clip ) +static int mlt_playlist_unmix( mlt_playlist self, int clip ) { - int error = ( clip < 0 || clip >= this->count ); + int error = ( clip < 0 || clip >= self->count ); // Ensure that the clip request is actually a mix if ( error == 0 ) { - mlt_producer producer = mlt_producer_cut_parent( this->list[ clip ]->producer ); + mlt_producer producer = mlt_producer_cut_parent( self->list[ clip ]->producer ); mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); error = mlt_properties_get_data( properties, "mlt_mix", NULL ) == NULL || - this->list[ clip ]->preservation_hack; + self->list[ clip ]->preservation_hack; } if ( error == 0 ) { - playlist_entry *mix = this->list[ clip ]; + playlist_entry *mix = self->list[ clip ]; mlt_tractor tractor = ( mlt_tractor )mlt_producer_cut_parent( mix->producer ); mlt_properties properties = MLT_TRACTOR_PROPERTIES( tractor ); mlt_producer clip_a = mlt_properties_get_data( properties, "mix_in", NULL ); mlt_producer clip_b = mlt_properties_get_data( properties, "mix_out", NULL ); int length = mlt_producer_get_playtime( MLT_TRACTOR_PRODUCER( tractor ) ); - mlt_events_block( MLT_PLAYLIST_PROPERTIES( this ), this ); + mlt_events_block( MLT_PLAYLIST_PROPERTIES( self ), self ); if ( clip_a != NULL ) { @@ -1300,7 +1302,7 @@ else { mlt_producer cut = mlt_tractor_get_track( tractor, 0 ); - mlt_playlist_insert( this, cut, clip, -1, -1 ); + mlt_playlist_insert( self, cut, clip, -1, -1 ); clip ++; } @@ -1311,13 +1313,13 @@ else { mlt_producer cut = mlt_tractor_get_track( tractor, 1 ); - mlt_playlist_insert( this, cut, clip + 1, -1, -1 ); + mlt_playlist_insert( self, cut, clip + 1, -1, -1 ); } mlt_properties_set_data( properties, "mlt_mix", NULL, 0, NULL, NULL ); - mlt_playlist_remove( this, clip ); - mlt_events_unblock( MLT_PLAYLIST_PROPERTIES( this ), this ); - mlt_playlist_virtual_refresh( this ); + mlt_playlist_remove( self, clip ); + mlt_events_unblock( MLT_PLAYLIST_PROPERTIES( self ), self ); + mlt_playlist_virtual_refresh( self ); } return error; } @@ -1325,28 +1327,28 @@ /** Resize a mix clip. * * \private \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param clip the index of the playlist entry * \param in the new starting point * \param out the new ending point * \return true if there was an error */ -static int mlt_playlist_resize_mix( mlt_playlist this, int clip, int in, int out ) +static int mlt_playlist_resize_mix( mlt_playlist self, int clip, int in, int out ) { - int error = ( clip < 0 || clip >= this->count ); + int error = ( clip < 0 || clip >= self->count ); // Ensure that the clip request is actually a mix if ( error == 0 ) { - mlt_producer producer = mlt_producer_cut_parent( this->list[ clip ]->producer ); + mlt_producer producer = mlt_producer_cut_parent( self->list[ clip ]->producer ); mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); error = mlt_properties_get_data( properties, "mlt_mix", NULL ) == NULL; } if ( error == 0 ) { - playlist_entry *mix = this->list[ clip ]; + playlist_entry *mix = self->list[ clip ]; mlt_tractor tractor = ( mlt_tractor )mlt_producer_cut_parent( mix->producer ); mlt_properties properties = MLT_TRACTOR_PROPERTIES( tractor ); mlt_producer clip_a = mlt_properties_get_data( properties, "mix_in", NULL ); @@ -1355,7 +1357,7 @@ mlt_producer track_b = mlt_tractor_get_track( tractor, 1 ); int length = out - in + 1; int length_diff = length - mlt_producer_get_playtime( MLT_TRACTOR_PRODUCER( tractor ) ); - mlt_events_block( MLT_PLAYLIST_PROPERTIES( this ), this ); + mlt_events_block( MLT_PLAYLIST_PROPERTIES( self ), self ); if ( clip_a != NULL ) mlt_producer_set_in_and_out( clip_a, mlt_producer_get_in( clip_a ), mlt_producer_get_out( clip_a ) - length_diff ); @@ -1370,8 +1372,8 @@ mlt_properties_set_position( MLT_PRODUCER_PROPERTIES( mix->producer ), "length", out - in + 1 ); mlt_producer_set_in_and_out( mix->producer, in, out ); - mlt_events_unblock( MLT_PLAYLIST_PROPERTIES( this ), this ); - mlt_playlist_virtual_refresh( this ); + mlt_events_unblock( MLT_PLAYLIST_PROPERTIES( self ), self ); + mlt_playlist_virtual_refresh( self ); } return error; } @@ -1379,93 +1381,93 @@ /** Consolidate adjacent blank producers. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param keep_length set false to remove the last entry if it is blank */ -void mlt_playlist_consolidate_blanks( mlt_playlist this, int keep_length ) +void mlt_playlist_consolidate_blanks( mlt_playlist self, int keep_length ) { - if ( this != NULL ) + if ( self != NULL ) { int i = 0; - mlt_properties properties = MLT_PLAYLIST_PROPERTIES( this ); + mlt_properties properties = MLT_PLAYLIST_PROPERTIES( self ); mlt_events_block( properties, properties ); - for ( i = 1; i < this->count; i ++ ) + for ( i = 1; i < self->count; i ++ ) { - playlist_entry *left = this->list[ i - 1 ]; - playlist_entry *right = this->list[ i ]; + playlist_entry *left = self->list[ i - 1 ]; + playlist_entry *right = self->list[ i ]; if ( mlt_producer_is_blank( left->producer ) && mlt_producer_is_blank( right->producer ) ) { - mlt_playlist_resize_clip( this, i - 1, 0, left->frame_count + right->frame_count - 1 ); - mlt_playlist_remove( this, i -- ); + mlt_playlist_resize_clip( self, i - 1, 0, left->frame_count + right->frame_count - 1 ); + mlt_playlist_remove( self, i -- ); } } - if ( !keep_length && this->count > 0 ) + if ( !keep_length && self->count > 0 ) { - playlist_entry *last = this->list[ this->count - 1 ]; + playlist_entry *last = self->list[ self->count - 1 ]; if ( mlt_producer_is_blank( last->producer ) ) - mlt_playlist_remove( this, this->count - 1 ); + mlt_playlist_remove( self, self->count - 1 ); } mlt_events_unblock( properties, properties ); - mlt_playlist_virtual_refresh( this ); + mlt_playlist_virtual_refresh( self ); } } /** Determine if the specified clip index is a blank. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param clip the index of the playlist entry * \return true if there was an error */ -int mlt_playlist_is_blank( mlt_playlist this, int clip ) +int mlt_playlist_is_blank( mlt_playlist self, int clip ) { - return this == NULL || mlt_producer_is_blank( mlt_playlist_get_clip( this, clip ) ); + return self == NULL || mlt_producer_is_blank( mlt_playlist_get_clip( self, clip ) ); } /** Determine if the specified position is a blank. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param position a time relative to the start or end (negative) of the playlist * \return true if there was an error */ -int mlt_playlist_is_blank_at( mlt_playlist this, mlt_position position ) +int mlt_playlist_is_blank_at( mlt_playlist self, mlt_position position ) { - return this == NULL || mlt_producer_is_blank( mlt_playlist_get_clip_at( this, position ) ); + return self == NULL || mlt_producer_is_blank( mlt_playlist_get_clip_at( self, position ) ); } /** Replace the specified clip with a blank and return the clip. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param clip the index of the playlist entry * \return a producer or NULL if there was an error */ -mlt_producer mlt_playlist_replace_with_blank( mlt_playlist this, int clip ) +mlt_producer mlt_playlist_replace_with_blank( mlt_playlist self, int clip ) { mlt_producer producer = NULL; - if ( !mlt_playlist_is_blank( this, clip ) ) + if ( !mlt_playlist_is_blank( self, clip ) ) { - playlist_entry *entry = this->list[ clip ]; + playlist_entry *entry = self->list[ clip ]; int in = entry->frame_in; int out = entry->frame_out; - mlt_properties properties = MLT_PLAYLIST_PROPERTIES( this ); + mlt_properties properties = MLT_PLAYLIST_PROPERTIES( self ); producer = entry->producer; mlt_properties_inc_ref( MLT_PRODUCER_PROPERTIES( producer ) ); mlt_events_block( properties, properties ); - mlt_playlist_remove( this, clip ); - mlt_playlist_blank( this, out - in ); - mlt_playlist_move( this, this->count - 1, clip ); + mlt_playlist_remove( self, clip ); + mlt_playlist_blank( self, out - in ); + mlt_playlist_move( self, self->count - 1, clip ); mlt_events_unblock( properties, properties ); - mlt_playlist_virtual_refresh( this ); + mlt_playlist_virtual_refresh( self ); mlt_producer_set_in_and_out( producer, in, out ); } return producer; @@ -1474,124 +1476,124 @@ /** Insert blank space. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param clip the index of the new blank section * \param length the ending time of the new blank section (duration - 1) */ -void mlt_playlist_insert_blank( mlt_playlist this, int clip, int length ) +void mlt_playlist_insert_blank( mlt_playlist self, int clip, int length ) { - if ( this != NULL && length >= 0 ) + if ( self != NULL && length >= 0 ) { - mlt_properties properties = MLT_PLAYLIST_PROPERTIES( this ); + mlt_properties properties = MLT_PLAYLIST_PROPERTIES( self ); mlt_events_block( properties, properties ); - mlt_playlist_blank( this, length ); - mlt_playlist_move( this, this->count - 1, clip ); + mlt_playlist_blank( self, length ); + mlt_playlist_move( self, self->count - 1, clip ); mlt_events_unblock( properties, properties ); - mlt_playlist_virtual_refresh( this ); + mlt_playlist_virtual_refresh( self ); } } /** Resize a blank entry. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param position the time at which the blank entry exists relative to the start or end (negative) of the playlist. * \param length the additional amount of blank frames to add * \param find true to fist locate the blank after the clip at position */ -void mlt_playlist_pad_blanks( mlt_playlist this, mlt_position position, int length, int find ) +void mlt_playlist_pad_blanks( mlt_playlist self, mlt_position position, int length, int find ) { - if ( this != NULL && length != 0 ) + if ( self != NULL && length != 0 ) { - int clip = mlt_playlist_get_clip_index_at( this, position ); - mlt_properties properties = MLT_PLAYLIST_PROPERTIES( this ); + int clip = mlt_playlist_get_clip_index_at( self, position ); + mlt_properties properties = MLT_PLAYLIST_PROPERTIES( self ); mlt_events_block( properties, properties ); - if ( find && clip < this->count && !mlt_playlist_is_blank( this, clip ) ) + if ( find && clip < self->count && !mlt_playlist_is_blank( self, clip ) ) clip ++; - if ( clip < this->count && mlt_playlist_is_blank( this, clip ) ) + if ( clip < self->count && mlt_playlist_is_blank( self, clip ) ) { mlt_playlist_clip_info info; - mlt_playlist_get_clip_info( this, &info, clip ); + mlt_playlist_get_clip_info( self, &info, clip ); if ( info.frame_out + length > info.frame_in ) - mlt_playlist_resize_clip( this, clip, info.frame_in, info.frame_out + length ); + mlt_playlist_resize_clip( self, clip, info.frame_in, info.frame_out + length ); else - mlt_playlist_remove( this, clip ); + mlt_playlist_remove( self, clip ); } - else if ( find && clip < this->count && length > 0 ) + else if ( find && clip < self->count && length > 0 ) { - mlt_playlist_insert_blank( this, clip, length ); + mlt_playlist_insert_blank( self, clip, length ); } mlt_events_unblock( properties, properties ); - mlt_playlist_virtual_refresh( this ); + mlt_playlist_virtual_refresh( self ); } } /** Insert a clip at a specific time. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param position the time at which to insert * \param producer the producer to insert * \param mode true if you want to overwrite any blank section * \return true if there was an error */ -int mlt_playlist_insert_at( mlt_playlist this, mlt_position position, mlt_producer producer, int mode ) +int mlt_playlist_insert_at( mlt_playlist self, mlt_position position, mlt_producer producer, int mode ) { - int ret = this == NULL || position < 0 || producer == NULL; + int ret = self == NULL || position < 0 || producer == NULL; if ( ret == 0 ) { - mlt_properties properties = MLT_PLAYLIST_PROPERTIES( this ); + mlt_properties properties = MLT_PLAYLIST_PROPERTIES( self ); int length = mlt_producer_get_playtime( producer ); - int clip = mlt_playlist_get_clip_index_at( this, position ); + int clip = mlt_playlist_get_clip_index_at( self, position ); mlt_playlist_clip_info info; - mlt_playlist_get_clip_info( this, &info, clip ); - mlt_events_block( properties, this ); - if ( clip < this->count && mlt_playlist_is_blank( this, clip ) ) + mlt_playlist_get_clip_info( self, &info, clip ); + mlt_events_block( properties, self ); + if ( clip < self->count && mlt_playlist_is_blank( self, clip ) ) { // Split and move to new clip if need be - if ( position != info.start && mlt_playlist_split( this, clip, position - info.start - 1 ) == 0 ) - mlt_playlist_get_clip_info( this, &info, ++ clip ); + if ( position != info.start && mlt_playlist_split( self, clip, position - info.start - 1 ) == 0 ) + mlt_playlist_get_clip_info( self, &info, ++ clip ); // Split again if need be if ( length < info.frame_count ) - mlt_playlist_split( this, clip, length - 1 ); + mlt_playlist_split( self, clip, length - 1 ); // Remove - mlt_playlist_remove( this, clip ); + mlt_playlist_remove( self, clip ); // Insert - mlt_playlist_insert( this, producer, clip, -1, -1 ); + mlt_playlist_insert( self, producer, clip, -1, -1 ); ret = clip; } - else if ( clip < this->count ) + else if ( clip < self->count ) { if ( position > info.start + info.frame_count / 2 ) clip ++; - if ( mode == 1 && clip < this->count && mlt_playlist_is_blank( this, clip ) ) + if ( mode == 1 && clip < self->count && mlt_playlist_is_blank( self, clip ) ) { - mlt_playlist_get_clip_info( this, &info, clip ); + mlt_playlist_get_clip_info( self, &info, clip ); if ( length < info.frame_count ) - mlt_playlist_split( this, clip, length ); - mlt_playlist_remove( this, clip ); + mlt_playlist_split( self, clip, length ); + mlt_playlist_remove( self, clip ); } - mlt_playlist_insert( this, producer, clip, -1, -1 ); + mlt_playlist_insert( self, producer, clip, -1, -1 ); ret = clip; } else { if ( mode == 1 ) { if ( position == info.start ) - mlt_playlist_remove( this, clip ); + mlt_playlist_remove( self, clip ); else - mlt_playlist_blank( this, position - mlt_properties_get_int( properties, "length" ) - 1 ); + mlt_playlist_blank( self, position - mlt_properties_get_int( properties, "length" ) - 1 ); } - mlt_playlist_append( this, producer ); - ret = this->count - 1; + mlt_playlist_append( self, producer ); + ret = self->count - 1; } - mlt_events_unblock( properties, this ); - mlt_playlist_virtual_refresh( this ); + mlt_events_unblock( properties, self ); + mlt_playlist_virtual_refresh( self ); } else { @@ -1603,31 +1605,31 @@ /** Get the time at which the clip starts relative to the playlist. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param clip the index of the playlist entry * \return the starting time */ -int mlt_playlist_clip_start( mlt_playlist this, int clip ) +int mlt_playlist_clip_start( mlt_playlist self, int clip ) { mlt_playlist_clip_info info; - if ( mlt_playlist_get_clip_info( this, &info, clip ) == 0 ) + if ( mlt_playlist_get_clip_info( self, &info, clip ) == 0 ) return info.start; - return clip < 0 ? 0 : mlt_producer_get_playtime( MLT_PLAYLIST_PRODUCER( this ) ); + return clip < 0 ? 0 : mlt_producer_get_playtime( MLT_PLAYLIST_PRODUCER( self ) ); } /** Get the playable duration of the clip. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param clip the index of the playlist entry * \return the duration of the playlist entry */ -int mlt_playlist_clip_length( mlt_playlist this, int clip ) +int mlt_playlist_clip_length( mlt_playlist self, int clip ) { mlt_playlist_clip_info info; - if ( mlt_playlist_get_clip_info( this, &info, clip ) == 0 ) + if ( mlt_playlist_get_clip_info( self, &info, clip ) == 0 ) return info.frame_count; return 0; } @@ -1635,27 +1637,27 @@ /** Get the duration of a blank space. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param clip the index of the playlist entry * \param bounded the maximum number of blank entries or 0 for all * \return the duration of a blank section */ -int mlt_playlist_blanks_from( mlt_playlist this, int clip, int bounded ) +int mlt_playlist_blanks_from( mlt_playlist self, int clip, int bounded ) { int count = 0; mlt_playlist_clip_info info; - if ( this != NULL && clip < this->count ) + if ( self != NULL && clip < self->count ) { - mlt_playlist_get_clip_info( this, &info, clip ); - if ( mlt_playlist_is_blank( this, clip ) ) + mlt_playlist_get_clip_info( self, &info, clip ); + if ( mlt_playlist_is_blank( self, clip ) ) count += info.frame_count; if ( bounded == 0 ) - bounded = this->count; - for ( clip ++; clip < this->count && bounded >= 0; clip ++ ) + bounded = self->count; + for ( clip ++; clip < self->count && bounded >= 0; clip ++ ) { - mlt_playlist_get_clip_info( this, &info, clip ); - if ( mlt_playlist_is_blank( this, clip ) ) + mlt_playlist_get_clip_info( self, &info, clip ); + if ( mlt_playlist_is_blank( self, clip ) ) count += info.frame_count; else bounded --; @@ -1667,44 +1669,44 @@ /** Remove a portion of the playlist by time. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist * \param position the starting time * \param length the duration of time to remove * \return the new entry index at the position */ -int mlt_playlist_remove_region( mlt_playlist this, mlt_position position, int length ) +int mlt_playlist_remove_region( mlt_playlist self, mlt_position position, int length ) { - int index = mlt_playlist_get_clip_index_at( this, position ); - if ( index >= 0 && index < this->count ) + int index = mlt_playlist_get_clip_index_at( self, position ); + if ( index >= 0 && index < self->count ) { - mlt_properties properties = MLT_PLAYLIST_PROPERTIES( this ); - int clip_start = mlt_playlist_clip_start( this, index ); - int list_length = mlt_producer_get_playtime( MLT_PLAYLIST_PRODUCER( this ) ); - mlt_events_block( properties, this ); + mlt_properties properties = MLT_PLAYLIST_PROPERTIES( self ); + int clip_start = mlt_playlist_clip_start( self, index ); + int list_length = mlt_producer_get_playtime( MLT_PLAYLIST_PRODUCER( self ) ); + mlt_events_block( properties, self ); if ( position + length > list_length ) length -= ( position + length - list_length ); if ( clip_start < position ) { - mlt_playlist_split( this, index ++, position - clip_start - 1 ); + mlt_playlist_split( self, index ++, position - clip_start - 1 ); } while( length > 0 ) { - if ( mlt_playlist_clip_length( this, index ) > length ) - mlt_playlist_split( this, index, length - 1 ); - length -= mlt_playlist_clip_length( this, index ); - mlt_playlist_remove( this, index ); + if ( mlt_playlist_clip_length( self, index ) > length ) + mlt_playlist_split( self, index, length - 1 ); + length -= mlt_playlist_clip_length( self, index ); + mlt_playlist_remove( self, index ); } - mlt_playlist_consolidate_blanks( this, 0 ); - mlt_events_unblock( properties, this ); - mlt_playlist_virtual_refresh( this ); + mlt_playlist_consolidate_blanks( self, 0 ); + mlt_events_unblock( properties, self ); + mlt_playlist_virtual_refresh( self ); // Just to be sure, we'll get the clip index again... - index = mlt_playlist_get_clip_index_at( this, position ); + index = mlt_playlist_get_clip_index_at( self, position ); } return index; } @@ -1713,16 +1715,16 @@ * * \deprecated not implemented * \public \memberof mlt_playlist_s - * \param this + * \param self * \param position * \param length * \param new_position * \return */ -int mlt_playlist_move_region( mlt_playlist this, mlt_position position, int length, int new_position ) +int mlt_playlist_move_region( mlt_playlist self, mlt_position position, int length, int new_position ) { - if ( this != NULL ) + if ( self != NULL ) { } return 0; @@ -1748,13 +1750,13 @@ } // Get this mlt_playlist - mlt_playlist this = producer->child; + mlt_playlist self = producer->child; // Need to ensure the frame is deinterlaced when repeating 1 frame int progressive = 0; // Get the real producer - mlt_service real = mlt_playlist_virtual_seek( this, &progressive ); + mlt_service real = mlt_playlist_virtual_seek( self, &progressive ); // Check that we have a producer if ( real == NULL ) @@ -1784,7 +1786,7 @@ // Check if we're at the end of the clip mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); if ( mlt_properties_get_int( properties, "end_of_clip" ) ) - mlt_playlist_virtual_set_out( this ); + mlt_playlist_virtual_set_out( self ); // Set the consumer progressive property if ( progressive ) @@ -1814,24 +1816,24 @@ /** Close the playlist. * * \public \memberof mlt_playlist_s - * \param this a playlist + * \param self a playlist */ -void mlt_playlist_close( mlt_playlist this ) +void mlt_playlist_close( mlt_playlist self ) { - if ( this != NULL && mlt_properties_dec_ref( MLT_PLAYLIST_PROPERTIES( this ) ) <= 0 ) + if ( self != NULL && mlt_properties_dec_ref( MLT_PLAYLIST_PROPERTIES( self ) ) <= 0 ) { int i = 0; - this->parent.close = NULL; - for ( i = 0; i < this->count; i ++ ) + self->parent.close = NULL; + for ( i = 0; i < self->count; i ++ ) { - mlt_event_close( this->list[ i ]->event ); - mlt_producer_close( this->list[ i ]->producer ); - free( this->list[ i ] ); - } - mlt_producer_close( &this->blank ); - mlt_producer_close( &this->parent ); - free( this->list ); - free( this ); + mlt_event_close( self->list[ i ]->event ); + mlt_producer_close( self->list[ i ]->producer ); + free( self->list[ i ] ); + } + mlt_producer_close( &self->blank ); + mlt_producer_close( &self->parent ); + free( self->list ); + free( self ); } } diff -Nru mlt-0.6.2/src/framework/mlt_pool.c mlt-0.7.2/src/framework/mlt_pool.c --- mlt-0.6.2/src/framework/mlt_pool.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_pool.c 2011-05-02 05:59:12.000000000 +0000 @@ -72,48 +72,48 @@ static mlt_pool pool_init( int size ) { // Create the pool - mlt_pool this = calloc( 1, sizeof( struct mlt_pool_s ) ); + mlt_pool self = calloc( 1, sizeof( struct mlt_pool_s ) ); // Initialise it - if ( this != NULL ) + if ( self != NULL ) { // Initialise the mutex - pthread_mutex_init( &this->lock, NULL ); + pthread_mutex_init( &self->lock, NULL ); // Create the stack - this->stack = mlt_deque_init( ); + self->stack = mlt_deque_init( ); // Assign the size - this->size = size; + self->size = size; } // Return it - return this; + return self; } /** Get an item from the pool. * * \private \memberof mlt_pool_s - * \param this a pool + * \param self a pool * \return an opaque pointer */ -static void *pool_fetch( mlt_pool this ) +static void *pool_fetch( mlt_pool self ) { // We will generate a release object void *ptr = NULL; // Sanity check - if ( this != NULL ) + if ( self != NULL ) { // Lock the pool - pthread_mutex_lock( &this->lock ); + pthread_mutex_lock( &self->lock ); // Check if the stack is empty - if ( mlt_deque_count( this->stack ) != 0 ) + if ( mlt_deque_count( self->stack ) != 0 ) { // Pop the top of the stack - ptr = mlt_deque_pop_back( this->stack ); + ptr = mlt_deque_pop_back( self->stack ); // Assign the reference ( ( mlt_release )ptr )->references = 1; @@ -122,19 +122,19 @@ { // We need to generate a release item #ifdef linux - mlt_release release = memalign( 16, this->size ); + mlt_release release = memalign( 16, self->size ); #else - mlt_release release = malloc( this->size ); + mlt_release release = malloc( self->size ); #endif // Initialise it if ( release != NULL ) { // Increment the number of items allocated to this pool - this->count ++; + self->count ++; // Assign the pool - release->pool = this; + release->pool = self; // Assign the reference release->references = 1; @@ -145,7 +145,7 @@ } // Unlock the pool - pthread_mutex_unlock( &this->lock ); + pthread_mutex_unlock( &self->lock ); } // Return the generated release object @@ -167,18 +167,18 @@ mlt_release that = ( void * )(( char * )ptr - sizeof( struct mlt_release_s )); // Get the pool - mlt_pool this = that->pool; + mlt_pool self = that->pool; - if ( this != NULL ) + if ( self != NULL ) { // Lock the pool - pthread_mutex_lock( &this->lock ); + pthread_mutex_lock( &self->lock ); // Push the that back back on to the stack - mlt_deque_push_back( this->stack, ptr ); + mlt_deque_push_back( self->stack, ptr ); // Unlock the pool - pthread_mutex_unlock( &this->lock ); + pthread_mutex_unlock( &self->lock ); // Ensure that we don't clean up ptr = NULL; @@ -196,31 +196,31 @@ /** Destroy a pool. * * \private \memberof mlt_pool_s - * \param this a pool + * \param self a pool */ -static void pool_close( mlt_pool this ) +static void pool_close( mlt_pool self ) { - if ( this != NULL ) + if ( self != NULL ) { // We need to free up all items in the pool void *release = NULL; // Iterate through the stack until depleted - while ( ( release = mlt_deque_pop_back( this->stack ) ) != NULL ) + while ( ( release = mlt_deque_pop_back( self->stack ) ) != NULL ) { // We'll free this item now free( ( char * )release - sizeof( struct mlt_release_s ) ); } // We can now close the stack - mlt_deque_close( this->stack ); + mlt_deque_close( self->stack ); // Destroy the mutex - pthread_mutex_destroy( &this->lock ); + pthread_mutex_destroy( &self->lock ); // Close the pool - free( this ); + free( self ); } } @@ -339,20 +339,20 @@ for ( i = 0; i < mlt_properties_count( pools ); i ++ ) { // Get the pool - mlt_pool this = mlt_properties_get_data_at( pools, i, NULL ); + mlt_pool self = mlt_properties_get_data_at( pools, i, NULL ); // Pointer to unused memory void *release = NULL; // Lock the pool - pthread_mutex_lock( &this->lock ); + pthread_mutex_lock( &self->lock ); // We'll free all unused items now - while ( ( release = mlt_deque_pop_back( this->stack ) ) != NULL ) + while ( ( release = mlt_deque_pop_back( self->stack ) ) != NULL ) free( ( char * )release - sizeof( struct mlt_release_s ) ); // Unlock the pool - pthread_mutex_unlock( &this->lock ); + pthread_mutex_unlock( &self->lock ); } } diff -Nru mlt-0.6.2/src/framework/mlt_producer.c mlt-0.7.2/src/framework/mlt_producer.c --- mlt-0.6.2/src/framework/mlt_producer.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_producer.c 2011-05-02 05:59:12.000000000 +0000 @@ -34,9 +34,9 @@ /* Forward references. */ -static int producer_get_frame( mlt_service this, mlt_frame_ptr frame, int index ); -static void mlt_producer_property_changed( mlt_service owner, mlt_producer this, char *name ); -static void mlt_producer_service_changed( mlt_service owner, mlt_producer this ); +static int producer_get_frame( mlt_service self, mlt_frame_ptr frame, int index ); +static void mlt_producer_property_changed( mlt_service owner, mlt_producer self, char *name ); +static void mlt_producer_service_changed( mlt_service owner, mlt_producer self ); /* for debugging */ //#define _MLT_PRODUCER_CHECKS_ 1 @@ -48,15 +48,15 @@ /** Initialize a producer service. * * \public \memberof mlt_producer_s - * \param this the producer structure to initialize + * \param self the producer structure to initialize * \param child a pointer to the child object for the subclass * \return true if there was an error */ -int mlt_producer_init( mlt_producer this, void *child ) +int mlt_producer_init( mlt_producer self, void *child ) { // Check that we haven't received NULL - int error = this == NULL; + int error = self == NULL; // Continue if no error if ( error == 0 ) @@ -66,23 +66,23 @@ #endif // Initialise the producer - memset( this, 0, sizeof( struct mlt_producer_s ) ); + memset( self, 0, sizeof( struct mlt_producer_s ) ); // Associate with the child - this->child = child; + self->child = child; // Initialise the service - if ( mlt_service_init( &this->parent, this ) == 0 ) + if ( mlt_service_init( &self->parent, self ) == 0 ) { // The parent is the service - mlt_service parent = &this->parent; + mlt_service parent = &self->parent; // Define the parent close parent->close = ( mlt_destructor )mlt_producer_close; - parent->close_object = this; + parent->close_object = self; - // For convenience, we'll assume the close_object is this - this->close_object = this; + // For convenience, we'll assume the close_object is self + self->close_object = self; // Get the properties of the parent mlt_properties properties = MLT_SERVICE_PROPERTIES( parent ); @@ -91,7 +91,6 @@ mlt_properties_set( properties, "mlt_type", "mlt_producer" ); mlt_properties_set_position( properties, "_position", 0.0 ); mlt_properties_set_double( properties, "_frame", 0 ); - mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( NULL ) ); mlt_properties_set_double( properties, "_speed", 1.0 ); mlt_properties_set_position( properties, "in", 0 ); mlt_properties_set_position( properties, "out", 14999 ); @@ -102,8 +101,8 @@ // Override service get_frame parent->get_frame = producer_get_frame; - mlt_events_listen( properties, this, "service-changed", ( mlt_listener )mlt_producer_service_changed ); - mlt_events_listen( properties, this, "property-changed", ( mlt_listener )mlt_producer_property_changed ); + mlt_events_listen( properties, self, "service-changed", ( mlt_listener )mlt_producer_service_changed ); + mlt_events_listen( properties, self, "property-changed", ( mlt_listener )mlt_producer_property_changed ); mlt_events_register( properties, "producer-changed", NULL ); } } @@ -117,14 +116,14 @@ * * \private \memberof mlt_producer_s * \param owner a service (ignored) - * \param this the producer + * \param self the producer * \param name the property that changed */ -static void mlt_producer_property_changed( mlt_service owner, mlt_producer this, char *name ) +static void mlt_producer_property_changed( mlt_service owner, mlt_producer self, char *name ) { if ( !strcmp( name, "in" ) || !strcmp( name, "out" ) || !strcmp( name, "length" ) ) - mlt_events_fire( MLT_PRODUCER_PROPERTIES( mlt_producer_cut_parent( this ) ), "producer-changed", NULL ); + mlt_events_fire( MLT_PRODUCER_PROPERTIES( mlt_producer_cut_parent( self ) ), "producer-changed", NULL ); } /** Listener for service changes. @@ -133,12 +132,12 @@ * * \private \memberof mlt_producer_s * \param owner a service (ignored) - * \param this the producer + * \param self the producer */ -static void mlt_producer_service_changed( mlt_service owner, mlt_producer this ) +static void mlt_producer_service_changed( mlt_service owner, mlt_producer self ) { - mlt_events_fire( MLT_PRODUCER_PROPERTIES( mlt_producer_cut_parent( this ) ), "producer-changed", NULL ); + mlt_events_fire( MLT_PRODUCER_PROPERTIES( mlt_producer_cut_parent( self ) ), "producer-changed", NULL ); } /** Create and initialize a new producer. @@ -147,37 +146,44 @@ * \return the new producer */ -mlt_producer mlt_producer_new( ) +mlt_producer mlt_producer_new( mlt_profile profile ) { - mlt_producer this = malloc( sizeof( struct mlt_producer_s ) ); - mlt_producer_init( this, NULL ); - return this; + mlt_producer self = malloc( sizeof( struct mlt_producer_s ) ); + if ( self ) + { + if ( mlt_producer_init( self, NULL ) == 0 ) + { + mlt_properties_set_data( MLT_PRODUCER_PROPERTIES( self ), "_profile", profile, 0, NULL, NULL ); + mlt_properties_set_double( MLT_PRODUCER_PROPERTIES( self ), "aspect_ratio", mlt_profile_sar( profile ) ); + } + } + return self; } /** Determine if producer is a cut. * * \public \memberof mlt_producer_s - * \param this a producer - * \return true if \p this is a "cut" producer + * \param self a producer + * \return true if \p self is a "cut" producer * \see mlt_producer_cut */ -int mlt_producer_is_cut( mlt_producer this ) +int mlt_producer_is_cut( mlt_producer self ) { - return mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( this ), "_cut" ); + return mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( self ), "_cut" ); } /** Determine if producer is a mix. * * \public \memberof mlt_producer_s - * \param this a producer - * \return true if this is a "mix" producer + * \param self a producer + * \return true if \p self is a "mix" producer * \todo Define a mix producer. */ -int mlt_producer_is_mix( mlt_producer this ) +int mlt_producer_is_mix( mlt_producer self ) { - mlt_properties properties = this != NULL ? MLT_PRODUCER_PROPERTIES( this ) : NULL; + mlt_properties properties = self != NULL ? MLT_PRODUCER_PROPERTIES( self ) : NULL; mlt_tractor tractor = properties != NULL ? mlt_properties_get_data( properties, "mlt_mix", NULL ) : NULL; return tractor != NULL; } @@ -186,30 +192,30 @@ * * Blank producers should only appear as an item in a playlist. * \public \memberof mlt_producer_s - * \param this a producer - * \return true if this is a "blank" producer + * \param self a producer + * \return true if \p self is a "blank" producer * \see mlt_playlist_insert_blank */ -int mlt_producer_is_blank( mlt_producer this ) +int mlt_producer_is_blank( mlt_producer self ) { - return this == NULL || !strcmp( mlt_properties_get( MLT_PRODUCER_PROPERTIES( mlt_producer_cut_parent( this ) ), "resource" ), "blank" ); + return self == NULL || !strcmp( mlt_properties_get( MLT_PRODUCER_PROPERTIES( mlt_producer_cut_parent( self ) ), "resource" ), "blank" ); } /** Obtain the parent producer. * * \public \memberof mlt_producer_s - * \param this a producer - * \return either the parent producer if this is a "cut" producer or \p this otherwise. + * \param self a producer + * \return either the parent producer if \p self is a "cut" producer or \p self otherwise. */ -mlt_producer mlt_producer_cut_parent( mlt_producer this ) +mlt_producer mlt_producer_cut_parent( mlt_producer self ) { - mlt_properties properties = MLT_PRODUCER_PROPERTIES( this ); - if ( mlt_producer_is_cut( this ) ) + mlt_properties properties = MLT_PRODUCER_PROPERTIES( self ); + if ( mlt_producer_is_cut( self ) ) return mlt_properties_get_data( properties, "_cut_parent", NULL ); else - return this; + return self; } /** Create a cut of this producer. @@ -217,17 +223,17 @@ * A "cut" is a portion of another (parent) producer. * * \public \memberof mlt_producer_s - * \param this a producer + * \param self a producer * \param in the beginning * \param out the end * \return the new producer * \todo Expand on the value of a cut. */ -mlt_producer mlt_producer_cut( mlt_producer this, int in, int out ) +mlt_producer mlt_producer_cut( mlt_producer self, int in, int out ) { - mlt_producer result = mlt_producer_new( ); - mlt_producer parent = mlt_producer_cut_parent( this ); + mlt_producer result = mlt_producer_new( mlt_service_profile( MLT_PRODUCER_SERVICE( self ) ) ); + mlt_producer parent = mlt_producer_cut_parent( self ); mlt_properties properties = MLT_PRODUCER_PROPERTIES( result ); mlt_properties parent_props = MLT_PRODUCER_PROPERTIES( parent ); @@ -235,7 +241,7 @@ // Special case - allow for a cut of the entire producer (this will squeeze all other cuts to 0) if ( in <= 0 ) in = 0; - if ( ( out < 0 || out >= mlt_producer_get_length( parent ) ) && !mlt_producer_is_blank( this ) ) + if ( ( out < 0 || out >= mlt_producer_get_length( parent ) ) && !mlt_producer_is_blank( self ) ) out = mlt_producer_get_length( parent ) - 1; mlt_properties_inc_ref( parent_props ); @@ -251,70 +257,70 @@ /** Get the parent service object. * * \public \memberof mlt_producer_s - * \param this a producer + * \param self a producer * \return the service parent class * \see MLT_PRODUCER_SERVICE */ -mlt_service mlt_producer_service( mlt_producer this ) +mlt_service mlt_producer_service( mlt_producer self ) { - return this != NULL ? &this->parent : NULL; + return self != NULL ? &self->parent : NULL; } /** Get the producer properties. * * \public \memberof mlt_producer_s - * \param this a producer + * \param self a producer * \return the producer's property list * \see MLT_PRODUCER_PROPERTIES */ -mlt_properties mlt_producer_properties( mlt_producer this ) +mlt_properties mlt_producer_properties( mlt_producer self ) { - return MLT_SERVICE_PROPERTIES( &this->parent ); + return MLT_SERVICE_PROPERTIES( &self->parent ); } /** Seek to a specified position. * * \public \memberof mlt_producer_s - * \param this a producer + * \param self a producer * \param position set the "play head" position of the producer * \return false * \todo Document how the properties affect behavior. */ -int mlt_producer_seek( mlt_producer this, mlt_position position ) +int mlt_producer_seek( mlt_producer self, mlt_position position ) { // Determine eof handling - mlt_properties properties = MLT_PRODUCER_PROPERTIES( this ); + mlt_properties properties = MLT_PRODUCER_PROPERTIES( self ); char *eof = mlt_properties_get( properties, "eof" ); int use_points = 1 - mlt_properties_get_int( properties, "ignore_points" ); // Recursive behaviour for cuts - repositions parent and then repositions cut // hence no return on this condition - if ( mlt_producer_is_cut( this ) ) - mlt_producer_seek( mlt_producer_cut_parent( this ), position + mlt_producer_get_in( this ) ); + if ( mlt_producer_is_cut( self ) ) + mlt_producer_seek( mlt_producer_cut_parent( self ), position + mlt_producer_get_in( self ) ); // Check bounds - if ( position < 0 || mlt_producer_get_playtime( this ) == 0 ) + if ( position < 0 || mlt_producer_get_playtime( self ) == 0 ) { position = 0; } - else if ( use_points && ( eof == NULL || !strcmp( eof, "pause" ) ) && position >= mlt_producer_get_playtime( this ) ) + else if ( use_points && ( eof == NULL || !strcmp( eof, "pause" ) ) && position >= mlt_producer_get_playtime( self ) ) { - mlt_producer_set_speed( this, 0 ); - position = mlt_producer_get_playtime( this ) - 1; + mlt_producer_set_speed( self, 0 ); + position = mlt_producer_get_playtime( self ) - 1; } - else if ( use_points && !strcmp( eof, "loop" ) && position >= mlt_producer_get_playtime( this ) ) + else if ( use_points && !strcmp( eof, "loop" ) && position >= mlt_producer_get_playtime( self ) ) { - position = (int)position % (int)mlt_producer_get_playtime( this ); + position = (int)position % (int)mlt_producer_get_playtime( self ); } // Set the position - mlt_properties_set_position( MLT_PRODUCER_PROPERTIES( this ), "_position", position ); + mlt_properties_set_position( MLT_PRODUCER_PROPERTIES( self ), "_position", position ); // Calculate the absolute frame - mlt_properties_set_position( MLT_PRODUCER_PROPERTIES( this ), "_frame", use_points * mlt_producer_get_in( this ) + position ); + mlt_properties_set_position( MLT_PRODUCER_PROPERTIES( self ), "_frame", use_points * mlt_producer_get_in( self ) + position ); return 0; } @@ -322,50 +328,50 @@ /** Get the current position (relative to in point). * * \public \memberof mlt_producer_s - * \param this a producer + * \param self a producer * \return the position of the "play head" relative to its beginning */ -mlt_position mlt_producer_position( mlt_producer this ) +mlt_position mlt_producer_position( mlt_producer self ) { - return mlt_properties_get_position( MLT_PRODUCER_PROPERTIES( this ), "_position" ); + return mlt_properties_get_position( MLT_PRODUCER_PROPERTIES( self ), "_position" ); } /** Get the current position (relative to start of producer). * * \public \memberof mlt_producer_s - * \param this a producer + * \param self a producer * \return the position of the "play head" regardless of the in point */ -mlt_position mlt_producer_frame( mlt_producer this ) +mlt_position mlt_producer_frame( mlt_producer self ) { - return mlt_properties_get_position( MLT_PRODUCER_PROPERTIES( this ), "_frame" ); + return mlt_properties_get_position( MLT_PRODUCER_PROPERTIES( self ), "_frame" ); } /** Set the playing speed. * * \public \memberof mlt_producer_s - * \param this a producer + * \param self a producer * \param speed the new speed as a relative factor (1.0 = normal) * \return */ -int mlt_producer_set_speed( mlt_producer this, double speed ) +int mlt_producer_set_speed( mlt_producer self, double speed ) { - return mlt_properties_set_double( MLT_PRODUCER_PROPERTIES( this ), "_speed", speed ); + return mlt_properties_set_double( MLT_PRODUCER_PROPERTIES( self ), "_speed", speed ); } /** Get the playing speed. * * \public \memberof mlt_producer_s - * \param this a producer + * \param self a producer * \return the speed as a relative factor (1.0 = normal) */ -double mlt_producer_get_speed( mlt_producer this ) +double mlt_producer_get_speed( mlt_producer self ) { - return mlt_properties_get_double( MLT_PRODUCER_PROPERTIES( this ), "_speed" ); + return mlt_properties_get_double( MLT_PRODUCER_PROPERTIES( self ), "_speed" ); } /** Get the frames per second. @@ -373,13 +379,13 @@ * This is determined by the producer's profile. * * \public \memberof mlt_producer_s - * \param this a producer + * \param self a producer * \return the video refresh rate */ -double mlt_producer_get_fps( mlt_producer this ) +double mlt_producer_get_fps( mlt_producer self ) { - mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( this ) ); + mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( self ) ); return mlt_profile_fps( profile ); } @@ -392,26 +398,26 @@ * sample. * * \public \memberof mlt_producer_s - * \param this a producer + * \param self a producer * \param in the relative starting time; a negative value is the same as 0 * \param out the relative ending time; a negative value is the same as length - 1 * \return false */ -int mlt_producer_set_in_and_out( mlt_producer this, mlt_position in, mlt_position out ) +int mlt_producer_set_in_and_out( mlt_producer self, mlt_position in, mlt_position out ) { - mlt_properties properties = MLT_PRODUCER_PROPERTIES( this ); + mlt_properties properties = MLT_PRODUCER_PROPERTIES( self ); // Correct ins and outs if necessary if ( in < 0 ) in = 0; - else if ( in >= mlt_producer_get_length( this ) ) - in = mlt_producer_get_length( this ) - 1; + else if ( in >= mlt_producer_get_length( self ) ) + in = mlt_producer_get_length( self ) - 1; - if ( ( out < 0 || out >= mlt_producer_get_length( this ) ) && !mlt_producer_is_blank( this ) ) - out = mlt_producer_get_length( this ) - 1; - else if ( ( out < 0 || out >= mlt_producer_get_length( this ) ) && mlt_producer_is_blank( this ) ) - mlt_properties_set_position( MLT_PRODUCER_PROPERTIES( this ), "length", out + 1 ); + if ( ( out < 0 || out >= mlt_producer_get_length( self ) ) && !mlt_producer_is_blank( self ) ) + out = mlt_producer_get_length( self ) - 1; + else if ( ( out < 0 || out >= mlt_producer_get_length( self ) ) && mlt_producer_is_blank( self ) ) + mlt_properties_set_position( MLT_PRODUCER_PROPERTIES( self ), "length", out + 1 ); else if ( out < 0 ) out = 0; @@ -436,15 +442,15 @@ * Essentially, all 0 length cuts should be immediately removed by containers. * * \public \memberof mlt_producer_s - * \param this a producer + * \param self a producer * \return false */ -int mlt_producer_clear( mlt_producer this ) +int mlt_producer_clear( mlt_producer self ) { - if ( this != NULL ) + if ( self != NULL ) { - mlt_properties properties = MLT_PRODUCER_PROPERTIES( this ); + mlt_properties properties = MLT_PRODUCER_PROPERTIES( self ); mlt_events_block( properties, properties ); mlt_properties_set_position( properties, "in", 0 ); mlt_events_unblock( properties, properties ); @@ -456,37 +462,37 @@ /** Get the in point. * * \public \memberof mlt_producer_s - * \param this a producer + * \param self a producer * \return the in point */ -mlt_position mlt_producer_get_in( mlt_producer this ) +mlt_position mlt_producer_get_in( mlt_producer self ) { - return mlt_properties_get_position( MLT_PRODUCER_PROPERTIES( this ), "in" ); + return mlt_properties_get_position( MLT_PRODUCER_PROPERTIES( self ), "in" ); } /** Get the out point. * * \public \memberof mlt_producer_s - * \param this a producer + * \param self a producer * \return the out point */ -mlt_position mlt_producer_get_out( mlt_producer this ) +mlt_position mlt_producer_get_out( mlt_producer self ) { - return mlt_properties_get_position( MLT_PRODUCER_PROPERTIES( this ), "out" ); + return mlt_properties_get_position( MLT_PRODUCER_PROPERTIES( self ), "out" ); } /** Get the total play time. * * \public \memberof mlt_producer_s - * \param this a producer + * \param self a producer * \return the playable (based on in and out points) duration */ -mlt_position mlt_producer_get_playtime( mlt_producer this ) +mlt_position mlt_producer_get_playtime( mlt_producer self ) { - return mlt_producer_get_out( this ) - mlt_producer_get_in( this ) + 1; + return mlt_producer_get_out( self ) - mlt_producer_get_in( self ) + 1; } /** Get the total, unedited length of the producer. @@ -494,13 +500,13 @@ * The value returned by a live streaming producer is unknown. * * \public \memberof mlt_producer_s - * \param this a producer + * \param self a producer * \return the duration of the producer regardless of in and out points */ -mlt_position mlt_producer_get_length( mlt_producer this ) +mlt_position mlt_producer_get_length( mlt_producer self ) { - return mlt_properties_get_position( MLT_PRODUCER_PROPERTIES( this ), "length" ); + return mlt_properties_get_position( MLT_PRODUCER_PROPERTIES( self ), "length" ); } /** Prepare for next frame. @@ -509,13 +515,13 @@ * move the play out position in the reverse direction. * * \public \memberof mlt_producer_s - * \param this a producer + * \param self a producer */ -void mlt_producer_prepare_next( mlt_producer this ) +void mlt_producer_prepare_next( mlt_producer self ) { - if ( mlt_producer_get_speed( this ) != 0 ) - mlt_producer_seek( this, mlt_producer_position( this ) + mlt_producer_get_speed( this ) ); + if ( mlt_producer_get_speed( self ) != 0 ) + mlt_producer_seek( self, mlt_producer_position( self ) + mlt_producer_get_speed( self ) ); } /** Get a frame. @@ -537,45 +543,45 @@ static int producer_get_frame( mlt_service service, mlt_frame_ptr frame, int index ) { int result = 1; - mlt_producer this = service != NULL ? service->child : NULL; + mlt_producer self = service != NULL ? service->child : NULL; - if ( this != NULL && !mlt_producer_is_cut( this ) ) + if ( self != NULL && !mlt_producer_is_cut( self ) ) { // Get the properties of this producer - mlt_properties properties = MLT_PRODUCER_PROPERTIES( this ); + mlt_properties properties = MLT_PRODUCER_PROPERTIES( self ); // Determine eof handling - char *eof = mlt_properties_get( MLT_PRODUCER_PROPERTIES( this ), "eof" ); + char *eof = mlt_properties_get( MLT_PRODUCER_PROPERTIES( self ), "eof" ); // Get the speed of the producer - double speed = mlt_producer_get_speed( this ); + double speed = mlt_producer_get_speed( self ); // We need to use the clone if it's specified mlt_producer clone = mlt_properties_get_data( properties, "use_clone", NULL ); - // If no clone is specified, use this - clone = clone == NULL ? this : clone; + // If no clone is specified, use self + clone = clone == NULL ? self : clone; // A properly instatiated producer will have a get_frame method... - if ( this->get_frame == NULL || ( !strcmp( eof, "continue" ) && mlt_producer_position( this ) > mlt_producer_get_out( this ) ) ) + if ( self->get_frame == NULL || ( !strcmp( eof, "continue" ) && mlt_producer_position( self ) > mlt_producer_get_out( self ) ) ) { // Generate a test frame *frame = mlt_frame_init( service ); // Set the position - result = mlt_frame_set_position( *frame, mlt_producer_position( this ) ); + result = mlt_frame_set_position( *frame, mlt_producer_position( self ) ); // Mark as a test card mlt_properties_set_int( MLT_FRAME_PROPERTIES( *frame ), "test_image", 1 ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( *frame ), "test_audio", 1 ); // Calculate the next position - mlt_producer_prepare_next( this ); + mlt_producer_prepare_next( self ); } else { // Get the frame from the implementation - result = this->get_frame( clone, frame, index ); + result = self->get_frame( clone, frame, index ); } // Copy the fps and speed of the producer onto the frame @@ -586,33 +592,33 @@ if ( mlt_properties_get_data( properties, "_producer", NULL ) == NULL ) mlt_properties_set_data( properties, "_producer", service, 0, NULL, NULL ); } - else if ( this != NULL ) + else if ( self != NULL ) { // Get the speed of the cut - double speed = mlt_producer_get_speed( this ); + double speed = mlt_producer_get_speed( self ); - // Get the parent of this cut - mlt_producer parent = mlt_producer_cut_parent( this ); + // Get the parent of the cut + mlt_producer parent = mlt_producer_cut_parent( self ); // Get the properties of the parent mlt_properties parent_properties = MLT_PRODUCER_PROPERTIES( parent ); // Get the properties of the cut - mlt_properties properties = MLT_PRODUCER_PROPERTIES( this ); + mlt_properties properties = MLT_PRODUCER_PROPERTIES( self ); // Determine the clone index int clone_index = mlt_properties_get_int( properties, "_clone" ); // Determine the clone to use - mlt_producer clone = this; + mlt_producer clone = self; if ( clone_index > 0 ) { char key[ 25 ]; sprintf( key, "_clone.%d", clone_index - 1 ); - clone = mlt_properties_get_data( MLT_PRODUCER_PROPERTIES( mlt_producer_cut_parent( this ) ), key, NULL ); + clone = mlt_properties_get_data( MLT_PRODUCER_PROPERTIES( mlt_producer_cut_parent( self ) ), key, NULL ); if ( clone == NULL ) mlt_log( service, MLT_LOG_ERROR, "requested clone doesn't exist %d\n", clone_index ); - clone = clone == NULL ? this : clone; + clone = clone == NULL ? self : clone; } else { @@ -620,7 +626,7 @@ } // We need to seek to the correct position in the clone - mlt_producer_seek( clone, mlt_producer_get_in( this ) + mlt_properties_get_int( properties, "_position" ) ); + mlt_producer_seek( clone, mlt_producer_get_in( self ) + mlt_properties_get_int( properties, "_position" ) ); // Assign the clone property to the parent mlt_properties_set_data( parent_properties, "use_clone", clone, 0, NULL, NULL ); @@ -633,10 +639,10 @@ // This is useful and required by always_active transitions to determine in/out points of the cut if ( mlt_properties_get_data( MLT_FRAME_PROPERTIES( *frame ), "_producer", NULL ) == MLT_PRODUCER_SERVICE( parent ) ) - mlt_properties_set_data( MLT_FRAME_PROPERTIES( *frame ), "_producer", this, 0, NULL, NULL ); + mlt_properties_set_data( MLT_FRAME_PROPERTIES( *frame ), "_producer", self, 0, NULL, NULL ); mlt_properties_set_double( MLT_FRAME_PROPERTIES( *frame ), "_speed", speed ); - mlt_producer_prepare_next( this ); + mlt_producer_prepare_next( self ); } else { @@ -645,20 +651,22 @@ } // Pass on all meta properties from the producer/cut on to the frame - if ( *frame != NULL && this != NULL ) + if ( *frame != NULL && self != NULL ) { int i = 0; - mlt_properties p_props = MLT_PRODUCER_PROPERTIES( this ); + mlt_properties p_props = MLT_PRODUCER_PROPERTIES( self ); mlt_properties f_props = MLT_FRAME_PROPERTIES( *frame ); + mlt_properties_lock( p_props ); int count = mlt_properties_count( p_props ); for ( i = 0; i < count; i ++ ) { char *name = mlt_properties_get_name( p_props, i ); if ( !strncmp( name, "meta.", 5 ) ) - mlt_properties_set( f_props, name, mlt_properties_get( p_props, name ) ); + mlt_properties_set( f_props, name, mlt_properties_get_value( p_props, i ) ); else if ( !strncmp( name, "set.", 4 ) ) - mlt_properties_set( f_props, name + 4, mlt_properties_get( p_props, name ) ); + mlt_properties_set( f_props, name + 4, mlt_properties_get_value( p_props, i ) ); } + mlt_properties_unlock( p_props ); } return result; @@ -667,57 +675,57 @@ /** Attach a filter. * * \public \memberof mlt_producer_s - * \param this a producer + * \param self a producer * \param filter the filter to attach * \return true if there was an error */ -int mlt_producer_attach( mlt_producer this, mlt_filter filter ) +int mlt_producer_attach( mlt_producer self, mlt_filter filter ) { - return mlt_service_attach( MLT_PRODUCER_SERVICE( this ), filter ); + return mlt_service_attach( MLT_PRODUCER_SERVICE( self ), filter ); } /** Detach a filter. * * \public \memberof mlt_producer_s - * \param this a service + * \param self a service * \param filter the filter to detach * \return true if there was an error */ -int mlt_producer_detach( mlt_producer this, mlt_filter filter ) +int mlt_producer_detach( mlt_producer self, mlt_filter filter ) { - return mlt_service_detach( MLT_PRODUCER_SERVICE( this ), filter ); + return mlt_service_detach( MLT_PRODUCER_SERVICE( self ), filter ); } /** Retrieve a filter. * * \public \memberof mlt_producer_s - * \param this a service + * \param self a service * \param index which filter to retrieve * \return the filter or null if there was an error */ -mlt_filter mlt_producer_filter( mlt_producer this, int index ) +mlt_filter mlt_producer_filter( mlt_producer self, int index ) { - return mlt_service_filter( MLT_PRODUCER_SERVICE( this ), index ); + return mlt_service_filter( MLT_PRODUCER_SERVICE( self ), index ); } -/** Clone this producer. +/** Clone self producer. * * \private \memberof mlt_producer_s - * \param this a producer - * \return a new producer that is a copy of \p this + * \param self a producer + * \return a new producer that is a copy of \p self * \see mlt_producer_set_clones */ -static mlt_producer mlt_producer_clone( mlt_producer this ) +static mlt_producer mlt_producer_clone( mlt_producer self ) { mlt_producer clone = NULL; - mlt_properties properties = MLT_PRODUCER_PROPERTIES( this ); + mlt_properties properties = MLT_PRODUCER_PROPERTIES( self ); char *resource = mlt_properties_get( properties, "resource" ); char *service = mlt_properties_get( properties, "mlt_service" ); - mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( this ) ); + mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( self ) ); mlt_events_block( mlt_factory_event_object( ), mlt_factory_event_object( ) ); @@ -738,14 +746,14 @@ /** Create clones. * * \private \memberof mlt_producer_s - * \param this a producer + * \param self a producer * \param clones the number of copies to make * \see mlt_producer_optimise */ -static void mlt_producer_set_clones( mlt_producer this, int clones ) +static void mlt_producer_set_clones( mlt_producer self, int clones ) { - mlt_producer parent = mlt_producer_cut_parent( this ); + mlt_producer parent = mlt_producer_cut_parent( self ); mlt_properties properties = MLT_PRODUCER_PROPERTIES( parent ); int existing = mlt_properties_get_int( properties, "_clones" ); int i = 0; @@ -815,9 +823,9 @@ return diff >= 0 && diff < ( a->end - a->start + 1 ); } -static int push( mlt_parser this, int multitrack, int track, int position ) +static int push( mlt_parser self, int multitrack, int track, int position ) { - mlt_properties properties = mlt_parser_properties( this ); + mlt_properties properties = mlt_parser_properties( self ); mlt_deque stack = mlt_properties_get_data( properties, "stack", NULL ); track_info *info = malloc( sizeof( track_info ) ); info->multitrack = multitrack; @@ -828,37 +836,37 @@ return mlt_deque_push_back( stack, info ); } -static track_info *pop( mlt_parser this ) +static track_info *pop( mlt_parser self ) { - mlt_properties properties = mlt_parser_properties( this ); + mlt_properties properties = mlt_parser_properties( self ); mlt_deque stack = mlt_properties_get_data( properties, "stack", NULL ); return mlt_deque_pop_back( stack ); } -static track_info *peek( mlt_parser this ) +static track_info *peek( mlt_parser self ) { - mlt_properties properties = mlt_parser_properties( this ); + mlt_properties properties = mlt_parser_properties( self ); mlt_deque stack = mlt_properties_get_data( properties, "stack", NULL ); return mlt_deque_peek_back( stack ); } -static int on_start_multitrack( mlt_parser this, mlt_multitrack object ) +static int on_start_multitrack( mlt_parser self, mlt_multitrack object ) { - track_info *info = peek( this ); - return push( this, info->multitrack ++, info->track, info->position ); + track_info *info = peek( self ); + return push( self, info->multitrack ++, info->track, info->position ); } -static int on_start_track( mlt_parser this ) +static int on_start_track( mlt_parser self ) { - track_info *info = peek( this ); + track_info *info = peek( self ); info->position -= info->offset; info->length -= info->offset; - return push( this, info->multitrack, info->track ++, info->position ); + return push( self, info->multitrack, info->track ++, info->position ); } -static int on_start_producer( mlt_parser this, mlt_producer object ) +static int on_start_producer( mlt_parser self, mlt_producer object ) { - mlt_properties properties = mlt_parser_properties( this ); + mlt_properties properties = mlt_parser_properties( self ); mlt_properties producers = mlt_properties_get_data( properties, "producers", NULL ); mlt_producer parent = mlt_producer_cut_parent( object ); if ( mlt_service_identify( ( mlt_service )mlt_producer_cut_parent( object ) ) == producer_type && mlt_producer_is_cut( object ) ) @@ -868,7 +876,7 @@ clip_references *refs = NULL; char key[ 50 ]; int count = 0; - track_info *info = peek( this ); + track_info *info = peek( self ); sprintf( key, "%p", parent ); mlt_properties_get_data( producers, key, &count ); mlt_properties_set_data( producers, key, parent, ++ count, NULL, NULL ); @@ -887,10 +895,10 @@ return 0; } -static int on_end_track( mlt_parser this ) +static int on_end_track( mlt_parser self ) { - track_info *track = pop( this ); - track_info *multi = peek( this ); + track_info *track = pop( self ); + track_info *multi = peek( self ); multi->length += track->length; multi->position += track->length; multi->offset = track->length; @@ -898,10 +906,10 @@ return 0; } -static int on_end_multitrack( mlt_parser this, mlt_multitrack object ) +static int on_end_multitrack( mlt_parser self, mlt_multitrack object ) { - track_info *multi = pop( this ); - track_info *track = peek( this ); + track_info *multi = pop( self ); + track_info *track = peek( self ); track->position += multi->length; track->length += multi->length; free( multi ); @@ -912,11 +920,11 @@ * * \todo learn more about this * \public \memberof mlt_producer_s - * \param this a producer + * \param self a producer * \return true if there was an error */ -int mlt_producer_optimise( mlt_producer this ) +int mlt_producer_optimise( mlt_producer self ) { int error = 1; mlt_parser parser = mlt_parser_new( ); @@ -934,7 +942,7 @@ parser->on_start_multitrack = on_start_multitrack; parser->on_end_multitrack = on_end_multitrack; push( parser, 0, 0, 0 ); - mlt_parser_start( parser, MLT_PRODUCER_SERVICE( this ) ); + mlt_parser_start( parser, MLT_PRODUCER_SERVICE( self ) ); free( pop( parser ) ); for ( k = 0; k < mlt_properties_count( producers ); k ++ ) { @@ -942,7 +950,7 @@ int count = 0; int clones = 0; int max_clones = 0; - mlt_producer producer = mlt_properties_get_data( producers, name, &count ); + mlt_producer producer = mlt_properties_get_data_at( producers, k, &count ); if ( producer != NULL && count > 1 ) { clip_references *refs = mlt_properties_get_data( properties, name, &count ); @@ -994,37 +1002,37 @@ * function to NULL prior to calling this to avoid circular calls. * * \public \memberof mlt_producer_s - * \param this a producer + * \param self a producer */ -void mlt_producer_close( mlt_producer this ) +void mlt_producer_close( mlt_producer self ) { - if ( this != NULL && mlt_properties_dec_ref( MLT_PRODUCER_PROPERTIES( this ) ) <= 0 ) + if ( self != NULL && mlt_properties_dec_ref( MLT_PRODUCER_PROPERTIES( self ) ) <= 0 ) { - this->parent.close = NULL; + self->parent.close = NULL; - if ( this->close != NULL ) + if ( self->close != NULL ) { - this->close( this->close_object ); + self->close( self->close_object ); } else { - int destroy = mlt_producer_is_cut( this ); + int destroy = mlt_producer_is_cut( self ); #if _MLT_PRODUCER_CHECKS_ == 1 // Show debug info - mlt_properties_debug( MLT_PRODUCER_PROPERTIES( this ), "Producer closing", stderr ); + mlt_properties_debug( MLT_PRODUCER_PROPERTIES( self ), "Producer closing", stderr ); #endif #ifdef _MLT_PRODUCER_CHECKS_ // Show current stats - these should match when the app is closed - mlt_log( MLT_PRODUCER_SERVICE( this ), MLT_LOG_DEBUG, "Producers created %d, destroyed %d\n", producers_created, ++producers_destroyed ); + mlt_log( MLT_PRODUCER_SERVICE( self ), MLT_LOG_DEBUG, "Producers created %d, destroyed %d\n", producers_created, ++producers_destroyed ); #endif - mlt_service_close( &this->parent ); + mlt_service_close( &self->parent ); if ( destroy ) - free( this ); + free( self ); } } } diff -Nru mlt-0.6.2/src/framework/mlt_producer.h mlt-0.7.2/src/framework/mlt_producer.h --- mlt-0.6.2/src/framework/mlt_producer.h 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_producer.h 2011-05-02 05:59:12.000000000 +0000 @@ -26,6 +26,7 @@ #include "mlt_service.h" #include "mlt_filter.h" +#include "mlt_profile.h" /** \brief Producer abstract service class * @@ -88,7 +89,7 @@ #define MLT_PRODUCER_PROPERTIES( producer ) MLT_SERVICE_PROPERTIES( MLT_PRODUCER_SERVICE( producer ) ) extern int mlt_producer_init( mlt_producer self, void *child ); -extern mlt_producer mlt_producer_new( ); +extern mlt_producer mlt_producer_new( mlt_profile ); extern mlt_service mlt_producer_service( mlt_producer self ); extern mlt_properties mlt_producer_properties( mlt_producer self ); extern int mlt_producer_seek( mlt_producer self, mlt_position position ); diff -Nru mlt-0.6.2/src/framework/mlt_profile.c mlt-0.7.2/src/framework/mlt_profile.c --- mlt-0.6.2/src/framework/mlt_profile.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_profile.c 2011-05-02 05:59:12.000000000 +0000 @@ -90,9 +90,9 @@ * This will never return NULL as it uses the dv_pal settings as hard-coded fallback default. * * \public \memberof mlt_profile_s - * @param name the name of a profile settings file located in the standard location or + * \param name the name of a profile settings file located in the standard location or * the full path name to a profile settings file - * @return a profile + * \return a profile */ mlt_profile mlt_profile_init( const char *name ) @@ -163,8 +163,8 @@ /** Load a profile from specific file. * * \public \memberof mlt_profile_s - * @param file the full path name to a properties file - * @return a profile or NULL on error + * \param file the full path name to a properties file + * \return a profile or NULL on error */ mlt_profile mlt_profile_load_file( const char *file ) @@ -198,8 +198,8 @@ /** Load a profile from a properties object. * * \public \memberof mlt_profile_s - * @param properties a properties list - * @return a profile or NULL if out of memory + * \param properties a properties list + * \return a profile or NULL if out of memory */ mlt_profile mlt_profile_load_properties( mlt_properties properties ) @@ -228,8 +228,8 @@ /** Load an anonymous profile from string. * * \public \memberof mlt_profile_s - * @param string a newline-delimited list of properties as name=value pairs - * @return a profile or NULL if out of memory + * \param string a newline-delimited list of properties as name=value pairs + * \return a profile or NULL if out of memory */ mlt_profile mlt_profile_load_string( const char *string ) @@ -252,14 +252,14 @@ /** Get the video frame rate as a floating point value. * * \public \memberof mlt_profile_s - * @param aprofile a profile + * @param profile a profile * @return the frame rate */ -double mlt_profile_fps( mlt_profile aprofile ) +double mlt_profile_fps( mlt_profile profile ) { - if ( aprofile ) - return ( double ) aprofile->frame_rate_num / aprofile->frame_rate_den; + if ( profile ) + return ( double ) profile->frame_rate_num / profile->frame_rate_den; else return 0; } @@ -267,14 +267,14 @@ /** Get the sample aspect ratio as a floating point value. * * \public \memberof mlt_profile_s - * @param aprofile a profile - * @return the pixel aspect ratio + * \param profile a profile + * \return the pixel aspect ratio */ -double mlt_profile_sar( mlt_profile aprofile ) +double mlt_profile_sar( mlt_profile profile ) { - if ( aprofile ) - return ( double ) aprofile->sample_aspect_num / aprofile->sample_aspect_den; + if ( profile ) + return ( double ) profile->sample_aspect_num / profile->sample_aspect_den; else return 0; } @@ -282,14 +282,14 @@ /** Get the display aspect ratio as floating point value. * * \public \memberof mlt_profile_s - * @param aprofile a profile - * @return the image aspect ratio + * \param profile a profile + * \return the image aspect ratio */ -double mlt_profile_dar( mlt_profile aprofile ) +double mlt_profile_dar( mlt_profile profile ) { - if ( aprofile ) - return ( double ) aprofile->display_aspect_num / aprofile->display_aspect_den; + if ( profile ) + return ( double ) profile->display_aspect_num / profile->display_aspect_den; else return 0; } @@ -297,7 +297,7 @@ /** Free up the global profile resources. * * \public \memberof mlt_profile_s - * @param profile a profile + * \param profile a profile */ void mlt_profile_close( mlt_profile profile ) @@ -334,3 +334,59 @@ } return clone; } + + +/** Get the list of profiles. + * + * The caller MUST close the returned properties object! + * Each entry in the list is keyed on its name, and its value is another + * properties object that contains the attributes of the profile. + * \public \memberof mlt_profile_s + * \return a list of profiles + */ + +mlt_properties mlt_profile_list( ) +{ + char *filename = NULL; + const char *prefix = getenv( "MLT_PROFILES_PATH" ); + mlt_properties properties = mlt_properties_new(); + mlt_properties dir = mlt_properties_new(); + int sort = 1; + const char *wildcard = NULL; + int i; + + // Load from $prefix/share/mlt/profiles if no env var + if ( prefix == NULL ) + { + prefix = PREFIX; + filename = calloc( 1, strlen( prefix ) + strlen( PROFILES_DIR ) + 2 ); + strcpy( filename, prefix ); + if ( filename[ strlen( filename ) - 1 ] != '/' ) + filename[ strlen( filename ) ] = '/'; + strcat( filename, PROFILES_DIR ); + prefix = filename; + } + + mlt_properties_dir_list( dir, prefix, wildcard, sort ); + + for ( i = 0; i < mlt_properties_count( dir ); i++ ) + { + char *filename = mlt_properties_get_value( dir, i ); + char *profile_name = basename( filename ); + if ( profile_name[0] != '.' && strcmp( profile_name, "Makefile" ) && + profile_name[ strlen( profile_name ) - 1 ] != '~' ) + { + mlt_properties profile = mlt_properties_load( filename ); + if ( profile ) + { + mlt_properties_set_data( properties, profile_name, profile, 0, + (mlt_destructor) mlt_properties_close, NULL ); + } + } + } + mlt_properties_close( dir ); + if ( filename ) + free( filename ); + + return properties; +} diff -Nru mlt-0.6.2/src/framework/mlt_profile.h mlt-0.7.2/src/framework/mlt_profile.h --- mlt-0.6.2/src/framework/mlt_profile.h 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_profile.h 2011-05-02 05:59:12.000000000 +0000 @@ -55,4 +55,5 @@ extern double mlt_profile_dar( mlt_profile profile ); extern void mlt_profile_close( mlt_profile profile ); extern mlt_profile mlt_profile_clone( mlt_profile profile ); +extern mlt_properties mlt_profile_list( ); #endif diff -Nru mlt-0.6.2/src/framework/mlt_properties.c mlt-0.7.2/src/framework/mlt_properties.c --- mlt-0.6.2/src/framework/mlt_properties.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_properties.c 2011-05-02 05:59:12.000000000 +0000 @@ -64,14 +64,14 @@ * * This does allocate its ::property_list, and it adds a reference count. * \public \memberof mlt_properties_s - * \param this the properties structure to initialize + * \param self the properties structure to initialize * \param child an opaque pointer to a subclass object * \return true if failed */ -int mlt_properties_init( mlt_properties this, void *child ) +int mlt_properties_init( mlt_properties self, void *child ) { - if ( this != NULL ) + if ( self != NULL ) { #ifdef _MLT_PROPERTY_CHECKS_ // Increment number of properties created @@ -79,21 +79,21 @@ #endif // NULL all methods - memset( this, 0, sizeof( struct mlt_properties_s ) ); + memset( self, 0, sizeof( struct mlt_properties_s ) ); // Assign the child of the object - this->child = child; + self->child = child; // Allocate the local structure - this->local = calloc( sizeof( property_list ), 1 ); + self->local = calloc( sizeof( property_list ), 1 ); // Increment the ref count - ( ( property_list * )this->local )->ref_count = 1; - pthread_mutex_init( &( ( property_list * )this->local )->mutex, NULL );; + ( ( property_list * )self->local )->ref_count = 1; + pthread_mutex_init( &( ( property_list * )self->local )->mutex, NULL );; } // Check that initialisation was successful - return this != NULL && this->local == NULL; + return self != NULL && self->local == NULL; } /** Create a properties object. @@ -107,13 +107,13 @@ mlt_properties mlt_properties_new( ) { // Construct a standalone properties object - mlt_properties this = calloc( sizeof( struct mlt_properties_s ), 1 ); + mlt_properties self = calloc( sizeof( struct mlt_properties_s ), 1 ); - // Initialise this - mlt_properties_init( this, NULL ); + // Initialise self + mlt_properties_init( self, NULL ); // Return the pointer - return this; + return self; } /** Create a properties object by reading a .properties text file. @@ -128,9 +128,9 @@ mlt_properties mlt_properties_load( const char *filename ) { // Construct a standalone properties object - mlt_properties this = mlt_properties_new( ); + mlt_properties self = mlt_properties_new( ); - if ( this != NULL ) + if ( self != NULL ) { // Open the file FILE *file = fopen( filename, "r" ); @@ -163,7 +163,7 @@ // Parse and set the property if ( strcmp( temp, "" ) && temp[ 0 ] != '#' ) - mlt_properties_parse( this, temp ); + mlt_properties_parse( self, temp ); } // Close the file @@ -172,7 +172,7 @@ } // Return the pointer - return this; + return self; } /** Generate a hash key. @@ -191,22 +191,22 @@ return hash; } -/** Copy a serializable property to properties list that is mirroring this one. +/** Copy a serializable property to a properties list that is mirroring this one. * * Special case - when a container (such as loader) is protecting another * producer, we need to ensure that properties are passed through to the * real producer. * \private \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the name of the property to copy */ -static inline void mlt_properties_do_mirror( mlt_properties this, const char *name ) +static inline void mlt_properties_do_mirror( mlt_properties self, const char *name ) { - property_list *list = this->local; + property_list *list = self->local; if ( list->mirror != NULL ) { - char *value = mlt_properties_get( this, name ); + char *value = mlt_properties_get( self, name ); if ( value != NULL ) mlt_properties_set( list->mirror, name, value ); } @@ -215,16 +215,16 @@ /** Increment the reference count. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \return the new reference count */ -int mlt_properties_inc_ref( mlt_properties this ) +int mlt_properties_inc_ref( mlt_properties self ) { int result = 0; - if ( this != NULL ) + if ( self != NULL ) { - property_list *list = this->local; + property_list *list = self->local; pthread_mutex_lock( &list->mutex ); result = ++ list->ref_count; pthread_mutex_unlock( &list->mutex ); @@ -235,16 +235,16 @@ /** Decrement the reference count. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \return the new reference count */ -int mlt_properties_dec_ref( mlt_properties this ) +int mlt_properties_dec_ref( mlt_properties self ) { int result = 0; - if ( this != NULL ) + if ( self != NULL ) { - property_list *list = this->local; + property_list *list = self->local; pthread_mutex_lock( &list->mutex ); result = -- list->ref_count; pthread_mutex_unlock( &list->mutex ); @@ -255,15 +255,15 @@ /** Get the reference count. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \return the current reference count */ -int mlt_properties_ref_count( mlt_properties this ) +int mlt_properties_ref_count( mlt_properties self ) { - if ( this != NULL ) + if ( self != NULL ) { - property_list *list = this->local; + property_list *list = self->local; return list->ref_count; } return 0; @@ -275,24 +275,24 @@ * call this before setting the properties that you wish to copy. * \public \memberof mlt_properties_s * \param that the properties which will receive copies of the properties as they are set. - * \param this the properties to mirror + * \param self the properties to mirror */ -void mlt_properties_mirror( mlt_properties this, mlt_properties that ) +void mlt_properties_mirror( mlt_properties self, mlt_properties that ) { - property_list *list = this->local; + property_list *list = self->local; list->mirror = that; } /** Copy all serializable properties to another properties list. * * \public \memberof mlt_properties_s - * \param this The properties to copy to + * \param self The properties to copy to * \param that The properties to copy from * \return false */ -int mlt_properties_inherit( mlt_properties this, mlt_properties that ) +int mlt_properties_inherit( mlt_properties self, mlt_properties that ) { int count = mlt_properties_count( that ); int i = 0; @@ -302,7 +302,7 @@ if ( value != NULL ) { char *name = mlt_properties_get_name( that, i ); - mlt_properties_set( this, name, value ); + mlt_properties_set( self, name, value ); } } return 0; @@ -311,13 +311,13 @@ /** Pass all serializable properties that match a prefix to another properties object * * \public \memberof mlt_properties_s - * \param this the properties to copy to + * \param self the properties to copy to * \param that The properties to copy from * \param prefix the property names to match (required) * \return false */ -int mlt_properties_pass( mlt_properties this, mlt_properties that, const char *prefix ) +int mlt_properties_pass( mlt_properties self, mlt_properties that, const char *prefix ) { int count = mlt_properties_count( that ); int length = strlen( prefix ); @@ -329,7 +329,7 @@ { char *value = mlt_properties_get_value( that, i ); if ( value != NULL ) - mlt_properties_set( this, name + length, value ); + mlt_properties_set( self, name + length, value ); } } return 0; @@ -338,18 +338,20 @@ /** Locate a property by name. * * \private \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to lookup by name * \return the property or NULL for failure */ -static inline mlt_property mlt_properties_find( mlt_properties this, const char *name ) +static inline mlt_property mlt_properties_find( mlt_properties self, const char *name ) { - property_list *list = this->local; + property_list *list = self->local; mlt_property value = NULL; int key = generate_hash( name ); - int i = list->hash[ key ] - 1; + mlt_properties_lock( self ); + + int i = list->hash[ key ] - 1; if ( i >= 0 ) { // Check if we're hashed @@ -363,6 +365,7 @@ if ( name[ 0 ] == list->name[ i ][ 0 ] && !strcmp( list->name[ i ], name ) ) value = list->value[ i ]; } + mlt_properties_unlock( self ); return value; } @@ -370,15 +373,18 @@ /** Add a new property. * * \private \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the name of the new property * \return the new property */ -static mlt_property mlt_properties_add( mlt_properties this, const char *name ) +static mlt_property mlt_properties_add( mlt_properties self, const char *name ) { - property_list *list = this->local; + property_list *list = self->local; int key = generate_hash( name ); + mlt_property result; + + mlt_properties_lock( self ); // Check that we have space and resize if necessary if ( list->count == list->size ) @@ -397,25 +403,29 @@ list->hash[ key ] = list->count + 1; // Return and increment count accordingly - return list->value[ list->count ++ ]; + result = list->value[ list->count ++ ]; + + mlt_properties_unlock( self ); + + return result; } /** Fetch a property by name and add one if not found. * * \private \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to lookup or add * \return the property */ -static mlt_property mlt_properties_fetch( mlt_properties this, const char *name ) +static mlt_property mlt_properties_fetch( mlt_properties self, const char *name ) { // Try to find an existing property first - mlt_property property = mlt_properties_find( this, name ); + mlt_property property = mlt_properties_find( self, name ); // If it wasn't found, create one if ( property == NULL ) - property = mlt_properties_add( this, name ); + property = mlt_properties_add( self, name ); // Return the property return property; @@ -425,19 +435,19 @@ * * \public \memberof mlt_properties_s * \author Zach - * \param this the properties to copy to + * \param self the properties to copy to * \param that the properties to copy from * \param name the name of the property to copy */ -void mlt_properties_pass_property( mlt_properties this, mlt_properties that, const char *name ) +void mlt_properties_pass_property( mlt_properties self, mlt_properties that, const char *name ) { // Make sure the source property isn't null. mlt_property that_prop = mlt_properties_find( that, name ); if( that_prop == NULL ) return; - mlt_property_pass( mlt_properties_fetch( this, name ), that_prop ); + mlt_property_pass( mlt_properties_fetch( self, name ), that_prop ); } /** Copy all properties specified in a comma-separated list to another properties list. @@ -445,14 +455,14 @@ * White space is also a delimiter. * \public \memberof mlt_properties_s * \author Zach - * \param this the properties to copy to + * \param self the properties to copy to * \param that the properties to copy from * \param list a delimited list of property names * \return false */ -int mlt_properties_pass_list( mlt_properties this, mlt_properties that, const char *list ) +int mlt_properties_pass_list( mlt_properties self, mlt_properties that, const char *list ) { char *props = strdup( list ); char *ptr = props; @@ -468,7 +478,7 @@ else ptr[count] = '\0'; // Make it a real string - mlt_properties_pass_property( this, that, ptr ); + mlt_properties_pass_property( self, that, ptr ); ptr += count + 1; ptr += strspn( ptr, delim ); @@ -484,18 +494,18 @@ * * This makes a copy of the string value you supply. * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to set * \param value the property's new value * \return true if error */ -int mlt_properties_set( mlt_properties this, const char *name, const char *value ) +int mlt_properties_set( mlt_properties self, const char *name, const char *value ) { int error = 1; // Fetch the property to work with - mlt_property property = mlt_properties_fetch( this, name ); + mlt_property property = mlt_properties_fetch( self, name ); // Set it if not NULL if ( property == NULL ) @@ -505,12 +515,12 @@ else if ( value == NULL ) { error = mlt_property_set_string( property, value ); - mlt_properties_do_mirror( this, name ); + mlt_properties_do_mirror( self, name ); } else if ( *value != '@' ) { error = mlt_property_set_string( property, value ); - mlt_properties_do_mirror( this, name ); + mlt_properties_do_mirror( self, name ); } else if ( value[ 0 ] == '@' ) { @@ -534,7 +544,7 @@ if ( isdigit( id[ 0 ] ) ) current = atof( id ); else - current = mlt_properties_get_double( this, id ); + current = mlt_properties_get_double( self, id ); // Apply the operation switch( op ) @@ -558,10 +568,10 @@ } error = mlt_property_set_double( property, total ); - mlt_properties_do_mirror( this, name ); + mlt_properties_do_mirror( self, name ); } - mlt_events_fire( this, "property-changed", name, NULL ); + mlt_events_fire( self, "property-changed", name, NULL ); return error; } @@ -570,16 +580,16 @@ * * This makes a copy of the string value you supply. * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to set * \param value the string value to set or NULL to use the default * \param def the default string if value is NULL * \return true if error */ -int mlt_properties_set_or_default( mlt_properties this, const char *name, const char *value, const char *def ) +int mlt_properties_set_or_default( mlt_properties self, const char *name, const char *value, const char *def ) { - return mlt_properties_set( this, name, value == NULL ? def : value ); + return mlt_properties_set( self, name, value == NULL ? def : value ); } /** Get a string value by name. @@ -587,14 +597,14 @@ * Do not free the returned string. It's lifetime is controlled by the property * and this properties object. * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to get * \return the property's string value or NULL if it does not exist */ -char *mlt_properties_get( mlt_properties this, const char *name ) +char *mlt_properties_get( mlt_properties self, const char *name ) { - mlt_property value = mlt_properties_find( this, name ); + mlt_property value = mlt_properties_find( self, name ); return value == NULL ? NULL : mlt_property_get_string( value ); } @@ -602,14 +612,14 @@ * * Do not free the returned string. * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param index the numeric index of the property * \return the name of the property or NULL if index is out of range */ -char *mlt_properties_get_name( mlt_properties this, int index ) +char *mlt_properties_get_name( mlt_properties self, int index ) { - property_list *list = this->local; + property_list *list = self->local; if ( index >= 0 && index < list->count ) return list->name[ index ]; return NULL; @@ -619,14 +629,14 @@ * * Do not free the returned string. * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param index the numeric index of the property * \return the property value as a string or NULL if the index is out of range */ -char *mlt_properties_get_value( mlt_properties this, int index ) +char *mlt_properties_get_value( mlt_properties self, int index ) { - property_list *list = this->local; + property_list *list = self->local; if ( index >= 0 && index < list->count ) return mlt_property_get_string( list->value[ index ] ); return NULL; @@ -637,14 +647,14 @@ * Do not free the returned pointer if you supplied a destructor function when you * set this property. * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param index the numeric index of the property * \param[out] size the size of the binary data in bytes or NULL if the index is out of range */ -void *mlt_properties_get_data_at( mlt_properties this, int index, int *size ) +void *mlt_properties_get_data_at( mlt_properties self, int index, int *size ) { - property_list *list = this->local; + property_list *list = self->local; if ( index >= 0 && index < list->count ) return mlt_property_get_data( list->value[ index ], size ); return NULL; @@ -653,25 +663,25 @@ /** Return the number of items in the list. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \return the number of property objects */ -int mlt_properties_count( mlt_properties this ) +int mlt_properties_count( mlt_properties self ) { - property_list *list = this->local; + property_list *list = self->local; return list->count; } /** Set a value by parsing a name=value string. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param namevalue a string containing name and value delimited by '=' * \return true if there was an error */ -int mlt_properties_parse( mlt_properties this, const char *namevalue ) +int mlt_properties_parse( mlt_properties self, const char *namevalue ) { char *name = strdup( namevalue ); char *value = NULL; @@ -699,7 +709,7 @@ value = strdup( "" ); } - error = mlt_properties_set( this, name, value ); + error = mlt_properties_set( self, name, value ); free( name ); free( value ); @@ -710,41 +720,41 @@ /** Get an integer associated to the name. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to get * \return The integer value, 0 if not found (which may also be a legitimate value) */ -int mlt_properties_get_int( mlt_properties this, const char *name ) +int mlt_properties_get_int( mlt_properties self, const char *name ) { - mlt_property value = mlt_properties_find( this, name ); + mlt_property value = mlt_properties_find( self, name ); return value == NULL ? 0 : mlt_property_get_int( value ); } /** Set a property to an integer value. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to set * \param value the integer * \return true if error */ -int mlt_properties_set_int( mlt_properties this, const char *name, int value ) +int mlt_properties_set_int( mlt_properties self, const char *name, int value ) { int error = 1; // Fetch the property to work with - mlt_property property = mlt_properties_fetch( this, name ); + mlt_property property = mlt_properties_fetch( self, name ); // Set it if not NULL if ( property != NULL ) { error = mlt_property_set_int( property, value ); - mlt_properties_do_mirror( this, name ); + mlt_properties_do_mirror( self, name ); } - mlt_events_fire( this, "property-changed", name, NULL ); + mlt_events_fire( self, "property-changed", name, NULL ); return error; } @@ -752,41 +762,41 @@ /** Get a 64-bit integer associated to the name. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to get * \return the integer value, 0 if not found (which may also be a legitimate value) */ -int64_t mlt_properties_get_int64( mlt_properties this, const char *name ) +int64_t mlt_properties_get_int64( mlt_properties self, const char *name ) { - mlt_property value = mlt_properties_find( this, name ); + mlt_property value = mlt_properties_find( self, name ); return value == NULL ? 0 : mlt_property_get_int64( value ); } /** Set a property to a 64-bit integer value. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to set * \param value the integer * \return true if error */ -int mlt_properties_set_int64( mlt_properties this, const char *name, int64_t value ) +int mlt_properties_set_int64( mlt_properties self, const char *name, int64_t value ) { int error = 1; // Fetch the property to work with - mlt_property property = mlt_properties_fetch( this, name ); + mlt_property property = mlt_properties_fetch( self, name ); // Set it if not NULL if ( property != NULL ) { error = mlt_property_set_int64( property, value ); - mlt_properties_do_mirror( this, name ); + mlt_properties_do_mirror( self, name ); } - mlt_events_fire( this, "property-changed", name, NULL ); + mlt_events_fire( self, "property-changed", name, NULL ); return error; } @@ -794,41 +804,41 @@ /** Get a floating point value associated to the name. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to get * \return the floating point, 0 if not found (which may also be a legitimate value) */ -double mlt_properties_get_double( mlt_properties this, const char *name ) +double mlt_properties_get_double( mlt_properties self, const char *name ) { - mlt_property value = mlt_properties_find( this, name ); + mlt_property value = mlt_properties_find( self, name ); return value == NULL ? 0 : mlt_property_get_double( value ); } /** Set a property to a floating point value. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to set * \param value the floating point value * \return true if error */ -int mlt_properties_set_double( mlt_properties this, const char *name, double value ) +int mlt_properties_set_double( mlt_properties self, const char *name, double value ) { int error = 1; // Fetch the property to work with - mlt_property property = mlt_properties_fetch( this, name ); + mlt_property property = mlt_properties_fetch( self, name ); // Set it if not NULL if ( property != NULL ) { error = mlt_property_set_double( property, value ); - mlt_properties_do_mirror( this, name ); + mlt_properties_do_mirror( self, name ); } - mlt_events_fire( this, "property-changed", name, NULL ); + mlt_events_fire( self, "property-changed", name, NULL ); return error; } @@ -836,41 +846,41 @@ /** Get a position value associated to the name. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to get * \return the position, 0 if not found (which may also be a legitimate value) */ -mlt_position mlt_properties_get_position( mlt_properties this, const char *name ) +mlt_position mlt_properties_get_position( mlt_properties self, const char *name ) { - mlt_property value = mlt_properties_find( this, name ); + mlt_property value = mlt_properties_find( self, name ); return value == NULL ? 0 : mlt_property_get_position( value ); } /** Set a property to a position value. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to get * \param value the position * \return true if error */ -int mlt_properties_set_position( mlt_properties this, const char *name, mlt_position value ) +int mlt_properties_set_position( mlt_properties self, const char *name, mlt_position value ) { int error = 1; // Fetch the property to work with - mlt_property property = mlt_properties_fetch( this, name ); + mlt_property property = mlt_properties_fetch( self, name ); // Set it if not NULL if ( property != NULL ) { error = mlt_property_set_position( property, value ); - mlt_properties_do_mirror( this, name ); + mlt_properties_do_mirror( self, name ); } - mlt_events_fire( this, "property-changed", name, NULL ); + mlt_events_fire( self, "property-changed", name, NULL ); return error; } @@ -880,41 +890,41 @@ * Do not free the returned pointer if you supplied a destructor function * when you set this property. * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to get * \param[out] length The size of the binary data in bytes, if available (often it is not, you should know) */ -void *mlt_properties_get_data( mlt_properties this, const char *name, int *length ) +void *mlt_properties_get_data( mlt_properties self, const char *name, int *length ) { - mlt_property value = mlt_properties_find( this, name ); + mlt_property value = mlt_properties_find( self, name ); return value == NULL ? NULL : mlt_property_get_data( value, length ); } /** Store binary data as a property. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param name the property to set * \param value an opaque pointer to binary data * \param length the size of the binary data in bytes (optional) - * \param destroy a function to dellacate the binary data when the property is closed (optional) + * \param destroy a function to deallocate the binary data when the property is closed (optional) * \param serialise a function that can serialize the binary data as text (optional) * \return true if error */ -int mlt_properties_set_data( mlt_properties this, const char *name, void *value, int length, mlt_destructor destroy, mlt_serialiser serialise ) +int mlt_properties_set_data( mlt_properties self, const char *name, void *value, int length, mlt_destructor destroy, mlt_serialiser serialise ) { int error = 1; // Fetch the property to work with - mlt_property property = mlt_properties_fetch( this, name ); + mlt_property property = mlt_properties_fetch( self, name ); // Set it if not NULL if ( property != NULL ) error = mlt_property_set_data( property, value, length, destroy, serialise ); - mlt_events_fire( this, "property-changed", name, NULL ); + mlt_events_fire( self, "property-changed", name, NULL ); return error; } @@ -922,22 +932,23 @@ /** Rename a property. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param source the property to rename * \param dest the new name * \return true if the name is already in use */ -int mlt_properties_rename( mlt_properties this, const char *source, const char *dest ) +int mlt_properties_rename( mlt_properties self, const char *source, const char *dest ) { - mlt_property value = mlt_properties_find( this, dest ); + mlt_property value = mlt_properties_find( self, dest ); if ( value == NULL ) { - property_list *list = this->local; + property_list *list = self->local; int i = 0; // Locate the item + mlt_properties_lock( self ); for ( i = 0; i < list->count; i ++ ) { if ( !strcmp( list->name[ i ], source ) ) @@ -948,6 +959,7 @@ break; } } + mlt_properties_unlock( self ); } return value != NULL; @@ -956,41 +968,41 @@ /** Dump the properties to a file handle. * * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param output a file handle */ -void mlt_properties_dump( mlt_properties this, FILE *output ) +void mlt_properties_dump( mlt_properties self, FILE *output ) { - property_list *list = this->local; + property_list *list = self->local; int i = 0; for ( i = 0; i < list->count; i ++ ) - if ( mlt_properties_get( this, list->name[ i ] ) != NULL ) - fprintf( output, "%s=%s\n", list->name[ i ], mlt_properties_get( this, list->name[ i ] ) ); + if ( mlt_properties_get( self, list->name[ i ] ) != NULL ) + fprintf( output, "%s=%s\n", list->name[ i ], mlt_properties_get( self, list->name[ i ] ) ); } /** Output the properties to a file handle. * * This version includes reference counts and does not put each property on a new line. * \public \memberof mlt_properties_s - * \param this a properties pointer + * \param self a properties pointer * \param title a string to preface the output * \param output a file handle */ -void mlt_properties_debug( mlt_properties this, const char *title, FILE *output ) +void mlt_properties_debug( mlt_properties self, const char *title, FILE *output ) { if ( output == NULL ) output = stderr; fprintf( output, "%s: ", title ); - if ( this != NULL ) + if ( self != NULL ) { - property_list *list = this->local; + property_list *list = self->local; int i = 0; fprintf( output, "[ ref=%d", list->ref_count ); for ( i = 0; i < list->count; i ++ ) - if ( mlt_properties_get( this, list->name[ i ] ) != NULL ) - fprintf( output, ", %s=%s", list->name[ i ], mlt_properties_get( this, list->name[ i ] ) ); + if ( mlt_properties_get( self, list->name[ i ] ) != NULL ) + fprintf( output, ", %s=%s", list->name[ i ], mlt_properties_get( self, list->name[ i ] ) ); else - fprintf( output, ", %s=%p", list->name[ i ], mlt_properties_get_data( this, list->name[ i ], NULL ) ); + fprintf( output, ", %s=%p", list->name[ i ], mlt_properties_get_data( self, list->name[ i ], NULL ) ); fprintf( output, " ]" ); } fprintf( output, "\n" ); @@ -1000,18 +1012,18 @@ * * This uses the dump format - one line per property. * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param filename the name of a file to create or overwrite * \return true if there was an error */ -int mlt_properties_save( mlt_properties this, const char *filename ) +int mlt_properties_save( mlt_properties self, const char *filename ) { int error = 1; FILE *f = fopen( filename, "w" ); if ( f != NULL ) { - mlt_properties_dump( this, f ); + mlt_properties_dump( self, f ); fclose( f ); error = 0; } @@ -1066,14 +1078,14 @@ /** Compare the string or serialized value of two properties. * * \private \memberof mlt_properties_s - * \param this a property + * \param self a property * \param that a property - * \return < 0 if 'this' less than 'that', 0 if equal, or > 0 if 'this' is greater than 'that' + * \return < 0 if \p self less than \p that, 0 if equal, or > 0 if \p self is greater than \p that */ -static int mlt_compare( const void *this, const void *that ) +static int mlt_compare( const void *self, const void *that ) { - return strcmp( mlt_property_get_string( *( const mlt_property * )this ), mlt_property_get_string( *( const mlt_property * )that ) ); + return strcmp( mlt_property_get_string( *( const mlt_property * )self ), mlt_property_get_string( *( const mlt_property * )that ) ); } /** Get the contents of a directory. @@ -1082,14 +1094,14 @@ * Entries in the list have a numeric name (running from 0 to count - 1). Only values change * position if sort is enabled. Designed to be posix compatible (linux, os/x, mingw etc). * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param dirname the name of the directory * \param pattern a wildcard pattern to filter the directory listing * \param sort Do you want to sort the directory listing? * \return the number of items in the directory listing */ -int mlt_properties_dir_list( mlt_properties this, const char *dirname, const char *pattern, int sort ) +int mlt_properties_dir_list( mlt_properties self, const char *dirname, const char *pattern, int sort ) { DIR *dir = opendir( dirname ); @@ -1100,50 +1112,52 @@ char fullname[ 1024 ]; while( de != NULL ) { - sprintf( key, "%d", mlt_properties_count( this ) ); + sprintf( key, "%d", mlt_properties_count( self ) ); snprintf( fullname, 1024, "%s/%s", dirname, de->d_name ); if ( pattern == NULL ) - mlt_properties_set( this, key, fullname ); + mlt_properties_set( self, key, fullname ); else if ( de->d_name[ 0 ] != '.' && mlt_fnmatch( pattern, de->d_name ) ) - mlt_properties_set( this, key, fullname ); + mlt_properties_set( self, key, fullname ); de = readdir( dir ); } closedir( dir ); } - if ( sort && mlt_properties_count( this ) ) + if ( sort && mlt_properties_count( self ) ) { - property_list *list = this->local; - qsort( list->value, mlt_properties_count( this ), sizeof( mlt_property ), mlt_compare ); + property_list *list = self->local; + mlt_properties_lock( self ); + qsort( list->value, mlt_properties_count( self ), sizeof( mlt_property ), mlt_compare ); + mlt_properties_unlock( self ); } - return mlt_properties_count( this ); + return mlt_properties_count( self ); } /** Close a properties object. * * Deallocates the properties object and everything it contains. * \public \memberof mlt_properties_s - * \param this a properties object + * \param self a properties object */ -void mlt_properties_close( mlt_properties this ) +void mlt_properties_close( mlt_properties self ) { - if ( this != NULL && mlt_properties_dec_ref( this ) <= 0 ) + if ( self != NULL && mlt_properties_dec_ref( self ) <= 0 ) { - if ( this->close != NULL ) + if ( self->close != NULL ) { - this->close( this->close_object ); + self->close( self->close_object ); } else { - property_list *list = this->local; + property_list *list = self->local; int index = 0; #if _MLT_PROPERTY_CHECKS_ == 1 // Show debug info - mlt_properties_debug( this, "Closing", stderr ); + mlt_properties_debug( self, "Closing", stderr ); #endif #ifdef _MLT_PROPERTY_CHECKS_ @@ -1157,8 +1171,8 @@ // Clean up names and values for ( index = list->count - 1; index >= 0; index -- ) { - free( list->name[ index ] ); mlt_property_close( list->value[ index ] ); + free( list->name[ index ] ); } // Clear up the list @@ -1167,9 +1181,9 @@ free( list->value ); free( list ); - // Free this now if this has no child - if ( this->child == NULL ) - free( this ); + // Free self now if self has no child + if ( self->child == NULL ) + free( self ); } } } @@ -1480,9 +1494,9 @@ mlt_properties mlt_properties_parse_yaml( const char *filename ) { // Construct a standalone properties object - mlt_properties this = mlt_properties_new( ); + mlt_properties self = mlt_properties_new( ); - if ( this ) + if ( self ) { // Open the file FILE *file = fopen( filename, "r" ); @@ -1497,7 +1511,7 @@ // Parser context yaml_parser context = calloc( 1, sizeof( struct yaml_parser_context ) ); context->stack = mlt_deque_init(); - mlt_deque_push_front( context->stack, this ); + mlt_deque_push_front( context->stack, self ); // Read each string from the file while( fgets( temp, 1024, file ) ) @@ -1525,7 +1539,7 @@ } // Return the pointer - return this; + return self; } /* @@ -1647,15 +1661,15 @@ /** Recursively serialize a properties list into a string buffer as YAML Tiny. * * \private \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \param output a string buffer to hold the serialized YAML Tiny * \param indent the number of spaces to indent (for recursion, initialize to 0) - * \param is_parent_sequence Is 'this' properties list really just a sequence (for recursion, initialize to 0)? + * \param is_parent_sequence Is this properties list really just a sequence (for recursion, initialize to 0)? */ -static void serialise_yaml( mlt_properties this, strbuf output, int indent, int is_parent_sequence ) +static void serialise_yaml( mlt_properties self, strbuf output, int indent, int is_parent_sequence ) { - property_list *list = this->local; + property_list *list = self->local; int i = 0; for ( i = 0; i < list->count; i ++ ) @@ -1664,7 +1678,7 @@ // Unfortunately, we do not have run time type identification. mlt_properties child = mlt_property_get_data( list->value[ i ], NULL ); - if ( mlt_properties_is_sequence( this ) ) + if ( mlt_properties_is_sequence( self ) ) { // Ignore hidden/non-serialisable items if ( list->name[ i ][ 0 ] != '_' ) @@ -1674,7 +1688,7 @@ strbuf_printf( output, "- " ); // If the value can be represented as a string - const char *value = mlt_properties_get( this, list->name[ i ] ); + const char *value = mlt_properties_get( self, list->name[ i ] ); if ( value && strcmp( value, "" ) ) { // Determine if this is an unfolded block literal @@ -1696,7 +1710,7 @@ else { // Assume this is a normal map-oriented properties list - const char *value = mlt_properties_get( this, list->name[ i ] ); + const char *value = mlt_properties_get( self, list->name[ i ] ); // Ignore hidden/non-serialisable items // If the value can be represented as a string @@ -1738,17 +1752,41 @@ * This operates on properties containing properties as a hierarchical data * structure. * \public \memberof mlt_properties_s - * \param this a properties list + * \param self a properties list * \return a string containing YAML Tiny that represents the properties list */ -char *mlt_properties_serialise_yaml( mlt_properties this ) +char *mlt_properties_serialise_yaml( mlt_properties self ) { strbuf b = strbuf_new(); strbuf_printf( b, "---\n" ); - serialise_yaml( this, b, 0, 0 ); + serialise_yaml( self, b, 0, 0 ); strbuf_printf( b, "...\n" ); char *ret = b->string; strbuf_close( b ); return ret; } + +/** Protect a properties list against concurrent access. + * + * \public \memberof mlt_properties_s + * \param self a properties list + */ + +void mlt_properties_lock( mlt_properties self ) +{ + if ( self ) + pthread_mutex_lock( &( ( property_list* )( self->local ) )->mutex ); +} + +/** End protecting a properties list against concurrent access. + * + * \public \memberof mlt_properties_s + * \param self a properties list + */ + +void mlt_properties_unlock( mlt_properties self ) +{ + if ( self ) + pthread_mutex_unlock( &( ( property_list* )( self->local ) )->mutex ); +} diff -Nru mlt-0.6.2/src/framework/mlt_properties.h mlt-0.7.2/src/framework/mlt_properties.h --- mlt-0.6.2/src/framework/mlt_properties.h 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_properties.h 2011-05-02 05:59:12.000000000 +0000 @@ -3,7 +3,7 @@ * \brief Properties class declaration * \see mlt_properties_s * - * Copyright (C) 2003-2009 Ushodaya Enterprises Limited + * Copyright (C) 2003-2011 Ushodaya Enterprises Limited * \author Charles Yates * \author Dan Dennedy * @@ -83,5 +83,7 @@ extern int mlt_properties_is_sequence( mlt_properties self ); extern mlt_properties mlt_properties_parse_yaml( const char *file ); extern char *mlt_properties_serialise_yaml( mlt_properties self ); +extern void mlt_properties_lock( mlt_properties self ); +extern void mlt_properties_unlock( mlt_properties self ); #endif diff -Nru mlt-0.6.2/src/framework/mlt_property.c mlt-0.7.2/src/framework/mlt_property.c --- mlt-0.6.2/src/framework/mlt_property.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_property.c 2011-05-02 05:59:12.000000000 +0000 @@ -76,82 +76,82 @@ mlt_property mlt_property_init( ) { - mlt_property this = malloc( sizeof( struct mlt_property_s ) ); - if ( this != NULL ) + mlt_property self = malloc( sizeof( struct mlt_property_s ) ); + if ( self != NULL ) { - this->types = 0; - this->prop_int = 0; - this->prop_position = 0; - this->prop_double = 0; - this->prop_int64 = 0; - this->prop_string = NULL; - this->data = NULL; - this->length = 0; - this->destructor = NULL; - this->serialiser = NULL; + self->types = 0; + self->prop_int = 0; + self->prop_position = 0; + self->prop_double = 0; + self->prop_int64 = 0; + self->prop_string = NULL; + self->data = NULL; + self->length = 0; + self->destructor = NULL; + self->serialiser = NULL; } - return this; + return self; } /** Clear (0/null) a property. * * Frees up any associated resources in the process. * \private \memberof mlt_property_s - * \param this a property + * \param self a property */ -static inline void mlt_property_clear( mlt_property this ) +static inline void mlt_property_clear( mlt_property self ) { // Special case data handling - if ( this->types & mlt_prop_data && this->destructor != NULL ) - this->destructor( this->data ); + if ( self->types & mlt_prop_data && self->destructor != NULL ) + self->destructor( self->data ); // Special case string handling - if ( this->types & mlt_prop_string ) - free( this->prop_string ); + if ( self->types & mlt_prop_string ) + free( self->prop_string ); // Wipe stuff - this->types = 0; - this->prop_int = 0; - this->prop_position = 0; - this->prop_double = 0; - this->prop_int64 = 0; - this->prop_string = NULL; - this->data = NULL; - this->length = 0; - this->destructor = NULL; - this->serialiser = NULL; + self->types = 0; + self->prop_int = 0; + self->prop_position = 0; + self->prop_double = 0; + self->prop_int64 = 0; + self->prop_string = NULL; + self->data = NULL; + self->length = 0; + self->destructor = NULL; + self->serialiser = NULL; } /** Set the property to an integer value. * * \public \memberof mlt_property_s - * \param this a property + * \param self a property * \param value an integer * \return false */ -int mlt_property_set_int( mlt_property this, int value ) +int mlt_property_set_int( mlt_property self, int value ) { - mlt_property_clear( this ); - this->types = mlt_prop_int; - this->prop_int = value; + mlt_property_clear( self ); + self->types = mlt_prop_int; + self->prop_int = value; return 0; } /** Set the property to a floating point value. * * \public \memberof mlt_property_s - * \param this a property + * \param self a property * \param value a double precision floating point value * \return false */ -int mlt_property_set_double( mlt_property this, double value ) +int mlt_property_set_double( mlt_property self, double value ) { - mlt_property_clear( this ); - this->types = mlt_prop_double; - this->prop_double = value; + mlt_property_clear( self ); + self->types = mlt_prop_double; + self->prop_double = value; return 0; } @@ -159,16 +159,16 @@ * * Position is a relative time value in frame units. * \public \memberof mlt_property_s - * \param this a property + * \param self a property * \param value a position value * \return false */ -int mlt_property_set_position( mlt_property this, mlt_position value ) +int mlt_property_set_position( mlt_property self, mlt_position value ) { - mlt_property_clear( this ); - this->types = mlt_prop_position; - this->prop_position = value; + mlt_property_clear( self ); + self->types = mlt_prop_position; + self->prop_position = value; return 0; } @@ -177,40 +177,40 @@ * This makes a copy of the string you supply so you do not need to track * a new reference to it. * \public \memberof mlt_property_s - * \param this a property + * \param self a property * \param value the string to copy to the property * \return true if it failed */ -int mlt_property_set_string( mlt_property this, const char *value ) +int mlt_property_set_string( mlt_property self, const char *value ) { - if ( value != this->prop_string ) + if ( value != self->prop_string ) { - mlt_property_clear( this ); - this->types = mlt_prop_string; + mlt_property_clear( self ); + self->types = mlt_prop_string; if ( value != NULL ) - this->prop_string = strdup( value ); + self->prop_string = strdup( value ); } else { - this->types = mlt_prop_string; + self->types = mlt_prop_string; } - return this->prop_string == NULL; + return self->prop_string == NULL; } /** Set the property to a 64-bit integer value. * * \public \memberof mlt_property_s - * \param this a property + * \param self a property * \param value a 64-bit integer * \return false */ -int mlt_property_set_int64( mlt_property this, int64_t value ) +int mlt_property_set_int64( mlt_property self, int64_t value ) { - mlt_property_clear( this ); - this->types = mlt_prop_int64; - this->prop_int64 = value; + mlt_property_clear( self ); + self->types = mlt_prop_int64; + self->prop_int64 = value; return 0; } @@ -221,7 +221,7 @@ * the lifetime of the data. Otherwise, pass NULL for the destructor * function and control the lifetime yourself. * \public \memberof mlt_property_s - * \param this a property + * \param self a property * \param value an opaque pointer * \param length the number of bytes pointed to by value (optional) * \param destructor a function to use to destroy this binary data (optional, assuming you manage the resource) @@ -229,16 +229,16 @@ * \return false */ -int mlt_property_set_data( mlt_property this, void *value, int length, mlt_destructor destructor, mlt_serialiser serialiser ) +int mlt_property_set_data( mlt_property self, void *value, int length, mlt_destructor destructor, mlt_serialiser serialiser ) { - if ( this->data == value ) - this->destructor = NULL; - mlt_property_clear( this ); - this->types = mlt_prop_data; - this->data = value; - this->length = length; - this->destructor = destructor; - this->serialiser = serialiser; + if ( self->data == value ) + self->destructor = NULL; + mlt_property_clear( self ); + self->types = mlt_prop_data; + self->data = value; + self->length = length; + self->destructor = destructor; + self->serialiser = serialiser; return 0; } @@ -285,44 +285,44 @@ /** Get the property as an integer. * * \public \memberof mlt_property_s - * \param this a property + * \param self a property * \return an integer value */ -int mlt_property_get_int( mlt_property this ) +int mlt_property_get_int( mlt_property self ) { - if ( this->types & mlt_prop_int ) - return this->prop_int; - else if ( this->types & mlt_prop_double ) - return ( int )this->prop_double; - else if ( this->types & mlt_prop_position ) - return ( int )this->prop_position; - else if ( this->types & mlt_prop_int64 ) - return ( int )this->prop_int64; - else if ( ( this->types & mlt_prop_string ) && this->prop_string ) - return mlt_property_atoi( this->prop_string ); + if ( self->types & mlt_prop_int ) + return self->prop_int; + else if ( self->types & mlt_prop_double ) + return ( int )self->prop_double; + else if ( self->types & mlt_prop_position ) + return ( int )self->prop_position; + else if ( self->types & mlt_prop_int64 ) + return ( int )self->prop_int64; + else if ( ( self->types & mlt_prop_string ) && self->prop_string ) + return mlt_property_atoi( self->prop_string ); return 0; } /** Get the property as a floating point. * * \public \memberof mlt_property_s - * \param this a property + * \param self a property * \return a floating point value */ -double mlt_property_get_double( mlt_property this ) +double mlt_property_get_double( mlt_property self ) { - if ( this->types & mlt_prop_double ) - return this->prop_double; - else if ( this->types & mlt_prop_int ) - return ( double )this->prop_int; - else if ( this->types & mlt_prop_position ) - return ( double )this->prop_position; - else if ( this->types & mlt_prop_int64 ) - return ( double )this->prop_int64; - else if ( ( this->types & mlt_prop_string ) && this->prop_string ) - return atof( this->prop_string ); + if ( self->types & mlt_prop_double ) + return self->prop_double; + else if ( self->types & mlt_prop_int ) + return ( double )self->prop_int; + else if ( self->types & mlt_prop_position ) + return ( double )self->prop_position; + else if ( self->types & mlt_prop_int64 ) + return ( double )self->prop_int64; + else if ( ( self->types & mlt_prop_string ) && self->prop_string ) + return atof( self->prop_string ); return 0; } @@ -330,22 +330,22 @@ * * A position is an offset time in terms of frame units. * \public \memberof mlt_property_s - * \param this a property + * \param self a property * \return the position in frames */ -mlt_position mlt_property_get_position( mlt_property this ) +mlt_position mlt_property_get_position( mlt_property self ) { - if ( this->types & mlt_prop_position ) - return this->prop_position; - else if ( this->types & mlt_prop_int ) - return ( mlt_position )this->prop_int; - else if ( this->types & mlt_prop_double ) - return ( mlt_position )this->prop_double; - else if ( this->types & mlt_prop_int64 ) - return ( mlt_position )this->prop_int64; - else if ( ( this->types & mlt_prop_string ) && this->prop_string ) - return ( mlt_position )atol( this->prop_string ); + if ( self->types & mlt_prop_position ) + return self->prop_position; + else if ( self->types & mlt_prop_int ) + return ( mlt_position )self->prop_int; + else if ( self->types & mlt_prop_double ) + return ( mlt_position )self->prop_double; + else if ( self->types & mlt_prop_int64 ) + return ( mlt_position )self->prop_int64; + else if ( ( self->types & mlt_prop_string ) && self->prop_string ) + return ( mlt_position )atol( self->prop_string ); return 0; } @@ -370,22 +370,22 @@ /** Get the property as a signed integer. * * \public \memberof mlt_property_s - * \param this a property + * \param self a property * \return a 64-bit integer */ -int64_t mlt_property_get_int64( mlt_property this ) +int64_t mlt_property_get_int64( mlt_property self ) { - if ( this->types & mlt_prop_int64 ) - return this->prop_int64; - else if ( this->types & mlt_prop_int ) - return ( int64_t )this->prop_int; - else if ( this->types & mlt_prop_double ) - return ( int64_t )this->prop_double; - else if ( this->types & mlt_prop_position ) - return ( int64_t )this->prop_position; - else if ( ( this->types & mlt_prop_string ) && this->prop_string ) - return mlt_property_atoll( this->prop_string ); + if ( self->types & mlt_prop_int64 ) + return self->prop_int64; + else if ( self->types & mlt_prop_int ) + return ( int64_t )self->prop_int; + else if ( self->types & mlt_prop_double ) + return ( int64_t )self->prop_double; + else if ( self->types & mlt_prop_position ) + return ( int64_t )self->prop_position; + else if ( ( self->types & mlt_prop_string ) && self->prop_string ) + return mlt_property_atoll( self->prop_string ); return 0; } @@ -396,48 +396,48 @@ * This tries its hardest to convert the property to string including using * a serialization function for binary data, if supplied. * \public \memberof mlt_property_s - * \param this a property + * \param self a property * \return a string representation of the property or NULL if failed */ -char *mlt_property_get_string( mlt_property this ) +char *mlt_property_get_string( mlt_property self ) { // Construct a string if need be - if ( ! ( this->types & mlt_prop_string ) ) + if ( ! ( self->types & mlt_prop_string ) ) { - if ( this->types & mlt_prop_int ) + if ( self->types & mlt_prop_int ) { - this->types |= mlt_prop_string; - this->prop_string = malloc( 32 ); - sprintf( this->prop_string, "%d", this->prop_int ); + self->types |= mlt_prop_string; + self->prop_string = malloc( 32 ); + sprintf( self->prop_string, "%d", self->prop_int ); } - else if ( this->types & mlt_prop_double ) + else if ( self->types & mlt_prop_double ) { - this->types |= mlt_prop_string; - this->prop_string = malloc( 32 ); - sprintf( this->prop_string, "%f", this->prop_double ); + self->types |= mlt_prop_string; + self->prop_string = malloc( 32 ); + sprintf( self->prop_string, "%f", self->prop_double ); } - else if ( this->types & mlt_prop_position ) + else if ( self->types & mlt_prop_position ) { - this->types |= mlt_prop_string; - this->prop_string = malloc( 32 ); - sprintf( this->prop_string, "%d", (int)this->prop_position ); /* I don't know if this is wanted. -Zach */ + self->types |= mlt_prop_string; + self->prop_string = malloc( 32 ); + sprintf( self->prop_string, "%d", (int)self->prop_position ); } - else if ( this->types & mlt_prop_int64 ) + else if ( self->types & mlt_prop_int64 ) { - this->types |= mlt_prop_string; - this->prop_string = malloc( 32 ); - sprintf( this->prop_string, "%lld", (long long int)this->prop_int64 ); + self->types |= mlt_prop_string; + self->prop_string = malloc( 32 ); + sprintf( self->prop_string, "%"PRId64, self->prop_int64 ); } - else if ( this->types & mlt_prop_data && this->serialiser != NULL ) + else if ( self->types & mlt_prop_data && self->serialiser != NULL ) { - this->types |= mlt_prop_string; - this->prop_string = this->serialiser( this->data, this->length ); + self->types |= mlt_prop_string; + self->prop_string = self->serialiser( self->data, self->length ); } } // Return the string (may be NULL) - return this->prop_string; + return self->prop_string; } /** Get the binary data from a property. @@ -449,31 +449,31 @@ * Therefore, only free the returned pointer if you did not supply a * destructor function. * \public \memberof mlt_property_s - * \param this a property + * \param self a property * \param[out] length the size of the binary object in bytes (optional) * \return an opaque data pointer or NULL if not available */ -void *mlt_property_get_data( mlt_property this, int *length ) +void *mlt_property_get_data( mlt_property self, int *length ) { // Assign length if not NULL if ( length != NULL ) - *length = this->length; + *length = self->length; // Return the data (note: there is no conversion here) - return this->data; + return self->data; } /** Destroy a property and free all related resources. * * \public \memberof mlt_property_s - * \param this a property + * \param self a property */ -void mlt_property_close( mlt_property this ) +void mlt_property_close( mlt_property self ) { - mlt_property_clear( this ); - free( this ); + mlt_property_clear( self ); + free( self ); } /** Copy a property. @@ -482,31 +482,31 @@ * function was supplied when you set the Property. * \public \memberof mlt_property_s * \author Zach - * \param this a property + * \param self a property * \param that another property */ -void mlt_property_pass( mlt_property this, mlt_property that ) +void mlt_property_pass( mlt_property self, mlt_property that ) { - mlt_property_clear( this ); + mlt_property_clear( self ); - this->types = that->types; + self->types = that->types; - if ( this->types & mlt_prop_int64 ) - this->prop_int64 = that->prop_int64; - else if ( this->types & mlt_prop_int ) - this->prop_int = that->prop_int; - else if ( this->types & mlt_prop_double ) - this->prop_double = that->prop_double; - else if ( this->types & mlt_prop_position ) - this->prop_position = that->prop_position; - else if ( this->types & mlt_prop_string ) + if ( self->types & mlt_prop_int64 ) + self->prop_int64 = that->prop_int64; + else if ( self->types & mlt_prop_int ) + self->prop_int = that->prop_int; + else if ( self->types & mlt_prop_double ) + self->prop_double = that->prop_double; + else if ( self->types & mlt_prop_position ) + self->prop_position = that->prop_position; + else if ( self->types & mlt_prop_string ) { if ( that->prop_string != NULL ) - this->prop_string = strdup( that->prop_string ); + self->prop_string = strdup( that->prop_string ); } - else if ( this->types & mlt_prop_data && this->serialiser != NULL ) + else if ( self->types & mlt_prop_data && self->serialiser != NULL ) { - this->types = mlt_prop_string; - this->prop_string = this->serialiser( this->data, this->length ); + self->types = mlt_prop_string; + self->prop_string = self->serialiser( self->data, self->length ); } } diff -Nru mlt-0.6.2/src/framework/mlt_property.h mlt-0.7.2/src/framework/mlt_property.h --- mlt-0.6.2/src/framework/mlt_property.h 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_property.h 2011-05-02 05:59:12.000000000 +0000 @@ -41,6 +41,6 @@ extern void *mlt_property_get_data( mlt_property self, int *length ); extern void mlt_property_close( mlt_property self ); -extern void mlt_property_pass( mlt_property this, mlt_property that ); +extern void mlt_property_pass( mlt_property self, mlt_property that ); #endif diff -Nru mlt-0.6.2/src/framework/mlt_repository.c mlt-0.7.2/src/framework/mlt_repository.c --- mlt-0.6.2/src/framework/mlt_repository.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_repository.c 2011-05-02 05:59:12.000000000 +0000 @@ -63,12 +63,12 @@ return NULL; // Construct the repository - mlt_repository this = calloc( sizeof( struct mlt_repository_s ), 1 ); - mlt_properties_init( &this->parent, this ); - this->consumers = mlt_properties_new(); - this->filters = mlt_properties_new(); - this->producers = mlt_properties_new(); - this->transitions = mlt_properties_new(); + mlt_repository self = calloc( sizeof( struct mlt_repository_s ), 1 ); + mlt_properties_init( &self->parent, self ); + self->consumers = mlt_properties_new(); + self->filters = mlt_properties_new(); + self->producers = mlt_properties_new(); + self->transitions = mlt_properties_new(); // Get the directory list mlt_properties dir = mlt_properties_new(); @@ -96,10 +96,10 @@ // Call the registration function if ( symbol_ptr != NULL ) { - symbol_ptr( this ); + symbol_ptr( self ); // Register the object file for closure - mlt_properties_set_data( &this->parent, object_name, object, 0, ( mlt_destructor )dlclose, NULL ); + mlt_properties_set_data( &self->parent, object_name, object, 0, ( mlt_destructor )dlclose, NULL ); } else { @@ -114,7 +114,7 @@ mlt_properties_close( dir ); - return this; + return self; } /** Create a properties list for a service holding a function pointer to its constructor function. @@ -136,28 +136,28 @@ * Typically, this is invoked by a module within its mlt_register(). * * \public \memberof mlt_repository_s - * \param this a repository + * \param self a repository * \param service_type a service class * \param service the name of a service * \param symbol a pointer to a function to create the service */ -void mlt_repository_register( mlt_repository this, mlt_service_type service_type, const char *service, mlt_register_callback symbol ) +void mlt_repository_register( mlt_repository self, mlt_service_type service_type, const char *service, mlt_register_callback symbol ) { // Add the entry point to the corresponding service list switch ( service_type ) { case consumer_type: - mlt_properties_set_data( this->consumers, service, new_service( symbol ), 0, ( mlt_destructor )mlt_properties_close, NULL ); + mlt_properties_set_data( self->consumers, service, new_service( symbol ), 0, ( mlt_destructor )mlt_properties_close, NULL ); break; case filter_type: - mlt_properties_set_data( this->filters, service, new_service( symbol ), 0, ( mlt_destructor )mlt_properties_close, NULL ); + mlt_properties_set_data( self->filters, service, new_service( symbol ), 0, ( mlt_destructor )mlt_properties_close, NULL ); break; case producer_type: - mlt_properties_set_data( this->producers, service, new_service( symbol ), 0, ( mlt_destructor )mlt_properties_close, NULL ); + mlt_properties_set_data( self->producers, service, new_service( symbol ), 0, ( mlt_destructor )mlt_properties_close, NULL ); break; case transition_type: - mlt_properties_set_data( this->transitions, service, new_service( symbol ), 0, ( mlt_destructor )mlt_properties_close, NULL ); + mlt_properties_set_data( self->transitions, service, new_service( symbol ), 0, ( mlt_destructor )mlt_properties_close, NULL ); break; default: break; @@ -167,13 +167,13 @@ /** Get the repository properties for particular service class. * * \private \memberof mlt_repository_s - * \param this a repository + * \param self a repository * \param type a service class * \param service the name of a service * \return a properties list or NULL if error */ -static mlt_properties get_service_properties( mlt_repository this, mlt_service_type type, const char *service ) +static mlt_properties get_service_properties( mlt_repository self, mlt_service_type type, const char *service ) { mlt_properties service_properties = NULL; @@ -181,16 +181,16 @@ switch ( type ) { case consumer_type: - service_properties = mlt_properties_get_data( this->consumers, service, NULL ); + service_properties = mlt_properties_get_data( self->consumers, service, NULL ); break; case filter_type: - service_properties = mlt_properties_get_data( this->filters, service, NULL ); + service_properties = mlt_properties_get_data( self->filters, service, NULL ); break; case producer_type: - service_properties = mlt_properties_get_data( this->producers, service, NULL ); + service_properties = mlt_properties_get_data( self->producers, service, NULL ); break; case transition_type: - service_properties = mlt_properties_get_data( this->transitions, service, NULL ); + service_properties = mlt_properties_get_data( self->transitions, service, NULL ); break; default: break; @@ -201,16 +201,16 @@ /** Construct a new instance of a service. * * \public \memberof mlt_repository_s - * \param this a repository + * \param self a repository * \param profile a \p mlt_profile to give the service * \param type a service class * \param service the name of the service * \param input an optional argument to the service constructor */ -void *mlt_repository_create( mlt_repository this, mlt_profile profile, mlt_service_type type, const char *service, const void *input ) +void *mlt_repository_create( mlt_repository self, mlt_profile profile, mlt_service_type type, const char *service, const void *input ) { - mlt_properties properties = get_service_properties( this, type, service ); + mlt_properties properties = get_service_properties( self, type, service ); if ( properties != NULL ) { mlt_register_callback symbol_ptr = mlt_properties_get_data( properties, "symbol", NULL ); @@ -224,17 +224,17 @@ /** Destroy a repository and free its resources. * * \public \memberof mlt_repository_s - * \param this a repository + * \param self a repository */ -void mlt_repository_close( mlt_repository this ) +void mlt_repository_close( mlt_repository self ) { - mlt_properties_close( this->consumers ); - mlt_properties_close( this->filters ); - mlt_properties_close( this->producers ); - mlt_properties_close( this->transitions ); - mlt_properties_close( &this->parent ); - free( this ); + mlt_properties_close( self->consumers ); + mlt_properties_close( self->filters ); + mlt_properties_close( self->producers ); + mlt_properties_close( self->transitions ); + mlt_properties_close( &self->parent ); + free( self ); } /** Get the list of registered consumers. diff -Nru mlt-0.6.2/src/framework/mlt_service.c mlt-0.7.2/src/framework/mlt_service.c --- mlt-0.6.2/src/framework/mlt_service.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_service.c 2011-05-02 05:59:12.000000000 +0000 @@ -63,46 +63,46 @@ /* Private methods */ -static void mlt_service_disconnect( mlt_service this ); -static void mlt_service_connect( mlt_service this, mlt_service that ); -static int service_get_frame( mlt_service this, mlt_frame_ptr frame, int index ); -static void mlt_service_property_changed( mlt_listener, mlt_properties owner, mlt_service this, void **args ); +static void mlt_service_disconnect( mlt_service self ); +static void mlt_service_connect( mlt_service self, mlt_service that ); +static int service_get_frame( mlt_service self, mlt_frame_ptr frame, int index ); +static void mlt_service_property_changed( mlt_listener, mlt_properties owner, mlt_service self, void **args ); /** Initialize a service. * * \public \memberof mlt_service_s - * \param this the service structure to initialize + * \param self the service structure to initialize * \param child pointer to the child object for the subclass * \return true if there was an error */ -int mlt_service_init( mlt_service this, void *child ) +int mlt_service_init( mlt_service self, void *child ) { int error = 0; // Initialise everything to NULL - memset( this, 0, sizeof( struct mlt_service_s ) ); + memset( self, 0, sizeof( struct mlt_service_s ) ); // Assign the child - this->child = child; + self->child = child; // Generate local space - this->local = calloc( sizeof( mlt_service_base ), 1 ); + self->local = calloc( sizeof( mlt_service_base ), 1 ); // Associate the methods - this->get_frame = service_get_frame; + self->get_frame = service_get_frame; // Initialise the properties - error = mlt_properties_init( &this->parent, this ); + error = mlt_properties_init( &self->parent, self ); if ( error == 0 ) { - this->parent.close = ( mlt_destructor )mlt_service_close; - this->parent.close_object = this; + self->parent.close = ( mlt_destructor )mlt_service_close; + self->parent.close_object = self; - mlt_events_init( &this->parent ); - mlt_events_register( &this->parent, "service-changed", NULL ); - mlt_events_register( &this->parent, "property-changed", ( mlt_transmitter )mlt_service_property_changed ); - pthread_mutex_init( &( ( mlt_service_base * )this->local )->mutex, NULL ); + mlt_events_init( &self->parent ); + mlt_events_register( &self->parent, "service-changed", NULL ); + mlt_events_register( &self->parent, "property-changed", ( mlt_transmitter )mlt_service_property_changed ); + pthread_mutex_init( &( ( mlt_service_base * )self->local )->mutex, NULL ); } return error; @@ -115,53 +115,53 @@ * \private \memberof mlt_service_s * \param listener a function pointer that will be invoked * \param owner a properties list that will be passed to \p listener - * \param this a service that will be passed to \p listener + * \param self a service that will be passed to \p listener * \param args an array of pointers - the first entry is passed as a string to \p listener */ -static void mlt_service_property_changed( mlt_listener listener, mlt_properties owner, mlt_service this, void **args ) +static void mlt_service_property_changed( mlt_listener listener, mlt_properties owner, mlt_service self, void **args ) { if ( listener != NULL ) - listener( owner, this, ( char * )args[ 0 ] ); + listener( owner, self, ( char * )args[ 0 ] ); } /** Acquire a mutual exclusion lock on this service. * * \public \memberof mlt_service_s - * \param this the service to lock + * \param self the service to lock */ -void mlt_service_lock( mlt_service this ) +void mlt_service_lock( mlt_service self ) { - if ( this != NULL ) - pthread_mutex_lock( &( ( mlt_service_base * )this->local )->mutex ); + if ( self != NULL ) + pthread_mutex_lock( &( ( mlt_service_base * )self->local )->mutex ); } /** Release a mutual exclusion lock on this service. * * \public \memberof mlt_service_s - * \param this the service to unlock + * \param self the service to unlock */ -void mlt_service_unlock( mlt_service this ) +void mlt_service_unlock( mlt_service self ) { - if ( this != NULL ) - pthread_mutex_unlock( &( ( mlt_service_base * )this->local )->mutex ); + if ( self != NULL ) + pthread_mutex_unlock( &( ( mlt_service_base * )self->local )->mutex ); } /** Identify the subclass of the service. * * \public \memberof mlt_service_s - * \param this a service + * \param self a service * \return the subclass */ -mlt_service_type mlt_service_identify( mlt_service this ) +mlt_service_type mlt_service_identify( mlt_service self ) { mlt_service_type type = invalid_type; - if ( this != NULL ) + if ( self != NULL ) { - mlt_properties properties = MLT_SERVICE_PROPERTIES( this ); + mlt_properties properties = MLT_SERVICE_PROPERTIES( self ); char *mlt_type = mlt_properties_get( properties, "mlt_type" ); char *resource = mlt_properties_get( properties, "resource" ); if ( mlt_type == NULL ) @@ -189,21 +189,21 @@ /** Connect a producer to the service. * * \public \memberof mlt_service_s - * \param this a service + * \param self a service * \param producer a producer * \param index which of potentially multiple producers to this service (0 based) * \return > 0 warning, == 0 success, < 0 serious error, * 1 = this service does not accept input, * 2 = the producer is invalid, - * 3 = the producer is already registered with this consumer + * 3 = the producer is already registered with self consumer */ -int mlt_service_connect_producer( mlt_service this, mlt_service producer, int index ) +int mlt_service_connect_producer( mlt_service self, mlt_service producer, int index ) { int i = 0; // Get the service base - mlt_service_base *base = this->local; + mlt_service_base *base = self->local; // Special case 'track' index - only works for last filter(s) in a particular chain // but allows a filter to apply to the output frame regardless of which track it comes from @@ -249,7 +249,7 @@ base->count = index + 1; // Now we connect the producer to its connected consumer - mlt_service_connect( producer, this ); + mlt_service_connect( producer, self ); // Close the current service mlt_service_close( current ); @@ -263,70 +263,70 @@ } } -/** Disconnect this service from its consumer. +/** Disconnect a service from its consumer. * * \public \memberof mlt_service_s - * \param this a service + * \param self a service */ -static void mlt_service_disconnect( mlt_service this ) +static void mlt_service_disconnect( mlt_service self ) { - if ( this != NULL ) + if ( self != NULL ) { // Get the service base - mlt_service_base *base = this->local; + mlt_service_base *base = self->local; // Disconnect base->out = NULL; } } -/** Obtain the consumer this service is connected to. +/** Obtain the consumer a service is connected to. * * \public \memberof mlt_service_s - * \param this a service + * \param self a service * \return the consumer */ -mlt_service mlt_service_consumer( mlt_service this ) +mlt_service mlt_service_consumer( mlt_service self ) { // Get the service base - mlt_service_base *base = this->local; + mlt_service_base *base = self->local; // Return the connected consumer return base->out; } -/** Obtain the producer this service is connected to. +/** Obtain the producer a service is connected to. * * \public \memberof mlt_service_s - * \param this a service + * \param self a service * \return the last-most producer */ -mlt_service mlt_service_producer( mlt_service this ) +mlt_service mlt_service_producer( mlt_service self ) { // Get the service base - mlt_service_base *base = this->local; + mlt_service_base *base = self->local; // Return the connected producer return base->count > 0 ? base->in[ base->count - 1 ] : NULL; } -/** Associate this service to a consumer. +/** Associate a service to a consumer. * * Overwrites connection to any existing consumer. * \private \memberof mlt_service_s - * \param this a service + * \param self a service * \param that a consumer */ -static void mlt_service_connect( mlt_service this, mlt_service that ) +static void mlt_service_connect( mlt_service self, mlt_service that ) { - if ( this != NULL ) + if ( self != NULL ) { // Get the service base - mlt_service_base *base = this->local; + mlt_service_base *base = self->local; // There's a bit more required here... base->out = that; @@ -336,16 +336,16 @@ /** Get the first connected producer. * * \public \memberof mlt_service_s - * \param this a service + * \param self a service * \return the first producer */ -mlt_service mlt_service_get_producer( mlt_service this ) +mlt_service mlt_service_get_producer( mlt_service self ) { mlt_service producer = NULL; // Get the service base - mlt_service_base *base = this->local; + mlt_service_base *base = self->local; if ( base->in != NULL ) producer = base->in[ 0 ]; @@ -356,54 +356,54 @@ /** Default implementation of the get_frame virtual function. * * \private \memberof mlt_service_s - * \param this a service + * \param self a service * \param[out] frame a frame by reference * \param index as determined by the producer * \return false */ -static int service_get_frame( mlt_service this, mlt_frame_ptr frame, int index ) +static int service_get_frame( mlt_service self, mlt_frame_ptr frame, int index ) { - mlt_service_base *base = this->local; + mlt_service_base *base = self->local; if ( index < base->count ) { mlt_service producer = base->in[ index ]; if ( producer != NULL ) return mlt_service_get_frame( producer, frame, index ); } - *frame = mlt_frame_init( this ); + *frame = mlt_frame_init( self ); return 0; } /** Return the properties object. * * \public \memberof mlt_service_s - * \param this a service + * \param self a service * \return the properties */ -mlt_properties mlt_service_properties( mlt_service this ) +mlt_properties mlt_service_properties( mlt_service self ) { - return this != NULL ? &this->parent : NULL; + return self != NULL ? &self->parent : NULL; } /** Recursively apply attached filters. * * \public \memberof mlt_service_s - * \param this a service + * \param self a service * \param frame a frame * \param index used to track depth of recursion, top caller should supply 0 */ -void mlt_service_apply_filters( mlt_service this, mlt_frame frame, int index ) +void mlt_service_apply_filters( mlt_service self, mlt_frame frame, int index ) { int i; mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); - mlt_properties service_properties = MLT_SERVICE_PROPERTIES( this ); - mlt_service_base *base = this->local; + mlt_properties service_properties = MLT_SERVICE_PROPERTIES( self ); + mlt_service_base *base = self->local; mlt_position position = mlt_frame_get_position( frame ); - mlt_position this_in = mlt_properties_get_position( service_properties, "in" ); - mlt_position this_out = mlt_properties_get_position( service_properties, "out" ); + mlt_position self_in = mlt_properties_get_position( service_properties, "in" ); + mlt_position self_out = mlt_properties_get_position( service_properties, "out" ); if ( index == 0 || mlt_properties_get_int( service_properties, "_filter_private" ) == 0 ) { @@ -417,8 +417,8 @@ int disable = mlt_properties_get_int( MLT_FILTER_PROPERTIES( base->filters[ i ] ), "disable" ); if ( !disable && ( ( in == 0 && out == 0 ) || ( position >= in && ( position <= out || out == 0 ) ) ) ) { - mlt_properties_set_position( frame_properties, "in", in == 0 ? this_in : in ); - mlt_properties_set_position( frame_properties, "out", out == 0 ? this_out : out ); + mlt_properties_set_position( frame_properties, "in", in == 0 ? self_in : in ); + mlt_properties_set_position( frame_properties, "out", out == 0 ? self_out : out ); mlt_filter_process( base->filters[ i ], frame ); mlt_service_apply_filters( MLT_FILTER_SERVICE( base->filters[ i ] ), frame, index + 1 ); } @@ -430,31 +430,31 @@ /** Obtain a frame. * * \public \memberof mlt_service_s - * \param this a service + * \param self a service * \param[out] frame a frame by reference * \param index as determined by the producer * \return true if there was an error */ -int mlt_service_get_frame( mlt_service this, mlt_frame_ptr frame, int index ) +int mlt_service_get_frame( mlt_service self, mlt_frame_ptr frame, int index ) { int result = 0; // Lock the service - mlt_service_lock( this ); + mlt_service_lock( self ); // Ensure that the frame is NULL *frame = NULL; // Only process if we have a valid service - if ( this != NULL && this->get_frame != NULL ) + if ( self != NULL && self->get_frame != NULL ) { - mlt_properties properties = MLT_SERVICE_PROPERTIES( this ); + mlt_properties properties = MLT_SERVICE_PROPERTIES( self ); mlt_position in = mlt_properties_get_position( properties, "in" ); mlt_position out = mlt_properties_get_position( properties, "out" ); - mlt_position position = mlt_service_identify( this ) == producer_type ? mlt_producer_position( MLT_PRODUCER( this ) ) : -1; + mlt_position position = mlt_service_identify( self ) == producer_type ? mlt_producer_position( MLT_PRODUCER( self ) ) : -1; - result = this->get_frame( this, frame, index ); + result = self->get_frame( self, frame, index ); if ( result == 0 ) { @@ -466,27 +466,27 @@ mlt_properties_set_position( properties, "in", in ); mlt_properties_set_position( properties, "out", out ); } - mlt_service_apply_filters( this, *frame, 1 ); - mlt_deque_push_back( MLT_FRAME_SERVICE_STACK( *frame ), this ); + mlt_service_apply_filters( self, *frame, 1 ); + mlt_deque_push_back( MLT_FRAME_SERVICE_STACK( *frame ), self ); - if ( mlt_service_identify( this ) == producer_type && - mlt_properties_get_int( MLT_SERVICE_PROPERTIES( this ), "_need_previous_next" ) ) + if ( mlt_service_identify( self ) == producer_type && + mlt_properties_get_int( MLT_SERVICE_PROPERTIES( self ), "_need_previous_next" ) ) { - // Save the new position from this->get_frame - mlt_position new_position = mlt_producer_position( MLT_PRODUCER( this ) ); + // Save the new position from self->get_frame + mlt_position new_position = mlt_producer_position( MLT_PRODUCER( self ) ); // Get the preceding frame, unfiltered mlt_frame previous_frame; - mlt_producer_seek( MLT_PRODUCER(this), position - 1 ); - result = this->get_frame( this, &previous_frame, index ); + mlt_producer_seek( MLT_PRODUCER(self), position - 1 ); + result = self->get_frame( self, &previous_frame, index ); if ( !result ) mlt_properties_set_data( properties, "previous frame", previous_frame, 0, ( mlt_destructor ) mlt_frame_close, NULL ); // Get the following frame, unfiltered mlt_frame next_frame; - mlt_producer_seek( MLT_PRODUCER(this), position + 1 ); - result = this->get_frame( this, &next_frame, index ); + mlt_producer_seek( MLT_PRODUCER(self), position + 1 ); + result = self->get_frame( self, &next_frame, index ); if ( !result ) { mlt_properties_set_data( properties, "next frame", @@ -494,17 +494,17 @@ } // Restore the new position - mlt_producer_seek( MLT_PRODUCER(this), new_position ); + mlt_producer_seek( MLT_PRODUCER(self), new_position ); } } } // Make sure we return a frame if ( *frame == NULL ) - *frame = mlt_frame_init( this ); + *frame = mlt_frame_init( self ); // Unlock the service - mlt_service_unlock( this ); + mlt_service_unlock( self ); return result; } @@ -513,30 +513,30 @@ * * \private \memberof mlt_service_s * \param owner ignored - * \param this the service on which the "service-changed" event is fired + * \param self the service on which the "service-changed" event is fired */ -static void mlt_service_filter_changed( mlt_service owner, mlt_service this ) +static void mlt_service_filter_changed( mlt_service owner, mlt_service self ) { - mlt_events_fire( MLT_SERVICE_PROPERTIES( this ), "service-changed", NULL ); + mlt_events_fire( MLT_SERVICE_PROPERTIES( self ), "service-changed", NULL ); } /** Attach a filter. * * \public \memberof mlt_service_s - * \param this a service + * \param self a service * \param filter the filter to attach * \return true if there was an error */ -int mlt_service_attach( mlt_service this, mlt_filter filter ) +int mlt_service_attach( mlt_service self, mlt_filter filter ) { - int error = this == NULL || filter == NULL; + int error = self == NULL || filter == NULL; if ( error == 0 ) { int i = 0; - mlt_properties properties = MLT_SERVICE_PROPERTIES( this ); - mlt_service_base *base = this->local; + mlt_properties properties = MLT_SERVICE_PROPERTIES( self ); + mlt_service_base *base = self->local; for ( i = 0; error == 0 && i < base->filter_count; i ++ ) if ( base->filters[ i ] == filter ) @@ -555,11 +555,11 @@ mlt_properties props = MLT_FILTER_PROPERTIES( filter ); mlt_properties_inc_ref( MLT_FILTER_PROPERTIES( filter ) ); base->filters[ base->filter_count ++ ] = filter; - mlt_properties_set_data( props, "service", this, 0, NULL, NULL ); + mlt_properties_set_data( props, "service", self, 0, NULL, NULL ); mlt_events_fire( properties, "service-changed", NULL ); mlt_events_fire( props, "service-changed", NULL ); - mlt_events_listen( props, this, "service-changed", ( mlt_listener )mlt_service_filter_changed ); - mlt_events_listen( props, this, "property-changed", ( mlt_listener )mlt_service_filter_changed ); + mlt_events_listen( props, self, "service-changed", ( mlt_listener )mlt_service_filter_changed ); + mlt_events_listen( props, self, "property-changed", ( mlt_listener )mlt_service_filter_changed ); } else { @@ -573,19 +573,19 @@ /** Detach a filter. * * \public \memberof mlt_service_s - * \param this a service + * \param self a service * \param filter the filter to detach * \return true if there was an error */ -int mlt_service_detach( mlt_service this, mlt_filter filter ) +int mlt_service_detach( mlt_service self, mlt_filter filter ) { - int error = this == NULL || filter == NULL; + int error = self == NULL || filter == NULL; if ( error == 0 ) { int i = 0; - mlt_service_base *base = this->local; - mlt_properties properties = MLT_SERVICE_PROPERTIES( this ); + mlt_service_base *base = self->local; + mlt_properties properties = MLT_SERVICE_PROPERTIES( self ); for ( i = 0; i < base->filter_count; i ++ ) if ( base->filters[ i ] == filter ) @@ -597,7 +597,7 @@ for ( i ++ ; i < base->filter_count; i ++ ) base->filters[ i - 1 ] = base->filters[ i ]; base->filter_count --; - mlt_events_disconnect( MLT_FILTER_PROPERTIES( filter ), this ); + mlt_events_disconnect( MLT_FILTER_PROPERTIES( filter ), self ); mlt_filter_close( filter ); mlt_events_fire( properties, "service-changed", NULL ); } @@ -608,17 +608,17 @@ /** Retrieve a filter. * * \public \memberof mlt_service_s - * \param this a service + * \param self a service * \param index which one of potentially multiple filters * \return the filter or null if there was an error */ -mlt_filter mlt_service_filter( mlt_service this, int index ) +mlt_filter mlt_service_filter( mlt_service self, int index ) { mlt_filter filter = NULL; - if ( this != NULL ) + if ( self != NULL ) { - mlt_service_base *base = this->local; + mlt_service_base *base = self->local; if ( index >= 0 && index < base->filter_count ) filter = base->filters[ index ]; } @@ -628,46 +628,46 @@ /** Retrieve the profile. * * \public \memberof mlt_service_s - * \param this a service + * \param self a service * \return the profile */ -mlt_profile mlt_service_profile( mlt_service this ) +mlt_profile mlt_service_profile( mlt_service self ) { - return mlt_properties_get_data( MLT_SERVICE_PROPERTIES( this ), "_profile", NULL ); + return self? mlt_properties_get_data( MLT_SERVICE_PROPERTIES( self ), "_profile", NULL ) : NULL; } /** Destroy a service. * * \public \memberof mlt_service_s - * \param this the service to destroy + * \param self the service to destroy */ -void mlt_service_close( mlt_service this ) +void mlt_service_close( mlt_service self ) { - if ( this != NULL && mlt_properties_dec_ref( MLT_SERVICE_PROPERTIES( this ) ) <= 0 ) + if ( self != NULL && mlt_properties_dec_ref( MLT_SERVICE_PROPERTIES( self ) ) <= 0 ) { - if ( this->close != NULL ) + if ( self->close != NULL ) { - this->close( this->close_object ); + self->close( self->close_object ); } else { - mlt_service_base *base = this->local; + mlt_service_base *base = self->local; int i = 0; int count = base->filter_count; - mlt_events_block( MLT_SERVICE_PROPERTIES( this ), this ); + mlt_events_block( MLT_SERVICE_PROPERTIES( self ), self ); while( count -- ) - mlt_service_detach( this, base->filters[ 0 ] ); + mlt_service_detach( self, base->filters[ 0 ] ); free( base->filters ); for ( i = 0; i < base->count; i ++ ) if ( base->in[ i ] != NULL ) mlt_service_close( base->in[ i ] ); - this->parent.close = NULL; + self->parent.close = NULL; free( base->in ); pthread_mutex_destroy( &base->mutex ); free( base ); - mlt_properties_close( &this->parent ); + mlt_properties_close( &self->parent ); } } } diff -Nru mlt-0.6.2/src/framework/mlt_tokeniser.h mlt-0.7.2/src/framework/mlt_tokeniser.h --- mlt-0.6.2/src/framework/mlt_tokeniser.h 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_tokeniser.h 2011-05-02 05:59:12.000000000 +0000 @@ -41,10 +41,10 @@ */ extern mlt_tokeniser mlt_tokeniser_init( ); -extern int mlt_tokeniser_parse_new( mlt_tokeniser self, char *text, const char *delimiter ); -extern char *mlt_tokeniser_get_input( mlt_tokeniser self ); -extern int mlt_tokeniser_count( mlt_tokeniser self ); -extern char *mlt_tokeniser_get_string( mlt_tokeniser self, int index ); -extern void mlt_tokeniser_close( mlt_tokeniser self ); +extern int mlt_tokeniser_parse_new( mlt_tokeniser tokeniser, char *text, const char *delimiter ); +extern char *mlt_tokeniser_get_input( mlt_tokeniser tokeniser ); +extern int mlt_tokeniser_count( mlt_tokeniser tokeniser ); +extern char *mlt_tokeniser_get_string( mlt_tokeniser tokeniser, int index ); +extern void mlt_tokeniser_close( mlt_tokeniser tokeniser ); #endif diff -Nru mlt-0.6.2/src/framework/mlt_tractor.c mlt-0.7.2/src/framework/mlt_tractor.c --- mlt-0.6.2/src/framework/mlt_tractor.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_tractor.c 2011-05-02 05:59:12.000000000 +0000 @@ -36,7 +36,7 @@ */ static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int track ); -static void mlt_tractor_listener( mlt_multitrack tracks, mlt_tractor this ); +static void mlt_tractor_listener( mlt_multitrack tracks, mlt_tractor self ); /** Construct a tractor without a field or multitrack. * @@ -49,11 +49,11 @@ mlt_tractor mlt_tractor_init( ) { - mlt_tractor this = calloc( sizeof( struct mlt_tractor_s ), 1 ); - if ( this != NULL ) + mlt_tractor self = calloc( sizeof( struct mlt_tractor_s ), 1 ); + if ( self != NULL ) { - mlt_producer producer = &this->parent; - if ( mlt_producer_init( producer, this ) == 0 ) + mlt_producer producer = &self->parent; + if ( mlt_producer_init( producer, self ) == 0 ) { mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); @@ -66,15 +66,15 @@ producer->get_frame = producer_get_frame; producer->close = ( mlt_destructor )mlt_tractor_close; - producer->close_object = this; + producer->close_object = self; } else { - free( this ); - this = NULL; + free( self ); + self = NULL; } } - return this; + return self; } /** Construct a tractor as well as a field and multitrack. @@ -88,14 +88,14 @@ mlt_tractor mlt_tractor_new( ) { - mlt_tractor this = calloc( sizeof( struct mlt_tractor_s ), 1 ); - if ( this != NULL ) + mlt_tractor self = calloc( sizeof( struct mlt_tractor_s ), 1 ); + if ( self != NULL ) { - mlt_producer producer = &this->parent; - if ( mlt_producer_init( producer, this ) == 0 ) + mlt_producer producer = &self->parent; + if ( mlt_producer_init( producer, self ) == 0 ) { mlt_multitrack multitrack = mlt_multitrack_init( ); - mlt_field field = mlt_field_new( multitrack, this ); + mlt_field field = mlt_field_new( multitrack, self ); mlt_properties props = MLT_PRODUCER_PROPERTIES( producer ); mlt_properties_set( props, "resource", "" ); @@ -107,125 +107,125 @@ mlt_properties_set_data( props, "multitrack", multitrack, 0, ( mlt_destructor )mlt_multitrack_close, NULL ); mlt_properties_set_data( props, "field", field, 0, ( mlt_destructor )mlt_field_close, NULL ); - mlt_events_listen( MLT_MULTITRACK_PROPERTIES( multitrack ), this, "producer-changed", ( mlt_listener )mlt_tractor_listener ); + mlt_events_listen( MLT_MULTITRACK_PROPERTIES( multitrack ), self, "producer-changed", ( mlt_listener )mlt_tractor_listener ); producer->get_frame = producer_get_frame; producer->close = ( mlt_destructor )mlt_tractor_close; - producer->close_object = this; + producer->close_object = self; } else { - free( this ); - this = NULL; + free( self ); + self = NULL; } } - return this; + return self; } /** Get the service object associated to the tractor. * * \public \memberof mlt_tractor_s - * \param this a tractor + * \param self a tractor * \return the parent service object * \see MLT_TRACTOR_SERVICE */ -mlt_service mlt_tractor_service( mlt_tractor this ) +mlt_service mlt_tractor_service( mlt_tractor self ) { - return MLT_PRODUCER_SERVICE( &this->parent ); + return MLT_PRODUCER_SERVICE( &self->parent ); } /** Get the producer object associated to the tractor. * * \public \memberof mlt_tractor_s - * \param this a tractor + * \param self a tractor * \return the parent producer object * \see MLT_TRACTOR_PRODUCER */ -mlt_producer mlt_tractor_producer( mlt_tractor this ) +mlt_producer mlt_tractor_producer( mlt_tractor self ) { - return this != NULL ? &this->parent : NULL; + return self != NULL ? &self->parent : NULL; } /** Get the properties object associated to the tractor. * * \public \memberof mlt_tractor_s - * \param this a tractor + * \param self a tractor * \return the tractor's property list * \see MLT_TRACTOR_PROPERTIES */ -mlt_properties mlt_tractor_properties( mlt_tractor this ) +mlt_properties mlt_tractor_properties( mlt_tractor self ) { - return MLT_PRODUCER_PROPERTIES( &this->parent ); + return MLT_PRODUCER_PROPERTIES( &self->parent ); } -/** Get the field this tractor is harvesting. +/** Get the field self tractor is harvesting. * * \public \memberof mlt_tractor_s - * \param this a tractor + * \param self a tractor * \return a field or NULL if there is no field for this tractor */ -mlt_field mlt_tractor_field( mlt_tractor this ) +mlt_field mlt_tractor_field( mlt_tractor self ) { - return mlt_properties_get_data( MLT_TRACTOR_PROPERTIES( this ), "field", NULL ); + return mlt_properties_get_data( MLT_TRACTOR_PROPERTIES( self ), "field", NULL ); } -/** Get the multitrack this tractor is pulling. +/** Get the multitrack a tractor is pulling. * * \public \memberof mlt_tractor_s - * \param this a tractor + * \param self a tractor * \return a multitrack or NULL if there is none */ -mlt_multitrack mlt_tractor_multitrack( mlt_tractor this ) +mlt_multitrack mlt_tractor_multitrack( mlt_tractor self ) { - return mlt_properties_get_data( MLT_TRACTOR_PROPERTIES( this ), "multitrack", NULL ); + return mlt_properties_get_data( MLT_TRACTOR_PROPERTIES( self ), "multitrack", NULL ); } /** Ensure the tractors in/out points match the multitrack. * * \public \memberof mlt_tractor_s - * \param this a tractor + * \param self a tractor */ -void mlt_tractor_refresh( mlt_tractor this ) +void mlt_tractor_refresh( mlt_tractor self ) { - mlt_multitrack multitrack = mlt_tractor_multitrack( this ); - mlt_properties properties = MLT_MULTITRACK_PROPERTIES( multitrack ); - mlt_properties self = MLT_TRACTOR_PROPERTIES( this ); - mlt_events_block( properties, self ); - mlt_events_block( self, self ); + mlt_multitrack multitrack = mlt_tractor_multitrack( self ); + mlt_properties multitrack_props = MLT_MULTITRACK_PROPERTIES( multitrack ); + mlt_properties properties = MLT_TRACTOR_PROPERTIES( self ); + mlt_events_block( multitrack_props, properties ); + mlt_events_block( properties, properties ); mlt_multitrack_refresh( multitrack ); - mlt_properties_set_position( self, "in", 0 ); - mlt_properties_set_position( self, "out", mlt_properties_get_position( properties, "out" ) ); - mlt_events_unblock( self, self ); - mlt_events_unblock( properties, self ); - mlt_properties_set_position( self, "length", mlt_properties_get_position( properties, "length" ) ); + mlt_properties_set_position( properties, "in", 0 ); + mlt_properties_set_position( properties, "out", mlt_properties_get_position( multitrack_props, "out" ) ); + mlt_events_unblock( properties, properties ); + mlt_events_unblock( multitrack_props, properties ); + mlt_properties_set_position( properties, "length", mlt_properties_get_position( multitrack_props, "length" ) ); } -static void mlt_tractor_listener( mlt_multitrack tracks, mlt_tractor this ) +static void mlt_tractor_listener( mlt_multitrack tracks, mlt_tractor self ) { - mlt_tractor_refresh( this ); + mlt_tractor_refresh( self ); } /** Connect the tractor. * * \public \memberof mlt_tractor_s - * \param this a tractor + * \param self a tractor * \param producer a producer * \return true on error */ -int mlt_tractor_connect( mlt_tractor this, mlt_service producer ) +int mlt_tractor_connect( mlt_tractor self, mlt_service producer ) { - int ret = mlt_service_connect_producer( MLT_TRACTOR_SERVICE( this ), producer, 0 ); + int ret = mlt_service_connect_producer( MLT_TRACTOR_SERVICE( self ), producer, 0 ); // This is the producer we're going to connect to if ( ret == 0 ) - this->producer = producer; + self->producer = producer; return ret; } @@ -233,36 +233,36 @@ /** Set the producer for a specific track. * * \public \memberof mlt_tractor_s - * \param this a tractor + * \param self a tractor * \param producer a producer * \param index the 0-based track index * \return true on error */ -int mlt_tractor_set_track( mlt_tractor this, mlt_producer producer, int index ) +int mlt_tractor_set_track( mlt_tractor self, mlt_producer producer, int index ) { - return mlt_multitrack_connect( mlt_tractor_multitrack( this ), producer, index ); + return mlt_multitrack_connect( mlt_tractor_multitrack( self ), producer, index ); } /** Get the producer for a specific track. * * \public \memberof mlt_tractor_s - * \param this a tractor + * \param self a tractor * \param index the 0-based track index * \return the producer for track \p index */ -mlt_producer mlt_tractor_get_track( mlt_tractor this, int index ) +mlt_producer mlt_tractor_get_track( mlt_tractor self, int index ) { - return mlt_multitrack_track( mlt_tractor_multitrack( this ), index ); + return mlt_multitrack_track( mlt_tractor_multitrack( self ), index ); } -static int producer_get_image( mlt_frame this, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) +static int producer_get_image( mlt_frame self, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { uint8_t *data = NULL; int size = 0; - mlt_properties properties = MLT_FRAME_PROPERTIES( this ); - mlt_frame frame = mlt_frame_pop_service( this ); + mlt_properties properties = MLT_FRAME_PROPERTIES( self ); + mlt_frame frame = mlt_frame_pop_service( self ); mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); mlt_properties_set( frame_properties, "rescale.interp", mlt_properties_get( properties, "rescale.interp" ) ); mlt_properties_set_int( frame_properties, "resize_alpha", mlt_properties_get_int( properties, "resize_alpha" ) ); @@ -273,7 +273,7 @@ mlt_properties_set_int( frame_properties, "normalised_width", mlt_properties_get_int( properties, "normalised_width" ) ); mlt_properties_set_int( frame_properties, "normalised_height", mlt_properties_get_int( properties, "normalised_height" ) ); mlt_frame_get_image( frame, buffer, format, width, height, writable ); - mlt_properties_set_data( properties, "image", *buffer, *width * *height * 2, NULL, NULL ); + mlt_frame_set_image( self, *buffer, 0, NULL ); mlt_properties_set_int( properties, "width", *width ); mlt_properties_set_int( properties, "height", *height ); mlt_properties_set_int( properties, "format", *format ); @@ -284,16 +284,18 @@ mlt_properties_set_int( properties, "force_full_luma", mlt_properties_get_int( frame_properties, "force_full_luma" ) ); data = mlt_frame_get_alpha_mask( frame ); mlt_properties_get_data( frame_properties, "alpha", &size ); - mlt_properties_set_data( properties, "alpha", data, size, NULL, NULL ); + mlt_frame_set_alpha( self, data, size, NULL ); + self->convert_image = frame->convert_image; + self->convert_audio = frame->convert_audio; return 0; } -static int producer_get_audio( mlt_frame this, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) +static int producer_get_audio( mlt_frame self, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { - mlt_properties properties = MLT_FRAME_PROPERTIES( this ); - mlt_frame frame = mlt_frame_pop_audio( this ); + mlt_properties properties = MLT_FRAME_PROPERTIES( self ); + mlt_frame frame = mlt_frame_pop_audio( self ); mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); - mlt_properties_set_data( properties, "audio", *buffer, 0, NULL, NULL ); + mlt_frame_set_audio( self, *buffer, *format, mlt_audio_format_size( *format, *samples, *channels ), NULL ); mlt_properties_set_int( properties, "frequency", *frequency ); mlt_properties_set_int( properties, "channels", *channels ); return 0; @@ -326,10 +328,10 @@ static int producer_get_frame( mlt_producer parent, mlt_frame_ptr frame, int track ) { - mlt_tractor this = parent->child; + mlt_tractor self = parent->child; // We only respond to the first track requests - if ( track == 0 && this->producer != NULL ) + if ( track == 0 && self->producer != NULL ) { int i = 0; int done = 0; @@ -387,20 +389,22 @@ for ( i = 0; !done; i ++ ) { // Get a frame from the producer - mlt_service_get_frame( this->producer, &temp, i ); + mlt_service_get_frame( self->producer, &temp, i ); // Get the temporary properties temp_properties = MLT_FRAME_PROPERTIES( temp ); // Pass all unique meta properties from the producer's frame to the new frame + mlt_properties_lock( temp_properties ); int props_count = mlt_properties_count( temp_properties ); int j; for ( j = 0; j < props_count; j ++ ) { char *name = mlt_properties_get_name( temp_properties, j ); if ( !strncmp( name, "meta.", 5 ) && !mlt_properties_get( frame_properties, name ) ) - mlt_properties_set( frame_properties, name, mlt_properties_get( temp_properties, name ) ); + mlt_properties_set( frame_properties, name, mlt_properties_get_value( temp_properties, j ) ); } + mlt_properties_unlock( temp_properties ); // Copy the format conversion virtual functions if ( ! (*frame)->convert_image && temp->convert_image ) @@ -514,18 +518,17 @@ mlt_frame_set_position( *frame, mlt_producer_frame( parent ) ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( *frame ), "test_audio", audio == NULL ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( *frame ), "test_image", video == NULL ); - mlt_properties_set_data( MLT_FRAME_PROPERTIES( *frame ), "consumer_lock_service", this, 0, NULL, NULL ); } else if ( producer != NULL ) { mlt_producer_seek( producer, mlt_producer_frame( parent ) ); mlt_producer_set_speed( producer, mlt_producer_get_speed( parent ) ); - mlt_service_get_frame( this->producer, frame, track ); + mlt_service_get_frame( self->producer, frame, track ); } else { mlt_log( MLT_PRODUCER_SERVICE( parent ), MLT_LOG_ERROR, "tractor without a multitrack!!\n" ); - mlt_service_get_frame( this->producer, frame, track ); + mlt_service_get_frame( self->producer, frame, track ); } // Prepare the next frame @@ -545,16 +548,16 @@ /** Close the tractor and free its resources. * * \public \memberof mlt_tractor_s - * \param this a tractor + * \param self a tractor */ -void mlt_tractor_close( mlt_tractor this ) +void mlt_tractor_close( mlt_tractor self ) { - if ( this != NULL && mlt_properties_dec_ref( MLT_TRACTOR_PROPERTIES( this ) ) <= 0 ) + if ( self != NULL && mlt_properties_dec_ref( MLT_TRACTOR_PROPERTIES( self ) ) <= 0 ) { - this->parent.close = NULL; - mlt_producer_close( &this->parent ); - free( this ); + self->parent.close = NULL; + mlt_producer_close( &self->parent ); + free( self ); } } diff -Nru mlt-0.6.2/src/framework/mlt_transition.c mlt-0.7.2/src/framework/mlt_transition.c --- mlt-0.6.2/src/framework/mlt_transition.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_transition.c 2011-05-02 05:59:12.000000000 +0000 @@ -24,6 +24,7 @@ #include "mlt_transition.h" #include "mlt_frame.h" #include "mlt_log.h" +#include "mlt_producer.h" #include #include @@ -31,28 +32,28 @@ /* Forward references */ -static int transition_get_frame( mlt_service this, mlt_frame_ptr frame, int index ); +static int transition_get_frame( mlt_service self, mlt_frame_ptr frame, int index ); /** Initialize a new transition. * * \public \memberof mlt_transition_s - * \param this a transition + * \param self a transition * \param child the object of a subclass * \return true on error */ -int mlt_transition_init( mlt_transition this, void *child ) +int mlt_transition_init( mlt_transition self, void *child ) { - mlt_service service = &this->parent; - memset( this, 0, sizeof( struct mlt_transition_s ) ); - this->child = child; - if ( mlt_service_init( service, this ) == 0 ) + mlt_service service = &self->parent; + memset( self, 0, sizeof( struct mlt_transition_s ) ); + self->child = child; + if ( mlt_service_init( service, self ) == 0 ) { - mlt_properties properties = MLT_TRANSITION_PROPERTIES( this ); + mlt_properties properties = MLT_TRANSITION_PROPERTIES( self ); service->get_frame = transition_get_frame; service->close = ( mlt_destructor )mlt_transition_close; - service->close_object = this; + service->close_object = self; mlt_properties_set_position( properties, "in", 0 ); mlt_properties_set_position( properties, "out", 0 ); @@ -72,55 +73,55 @@ mlt_transition mlt_transition_new( ) { - mlt_transition this = calloc( 1, sizeof( struct mlt_transition_s ) ); - if ( this != NULL ) - mlt_transition_init( this, NULL ); - return this; + mlt_transition self = calloc( 1, sizeof( struct mlt_transition_s ) ); + if ( self != NULL ) + mlt_transition_init( self, NULL ); + return self; } /** Get the service class interface. * * \public \memberof mlt_transition_s - * \param this a transition + * \param self a transition * \return the service class * \see MLT_TRANSITION_SERVICE */ -mlt_service mlt_transition_service( mlt_transition this ) +mlt_service mlt_transition_service( mlt_transition self ) { - return this != NULL ? &this->parent : NULL; + return self != NULL ? &self->parent : NULL; } /** Get the properties interface. * * \public \memberof mlt_transition_s - * \param this a transition + * \param self a transition * \return the transition's properties * \see MLT_TRANSITION_PROPERTIES */ -mlt_properties mlt_transition_properties( mlt_transition this ) +mlt_properties mlt_transition_properties( mlt_transition self ) { - return MLT_TRANSITION_PROPERTIES( this ); + return MLT_TRANSITION_PROPERTIES( self ); } -/** Connect this transition with a producers a and b tracks. +/** Connect a transition with a producer's a and b tracks. * * \public \memberof mlt_transition_s - * \param this a transition + * \param self a transition * \param producer a producer * \param a_track the track index of the first input * \param b_track the track index of the second index * \return true on error */ -int mlt_transition_connect( mlt_transition this, mlt_service producer, int a_track, int b_track ) +int mlt_transition_connect( mlt_transition self, mlt_service producer, int a_track, int b_track ) { - int ret = mlt_service_connect_producer( &this->parent, producer, a_track ); + int ret = mlt_service_connect_producer( &self->parent, producer, a_track ); if ( ret == 0 ) { - mlt_properties properties = MLT_TRANSITION_PROPERTIES( this ); - this->producer = producer; + mlt_properties properties = MLT_TRANSITION_PROPERTIES( self ); + self->producer = producer; mlt_properties_set_int( properties, "a_track", a_track ); mlt_properties_set_int( properties, "b_track", b_track ); } @@ -130,14 +131,14 @@ /** Set the starting and ending time for when the transition is active. * * \public \memberof mlt_transition_s - * \param this a transition + * \param self a transition * \param in the starting time * \param out the ending time */ -void mlt_transition_set_in_and_out( mlt_transition this, mlt_position in, mlt_position out ) +void mlt_transition_set_in_and_out( mlt_transition self, mlt_position in, mlt_position out ) { - mlt_properties properties = MLT_TRANSITION_PROPERTIES( this ); + mlt_properties properties = MLT_TRANSITION_PROPERTIES( self ); mlt_properties_set_position( properties, "in", in ); mlt_properties_set_position( properties, "out", out ); } @@ -145,49 +146,148 @@ /** Get the index of the a track. * * \public \memberof mlt_transition_s - * \param this a transition + * \param self a transition * \return the 0-based index of the track of the first producer */ -int mlt_transition_get_a_track( mlt_transition this ) +int mlt_transition_get_a_track( mlt_transition self ) { - return mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( this ), "a_track" ); + return mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( self ), "a_track" ); } /** Get the index of the b track. * * \public \memberof mlt_transition_s - * \param this a transition + * \param self a transition * \return the 0-based index of the track of the second producer */ -int mlt_transition_get_b_track( mlt_transition this ) +int mlt_transition_get_b_track( mlt_transition self ) { - return mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( this ), "b_track" ); + return mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( self ), "b_track" ); } /** Get the in point. * * \public \memberof mlt_transition_s - * \param this a transition + * \param self a transition * \return the starting time */ -mlt_position mlt_transition_get_in( mlt_transition this ) +mlt_position mlt_transition_get_in( mlt_transition self ) { - return mlt_properties_get_position( MLT_TRANSITION_PROPERTIES( this ), "in" ); + return mlt_properties_get_position( MLT_TRANSITION_PROPERTIES( self ), "in" ); } /** Get the out point. * * \public \memberof mlt_transition_s - * \param this a transition + * \param self a transition * \return the ending time */ -mlt_position mlt_transition_get_out( mlt_transition this ) +mlt_position mlt_transition_get_out( mlt_transition self ) { - return mlt_properties_get_position( MLT_TRANSITION_PROPERTIES( this ), "out" ); + return mlt_properties_get_position( MLT_TRANSITION_PROPERTIES( self ), "out" ); +} + +/** Get the duration. + * + * \public \memberof mlt_transition_s + * \param self a transition + * \return the duration or zero if unlimited + */ + +mlt_position mlt_transition_get_length( mlt_transition self ) +{ + mlt_properties properties = MLT_SERVICE_PROPERTIES( &self->parent ); + mlt_position in = mlt_properties_get_position( properties, "in" ); + mlt_position out = mlt_properties_get_position( properties, "out" ); + return ( out > 0 ) ? ( out - in + 1 ) : 0; +} + +/** Get the position within the transition. + * + * The position is relative to the in point. + * + * \public \memberof mlt_transition_s + * \param self a transition + * \param frame a frame + * \return the position + */ + +mlt_position mlt_transition_get_position( mlt_transition self, mlt_frame frame ) +{ + mlt_position in = mlt_transition_get_in( self ); + mlt_position position = mlt_frame_get_position( frame ); + return position - in; +} + +/** Get the percent complete. + * + * \public \memberof mlt_transition_s + * \param self a transition + * \param frame a frame + * \return the progress in the range 0.0 to 1.0 + */ + +double mlt_transition_get_progress( mlt_transition self, mlt_frame frame ) +{ + double progress = 0; + mlt_position in = mlt_transition_get_in( self ); + mlt_position out = mlt_transition_get_out( self ); + + if ( out == 0 ) + { + // If always active, use the frame's producer + mlt_producer producer = mlt_frame_get_original_producer( frame ); + if ( producer ) + { + in = mlt_producer_get_in( producer ); + out = mlt_producer_get_out( producer ); + } + } + if ( out != 0 ) + { + mlt_position position = mlt_frame_get_position( frame ); + progress = ( double ) ( position - in ) / ( double ) ( out - in + 1 ); + } + return progress; +} + +/** Get the second field incremental progress. + * + * \public \memberof mlt_transition_s + * \param self a transition + * \param frame a frame + * \return the progress increment in the range 0.0 to 1.0 + */ + +double mlt_transition_get_progress_delta( mlt_transition self, mlt_frame frame ) +{ + double progress = 0; + mlt_position in = mlt_transition_get_in( self ); + mlt_position out = mlt_transition_get_out( self ); + + if ( out == 0 ) + { + // If always active, use the frame's producer + mlt_producer producer = mlt_frame_get_original_producer( frame ); + if ( producer ) + { + in = mlt_producer_get_in( producer ); + out = mlt_producer_get_out( producer ); + } + } + if ( out != 0 ) + { + mlt_position position = mlt_frame_get_position( frame ); + double length = out - in + 1; + double x = ( double ) ( position - in ) / length; + double y = ( double ) ( position + 1 - in ) / length; + progress = length * ( y - x ) / 2.0; + } + return progress; } /** Process the frame. @@ -195,21 +295,21 @@ * If we have no process method (unlikely), we simply return the a_frame unmolested. * * \public \memberof mlt_transition_s - * \param this a transition + * \param self a transition * \param a_frame a frame from the first producer * \param b_frame a frame from the second producer * \return a frame */ -mlt_frame mlt_transition_process( mlt_transition this, mlt_frame a_frame, mlt_frame b_frame ) +mlt_frame mlt_transition_process( mlt_transition self, mlt_frame a_frame, mlt_frame b_frame ) { - if ( this->process == NULL ) + if ( self->process == NULL ) return a_frame; else - return this->process( this, a_frame, b_frame ); + return self->process( self, a_frame, b_frame ); } -/** Get a frame from this transition. +/** Get a frame from a transition. The logic is complex here. A transition is typically applied to frames on the a and b tracks specified in the connect method above and only if both contain valid info @@ -250,9 +350,9 @@ static int transition_get_frame( mlt_service service, mlt_frame_ptr frame, int index ) { int error = 0; - mlt_transition this = service->child; + mlt_transition self = service->child; - mlt_properties properties = MLT_TRANSITION_PROPERTIES( this ); + mlt_properties properties = MLT_TRANSITION_PROPERTIES( self ); int accepts_blanks = mlt_properties_get_int( properties, "accepts_blanks" ); int a_track = mlt_properties_get_int( properties, "a_track" ); @@ -272,7 +372,7 @@ } // Only act on this operation once per multitrack iteration from the tractor - if ( !this->held ) + if ( !self->held ) { int active = 0; int i = 0; @@ -282,15 +382,15 @@ int ( *invalid )( mlt_frame ) = type == 1 ? mlt_frame_is_test_card : mlt_frame_is_test_audio; // Initialise temporary store - if ( this->frames == NULL ) - this->frames = calloc( sizeof( mlt_frame ), b_track + 1 ); + if ( self->frames == NULL ) + self->frames = calloc( sizeof( mlt_frame ), b_track + 1 ); // Get all frames between a and b for( i = a_track; i <= b_track; i ++ ) - mlt_service_get_frame( this->producer, &this->frames[ i ], i ); + mlt_service_get_frame( self->producer, &self->frames[ i ], i ); // We're holding these frames until the last_track frame property is received - this->held = 1; + self->held = 1; // When we need to locate the a_frame switch( type ) @@ -304,11 +404,11 @@ if ( !active ) { // Hunt for the a_frame - while( a_frame <= b_frame && invalid( this->frames[ a_frame ] ) ) + while( a_frame <= b_frame && invalid( self->frames[ a_frame ] ) ) a_frame ++; // Determine if we're active now - active = a_frame != b_frame && !invalid( this->frames[ b_frame ] ); + active = a_frame != b_frame && !invalid( self->frames[ b_frame ] ); } break; @@ -321,23 +421,23 @@ if ( active && !always_active ) { // For non-always-active transitions, we need the current position of the a frame - position = mlt_frame_get_position( this->frames[ a_frame ] ); + position = mlt_frame_get_position( self->frames[ a_frame ] ); // If a is in range, we're active - active = position >= in && position <= out; + active = position >= in && ( out == 0 || position <= out ); } // Finally, process the a and b frames if ( active ) { - mlt_frame a_frame_ptr = this->frames[ !reverse_order ? a_frame : b_frame ]; - mlt_frame b_frame_ptr = this->frames[ !reverse_order ? b_frame : a_frame ]; + mlt_frame a_frame_ptr = self->frames[ !reverse_order ? a_frame : b_frame ]; + mlt_frame b_frame_ptr = self->frames[ !reverse_order ? b_frame : a_frame ]; int a_hide = mlt_properties_get_int( MLT_FRAME_PROPERTIES( a_frame_ptr ), "hide" ); int b_hide = mlt_properties_get_int( MLT_FRAME_PROPERTIES( b_frame_ptr ), "hide" ); if ( !( a_hide & type ) && !( b_hide & type ) ) { // Process the transition - *frame = mlt_transition_process( this, a_frame_ptr, b_frame_ptr ); + *frame = mlt_transition_process( self, a_frame_ptr, b_frame_ptr ); // We need to ensure that the tractor doesn't consider this frame for output if ( *frame == a_frame_ptr ) @@ -353,12 +453,12 @@ // Obtain the frame from the cache or the producer we're attached to if ( index >= a_track && index <= b_track ) - *frame = this->frames[ index ]; + *frame = self->frames[ index ]; else - error = mlt_service_get_frame( this->producer, frame, index ); + error = mlt_service_get_frame( self->producer, frame, index ); // Determine if that was the last track - this->held = !mlt_properties_get_int( MLT_FRAME_PROPERTIES( *frame ), "last_track" ); + self->held = !mlt_properties_get_int( MLT_FRAME_PROPERTIES( *frame ), "last_track" ); return error; } @@ -366,23 +466,23 @@ /** Close and destroy the transition. * * \public \memberof mlt_transition_s - * \param this a transition + * \param self a transition */ -void mlt_transition_close( mlt_transition this ) +void mlt_transition_close( mlt_transition self ) { - if ( this != NULL && mlt_properties_dec_ref( MLT_TRANSITION_PROPERTIES( this ) ) <= 0 ) + if ( self != NULL && mlt_properties_dec_ref( MLT_TRANSITION_PROPERTIES( self ) ) <= 0 ) { - this->parent.close = NULL; - if ( this->close != NULL ) + self->parent.close = NULL; + if ( self->close != NULL ) { - this->close( this ); + self->close( self ); } else { - mlt_service_close( &this->parent ); - free( this->frames ); - free( this ); + mlt_service_close( &self->parent ); + free( self->frames ); + free( self ); } } } diff -Nru mlt-0.6.2/src/framework/mlt_transition.h mlt-0.7.2/src/framework/mlt_transition.h --- mlt-0.6.2/src/framework/mlt_transition.h 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_transition.h 2011-05-02 05:59:12.000000000 +0000 @@ -73,6 +73,10 @@ extern int mlt_transition_get_b_track( mlt_transition self ); extern mlt_position mlt_transition_get_in( mlt_transition self ); extern mlt_position mlt_transition_get_out( mlt_transition self ); +extern mlt_position mlt_transition_get_length( mlt_transition self ); +extern mlt_position mlt_transition_get_position( mlt_transition self, mlt_frame frame ); +extern double mlt_transition_get_progress( mlt_transition self, mlt_frame frame ); +extern double mlt_transition_get_progress_delta( mlt_transition self, mlt_frame frame ); extern mlt_frame mlt_transition_process( mlt_transition self, mlt_frame a_frame, mlt_frame b_frame ); extern void mlt_transition_close( mlt_transition self ); diff -Nru mlt-0.6.2/src/framework/mlt_types.h mlt-0.7.2/src/framework/mlt_types.h --- mlt-0.6.2/src/framework/mlt_types.h 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_types.h 2011-05-02 05:59:12.000000000 +0000 @@ -27,7 +27,7 @@ #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) #endif -#include +#include #include "mlt_pool.h" @@ -116,13 +116,14 @@ typedef void ( *mlt_destructor )( void * ); /**< pointer to destructor function */ typedef char *( *mlt_serialiser )( void *, int length );/**< pointer to serialization function */ -#define MLT_SERVICE(x) ( ( mlt_service )( x ) ) /**< Cast to a Service pointer */ -#define MLT_PRODUCER(x) ( ( mlt_producer )( x ) ) /**< Cast to a Producer pointer */ +#define MLT_SERVICE(x) ( ( mlt_service )( x ) ) /**< Cast to a Service pointer */ +#define MLT_PRODUCER(x) ( ( mlt_producer )( x ) ) /**< Cast to a Producer pointer */ #define MLT_MULTITRACK(x) ( ( mlt_multitrack )( x ) ) /**< Cast to a Multitrack pointer */ -#define MLT_PLAYLIST(x) ( ( mlt_playlist )( x ) ) /**< Cast to a Playlist pointer */ -#define MLT_TRACTOR(x) ( ( mlt_tractor )( x ) ) /**< Cast to a Tractor pointer */ -#define MLT_FILTER(x) ( ( mlt_filter )( x ) ) /**< Cast to a Filter pointer */ +#define MLT_PLAYLIST(x) ( ( mlt_playlist )( x ) ) /**< Cast to a Playlist pointer */ +#define MLT_TRACTOR(x) ( ( mlt_tractor )( x ) ) /**< Cast to a Tractor pointer */ +#define MLT_FILTER(x) ( ( mlt_filter )( x ) ) /**< Cast to a Filter pointer */ #define MLT_TRANSITION(x) ( ( mlt_transition )( x ) ) /**< Cast to a Transition pointer */ #define MLT_CONSUMER(x) ( ( mlt_consumer )( x ) ) /**< Cast to a Consumer pointer */ +#define MLT_FRAME(x) ( ( mlt_frame )( x ) ) /**< Cast to a Frame pointer */ #endif diff -Nru mlt-0.6.2/src/framework/mlt_version.h mlt-0.7.2/src/framework/mlt_version.h --- mlt-0.6.2/src/framework/mlt_version.h 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/framework/mlt_version.h 2011-05-02 05:59:12.000000000 +0000 @@ -28,7 +28,7 @@ #define STRINGIZE(s) STRINGIZE2(s) #define LIBMLT_VERSION_MAJOR 0 -#define LIBMLT_VERSION_MINOR 6 +#define LIBMLT_VERSION_MINOR 7 #define LIBMLT_VERSION_REVISION 2 #define LIBMLT_VERSION_INT ((LIBMLT_VERSION_MAJOR<<16)+(LIBMLT_VERSION_MINOR<<8)+LIBMLT_VERSION_REVISION) #define LIBMLT_VERSION STRINGIZE(LIBMLT_VERSION_MAJOR.LIBMLT_VERSION_MINOR.LIBMLT_VERSION_REVISION) diff -Nru mlt-0.6.2/src/melt/io.c mlt-0.7.2/src/melt/io.c --- mlt-0.6.2/src/melt/io.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/melt/io.c 2011-05-02 05:59:12.000000000 +0000 @@ -27,7 +27,12 @@ #include #include #include +#ifndef WIN32 #include +#else +// MinGW defines struct timespec in pthread.h +#include +#endif #include #include @@ -102,11 +107,13 @@ void term_exit(void) { +#ifndef WIN32 if ( mode == 1 ) { tcsetattr( 0, TCSANOW, &oldtty ); mode = 0; } +#endif } /** Init terminal so that we can grab keys without blocking. @@ -114,6 +121,7 @@ void term_init( ) { +#ifndef WIN32 struct termios tty; tcgetattr( 0, &tty ); @@ -132,6 +140,7 @@ mode = 1; atexit( term_exit ); +#endif } /** Check for a keypress without blocking infinitely. @@ -140,6 +149,7 @@ int term_read( ) { +#ifndef WIN32 int n = 1; unsigned char ch; struct timeval tv; @@ -158,6 +168,10 @@ return ch; return n; } +#else + struct timespec tm = { 0, 40000 }; + nanosleep( &tm, NULL ); +#endif return -1; } diff -Nru mlt-0.6.2/src/melt/Makefile mlt-0.7.2/src/melt/Makefile --- mlt-0.6.2/src/melt/Makefile 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/melt/Makefile 2011-05-02 05:59:12.000000000 +0000 @@ -10,6 +10,14 @@ SRCS := $(OBJS:.o=.c) +ifeq ($(targetos), MinGW) +CFLAGS += `sdl-config --cflags` +LDFLAGS += `sdl-config --libs` +OBJS += ../win32/win32.o +SRCS += ../win32/win32.c +bindir = $(prefix) +endif + all: $(TARGET) $(TARGET): $(OBJS) diff -Nru mlt-0.6.2/src/melt/melt.c mlt-0.7.2/src/melt/melt.c --- mlt-0.6.2/src/melt/melt.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/melt/melt.c 2011-05-02 05:59:12.000000000 +0000 @@ -31,7 +31,7 @@ #include -#ifdef __DARWIN__ +#if defined(__DARWIN__) || defined(WIN32) #include #endif @@ -50,6 +50,7 @@ switch( value[ 0 ] ) { case 'q': + case 'Q': mlt_properties_set_int( properties, "done", 1 ); break; case '0': @@ -199,7 +200,7 @@ } } -#ifdef __DARWIN__ +#if defined(__DARWIN__) || defined(WIN32) static void event_handling( mlt_producer producer, mlt_consumer consumer ) { @@ -263,7 +264,7 @@ transport_action( producer, string ); } -#ifdef __DARWIN__ +#if defined(__DARWIN__) || defined(WIN32) event_handling( producer, consumer ); #endif @@ -323,6 +324,10 @@ " -query \"filters\" | \"filter\"=id List filters or show info about one\n" " -query \"producers\" | \"producer\"=id List producers or show info about one\n" " -query \"transitions\" | \"transition\"=id List transitions, show info about one\n" +" -query \"profiles\" | \"profile\"=id List profiles, show info about one\n" +" -query \"formats\" List audio/video formats\n" +" -query \"audio_codecs\" List audio codecs\n" +" -query \"video_codecs\" List video codecs\n" " -serialise [filename] Write the commands to a text file\n" " -silent Do not display position/transport\n" " -split relative-frame Split the last cut into two cuts\n" @@ -432,6 +437,82 @@ fprintf( stderr, "...\n" ); } +static void query_profiles() +{ + mlt_properties profiles = mlt_profile_list(); + fprintf( stderr, "---\nprofiles:\n" ); + if ( profiles ) + { + int j; + for ( j = 0; j < mlt_properties_count( profiles ); j++ ) + fprintf( stderr, " - %s\n", mlt_properties_get_name( profiles, j ) ); + } + fprintf( stderr, "...\n" ); + mlt_properties_close( profiles ); +} + +static void query_profile( const char *id ) +{ + mlt_properties profiles = mlt_profile_list(); + mlt_properties profile = mlt_properties_get_data( profiles, id, NULL ); + if ( profile ) + { + char *s = mlt_properties_serialise_yaml( profile ); + fprintf( stderr, "%s", s ); + free( s ); + } + else + { + fprintf( stderr, "# No metadata for profile \"%s\"\n", id ); + } + mlt_properties_close( profiles ); +} + +static void query_formats( ) +{ + mlt_consumer consumer = mlt_factory_consumer( NULL, "avformat", NULL ); + if ( consumer ) + { + mlt_properties_set( MLT_CONSUMER_PROPERTIES(consumer), "f", "list" ); + mlt_consumer_start( consumer ); + mlt_consumer_close( consumer ); + } + else + { + fprintf( stderr, "# No formats - failed to load avformat consumer\n" ); + } +} + +static void query_acodecs( ) +{ + mlt_consumer consumer = mlt_factory_consumer( NULL, "avformat", NULL ); + if ( consumer ) + { + mlt_properties_set( MLT_CONSUMER_PROPERTIES(consumer), "acodec", "list" ); + mlt_consumer_start( consumer ); + mlt_consumer_close( consumer ); + } + else + { + fprintf( stderr, "# No audio codecs - failed to load avformat consumer\n" ); + } +} + +static void query_vcodecs( ) +{ + mlt_consumer consumer = mlt_factory_consumer( NULL, "avformat", NULL ); + if ( consumer ) + { + mlt_properties_set( MLT_CONSUMER_PROPERTIES(consumer), "vcodec", "list" ); + mlt_consumer_start( consumer ); + mlt_consumer_close( consumer ); + } + else + { + fprintf( stderr, "# No video codecs - failed to load avformat consumer\n" ); + } +} + static void on_fatal_error( mlt_properties owner, mlt_consumer consumer ) { mlt_consumer_stop( consumer ); @@ -453,6 +534,10 @@ // Construct the factory mlt_repository repo = mlt_factory_init( NULL ); +#ifdef WIN32 + is_silent = 1; +#endif + for ( i = 1; i < argc; i ++ ) { // Check for serialisation switch @@ -493,7 +578,15 @@ query_services( repo, producer_type ); else if ( !strcmp( pname, "transitions" ) || !strcmp( pname, "transition" ) ) query_services( repo, transition_type ); - + else if ( !strcmp( pname, "profiles" ) || !strcmp( pname, "profile" ) ) + query_profiles(); + else if ( !strncmp( pname, "format", 6 ) ) + query_formats(); + else if ( !strncmp( pname, "acodec", 6 ) || !strcmp( pname, "audio_codecs" ) ) + query_acodecs(); + else if ( !strncmp( pname, "vcodec", 6 ) || !strcmp( pname, "video_codecs" ) ) + query_vcodecs(); + else if ( !strncmp( pname, "consumer=", 9 ) ) query_metadata( repo, consumer_type, "consumer", strchr( pname, '=' ) + 1 ); else if ( !strncmp( pname, "filter=", 7 ) ) @@ -502,6 +595,8 @@ query_metadata( repo, producer_type, "producer", strchr( pname, '=' ) + 1 ); else if ( !strncmp( pname, "transition=", 11 ) ) query_metadata( repo, transition_type, "transition", strchr( pname, '=' ) + 1 ); + else if ( !strncmp( pname, "profile=", 8 ) ) + query_profile( strchr( pname, '=' ) + 1 ); else goto query_all; } diff -Nru mlt-0.6.2/src/mlt++/config.h mlt-0.7.2/src/mlt++/config.h --- mlt-0.6.2/src/mlt++/config.h 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/mlt++/config.h 2011-05-02 05:59:12.000000000 +0000 @@ -21,14 +21,14 @@ #ifndef MLTPP_CONFIG_H_ #define MLTPP_CONFIG_H_ -#ifdef WIN32 +#if defined(WIN32) #ifdef MLTPP_EXPORTS #define MLTPP_DECLSPEC __declspec( dllexport ) #else #define MLTPP_DECLSPEC __declspec( dllimport ) #endif #else - #define MLTPP_DECLSPEC + #define MLTPP_DECLSPEC #endif #endif diff -Nru mlt-0.6.2/src/mlt++/configure mlt-0.7.2/src/mlt++/configure --- mlt-0.6.2/src/mlt++/configure 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/mlt++/configure 2011-05-02 05:59:12.000000000 +0000 @@ -4,7 +4,6 @@ WARNINGS="-W -Wwrite-strings -Wcast-qual -Wpointer-arith -Wcast-align -Wredundant-decls" -targetos=$(uname -s) case $targetos in Darwin) echo LIBSUF=.dylib @@ -16,4 +15,9 @@ echo "CXXFLAGS+=-Wall $WARNINGS -fPIC -DPIC" echo "LIBFLAGS=-shared" ;; + MinGW) + echo LIBSUF=.dll + echo "CXXFLAGS+=-Wall $WARNINGS -DPIC" + echo "LIBFLAGS=-enable-auto-import -shared" + ;; esac >> config.mak diff -Nru mlt-0.6.2/src/mlt++/Makefile mlt-0.7.2/src/mlt++/Makefile --- mlt-0.6.2/src/mlt++/Makefile 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/mlt++/Makefile 2011-05-02 05:59:12.000000000 +0000 @@ -2,16 +2,21 @@ include config.mak INSTALL = install -ifneq ($(targetos), Darwin) -NAME = libmlt++$(LIBSUF) -TARGET = $(NAME).$(version) -SONAME = $(NAME).$(soversion) -LIBFLAGS += -Wl,-soname,$(SONAME) -else +ifeq ($(targetos), Darwin) NAME = libmlt++$(LIBSUF) TARGET = libmlt++.$(version)$(LIBSUF) SONAME = libmlt++.$(soversion)$(LIBSUF) LIBFLAGS += -install_name $(libdir)/$(SONAME) -current_version $(version) -compatibility_version $(soversion) +else ifeq ($(targetos), MinGW) +NAME = libmlt++$(LIBSUF) +TARGET = libmlt++-$(soversion)$(LIBSUF) +CXXFLAGS += -DMLTPP_EXPORTS +LIBFLAGS += -Wl,--output-def,libmlt++.def +else +NAME = libmlt++$(LIBSUF) +TARGET = $(NAME).$(version) +SONAME = $(NAME).$(soversion) +LIBFLAGS += -Wl,-soname,$(SONAME) endif CXXFLAGS += -I.. $(RDYNAMIC) -DVERSION=\"$(version)\" @@ -49,7 +54,9 @@ $(TARGET): $(OBJS) $(CXX) $(LIBFLAGS) -o $@ $(OBJS) $(LDFLAGS) ln -sf $(TARGET) $(NAME) - ln -sf $(TARGET) $(SONAME) + if [ "$(targetos)" != "MinGW" ]; then \ + ln -sf $(TARGET) $(SONAME) ; \ + fi depend: $(SRCS) $(CXX) -MM $(CXXFLAGS) $^ 1>.depend @@ -61,16 +68,24 @@ install: $(INSTALL) -d "$(DESTDIR)$(libdir)" - $(INSTALL) -m 755 $(TARGET) $(DESTDIR)$(libdir) - ln -sf $(TARGET) $(DESTDIR)$(libdir)/$(NAME) - ln -sf $(TARGET) $(DESTDIR)$(libdir)/$(SONAME) + if [ "$(targetos)" = "MinGW" ]; then \ + $(INSTALL) -m 755 $(TARGET) $(DESTDIR)$(prefix) ; \ + $(INSTALL) -m 755 $(TARGET) $(DESTDIR)$(libdir)/libmlt++.dll ; \ + $(INSTALL) -m 644 libmlt++.def $(DESTDIR)$(libdir) ; \ + else \ + $(INSTALL) -m 755 $(TARGET) $(DESTDIR)$(libdir) ; \ + ln -sf $(TARGET) $(DESTDIR)$(libdir)/$(SONAME) ; \ + ln -sf $(TARGET) $(DESTDIR)$(libdir)/$(NAME) ; \ + fi $(INSTALL) -d "$(DESTDIR)$(prefix)/include/mlt++" $(INSTALL) -m 644 $(HEADERS) "$(DESTDIR)$(prefix)/include/mlt++" uninstall: rm -f "$(DESTDIR)$(libdir)/$(TARGET)" - rm -f "$(DESTDIR)$(libdir)/$(NAME)" - rm -f "$(DESTDIR)$(libdir)/$(SONAME)" + if [ "$(targetos)" != "MinGW" ]; then \ + rm -f "$(DESTDIR)$(libdir)/$(NAME)" ; \ + rm -f "$(DESTDIR)$(libdir)/$(SONAME)" ; \ + fi rm -rf "$(DESTDIR)$(prefix)/include/mlt++" ifneq ($(wildcard .depend),) diff -Nru mlt-0.6.2/src/mlt++/MltFactory.cpp mlt-0.7.2/src/mlt++/MltFactory.cpp --- mlt-0.6.2/src/mlt++/MltFactory.cpp 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/mlt++/MltFactory.cpp 2011-05-02 05:59:12.000000000 +0000 @@ -57,18 +57,6 @@ return new Consumer( profile, id, arg ); } -#ifdef WIN32 -char *Factory::getenv( const char *name ) -{ - return mlt_getenv( name ); -} - -int Factory::setenv( const char *name, const char *value ) -{ - return mlt_setenv( name, value ); -} -#endif - void Factory::close( ) { mlt_factory_close( ); diff -Nru mlt-0.6.2/src/mlt++/MltFactory.h mlt-0.7.2/src/mlt++/MltFactory.h --- mlt-0.6.2/src/mlt++/MltFactory.h 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/mlt++/MltFactory.h 2011-05-02 05:59:12.000000000 +0000 @@ -49,10 +49,6 @@ static Filter *filter( Profile& profile, char *id, char *arg = NULL ); static Transition *transition( Profile& profile, char *id, char *arg = NULL ); static Consumer *consumer( Profile& profile, char *id, char *arg = NULL ); -#ifdef WIN32 - static char *getenv( const char * ); - static int setenv( const char *, const char * ); -#endif static void close( ); }; } diff -Nru mlt-0.6.2/src/mlt++/MltFilter.cpp mlt-0.7.2/src/mlt++/MltFilter.cpp --- mlt-0.6.2/src/mlt++/MltFilter.cpp 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/mlt++/MltFilter.cpp 2011-05-02 05:59:12.000000000 +0000 @@ -106,8 +106,22 @@ return mlt_filter_get_out( get_filter( ) ); } +int Filter::get_length( ) +{ + return mlt_filter_get_length( get_filter( ) ); +} + int Filter::get_track( ) { return mlt_filter_get_track( get_filter( ) ); } +int Filter::get_position( Frame &frame ) +{ + return mlt_filter_get_position( get_filter( ), frame.get_frame( ) ); +} + +double Filter::get_progress( Frame &frame ) +{ + return mlt_filter_get_progress( get_filter( ), frame.get_frame( ) ); +} diff -Nru mlt-0.6.2/src/mlt++/MltFilter.h mlt-0.7.2/src/mlt++/MltFilter.h --- mlt-0.6.2/src/mlt++/MltFilter.h 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/mlt++/MltFilter.h 2011-05-02 05:59:12.000000000 +0000 @@ -31,6 +31,7 @@ { class Service; class Profile; + class Frame; class MLTPP_DECLSPEC Filter : public Service { @@ -48,7 +49,10 @@ void set_in_and_out( int in, int out ); int get_in( ); int get_out( ); + int get_length( ); int get_track( ); + int get_position( Frame &frame ); + double get_progress( Frame &frame ); }; } diff -Nru mlt-0.6.2/src/mlt++/MltFrame.cpp mlt-0.7.2/src/mlt++/MltFrame.cpp --- mlt-0.6.2/src/mlt++/MltFrame.cpp 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/mlt++/MltFrame.cpp 2011-05-02 05:59:12.000000000 +0000 @@ -89,3 +89,18 @@ { return new Producer( mlt_frame_get_original_producer( get_frame( ) ) ); } + +mlt_properties Frame::get_unique_properties( Service &service ) +{ + return mlt_frame_unique_properties( get_frame(), service.get_service() ); +} + +int Frame::set_image( uint8_t *image, int size, mlt_destructor destroy ) +{ + return mlt_frame_set_image( get_frame(), image, size, destroy ); +} + +int Frame::set_alpha( uint8_t *alpha, int size, mlt_destructor destroy ) +{ + return mlt_frame_set_alpha( get_frame(), alpha, size, destroy ); +} diff -Nru mlt-0.6.2/src/mlt++/MltFrame.h mlt-0.7.2/src/mlt++/MltFrame.h --- mlt-0.6.2/src/mlt++/MltFrame.h 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/mlt++/MltFrame.h 2011-05-02 05:59:12.000000000 +0000 @@ -30,6 +30,7 @@ { class Properties; class Producer; + class Service; class MLTPP_DECLSPEC Frame : public Properties { @@ -46,6 +47,9 @@ void *get_audio( mlt_audio_format &format, int &frequency, int &channels, int &samples ); unsigned char *get_waveform( int w, int h ); Producer *get_original_producer( ); + mlt_properties get_unique_properties( Service &service ); + int set_image( uint8_t *image, int size, mlt_destructor destroy ); + int set_alpha( uint8_t *alpha, int size, mlt_destructor destroy ); }; } diff -Nru mlt-0.6.2/src/mlt++/MltProfile.cpp mlt-0.7.2/src/mlt++/MltProfile.cpp --- mlt-0.6.2/src/mlt++/MltProfile.cpp 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/mlt++/MltProfile.cpp 2011-05-02 05:59:12.000000000 +0000 @@ -120,3 +120,8 @@ { return mlt_profile_dar( instance ); } + +Properties* Profile::list() +{ + return new Properties( mlt_profile_list() ); +} diff -Nru mlt-0.6.2/src/mlt++/MltProfile.h mlt-0.7.2/src/mlt++/MltProfile.h --- mlt-0.6.2/src/mlt++/MltProfile.h 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/mlt++/MltProfile.h 2011-05-02 05:59:12.000000000 +0000 @@ -57,6 +57,7 @@ int display_aspect_num() const; int display_aspect_den() const; double dar() const; + static Properties* list(); }; } diff -Nru mlt-0.6.2/src/mlt++/MltProperties.cpp mlt-0.7.2/src/mlt++/MltProperties.cpp --- mlt-0.6.2/src/mlt++/MltProperties.cpp 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/mlt++/MltProperties.cpp 2011-05-02 05:59:12.000000000 +0000 @@ -82,6 +82,16 @@ return mlt_properties_ref_count( get_properties( ) ); } +void Properties::lock( ) +{ + mlt_properties_lock( get_properties( ) ); +} + +void Properties::unlock( ) +{ + mlt_properties_unlock( get_properties( ) ); +} + void Properties::block( void *object ) { mlt_events_block( get_properties( ), object != NULL ? object : get_properties( ) ); diff -Nru mlt-0.6.2/src/mlt++/MltProperties.h mlt-0.7.2/src/mlt++/MltProperties.h --- mlt-0.6.2/src/mlt++/MltProperties.h 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/mlt++/MltProperties.h 2011-05-02 05:59:12.000000000 +0000 @@ -49,6 +49,8 @@ int inc_ref( ); int dec_ref( ); int ref_count( ); + void lock( ); + void unlock( ); void block( void *object = NULL ); void unblock( void *object = NULL ); void fire_event( const char *event ); diff -Nru mlt-0.6.2/src/mlt++/MltTransition.cpp mlt-0.7.2/src/mlt++/MltTransition.cpp --- mlt-0.6.2/src/mlt++/MltTransition.cpp 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/mlt++/MltTransition.cpp 2011-05-02 05:59:12.000000000 +0000 @@ -116,3 +116,23 @@ { return mlt_transition_get_out( get_transition() ); } + +int Transition::get_length( ) +{ + return mlt_transition_get_length( get_transition( ) ); +} + +int Transition::get_position( Frame &frame ) +{ + return mlt_transition_get_position( get_transition( ), frame.get_frame( ) ); +} + +double Transition::get_progress( Frame &frame ) +{ + return mlt_transition_get_progress( get_transition( ), frame.get_frame( ) ); +} + +double Transition::get_progress_delta( Frame &frame ) +{ + return mlt_transition_get_progress_delta( get_transition( ), frame.get_frame( ) ); +} diff -Nru mlt-0.6.2/src/mlt++/MltTransition.h mlt-0.7.2/src/mlt++/MltTransition.h --- mlt-0.6.2/src/mlt++/MltTransition.h 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/mlt++/MltTransition.h 2011-05-02 05:59:12.000000000 +0000 @@ -30,6 +30,7 @@ { class Service; class Profile; + class Frame; class MLTPP_DECLSPEC Transition : public Service { @@ -49,6 +50,10 @@ int get_b_track( ); int get_in( ); int get_out( ); + int get_length( ); + int get_position( Frame &frame ); + double get_progress( Frame &frame ); + double get_progress_delta( Frame &frame ); }; } diff -Nru mlt-0.6.2/src/modules/avformat/audioconvert.h mlt-0.7.2/src/modules/avformat/audioconvert.h --- mlt-0.6.2/src/modules/avformat/audioconvert.h 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/avformat/audioconvert.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,111 +0,0 @@ -/* - * audio conversion - * Copyright (c) 2006 Michael Niedermayer - * Copyright (c) 2008 Peter Ross - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef AVCODEC_AUDIOCONVERT_H -#define AVCODEC_AUDIOCONVERT_H - -/** - * @file audioconvert.h - * Audio format conversion routines - */ - - -#include - - -/** - * Generate string corresponding to the sample format with - * number sample_fmt, or a header if sample_fmt is negative. - * - * @param[in] buf the buffer where to write the string - * @param[in] buf_size the size of buf - * @param[in] sample_fmt the number of the sample format to print the corresponding info string, or - * a negative value to print the corresponding header. - * Meaningful values for obtaining a sample format info vary from 0 to SAMPLE_FMT_NB -1. - */ -void avcodec_sample_fmt_string(char *buf, int buf_size, int sample_fmt); - -/** - * @return NULL on error - */ -const char *avcodec_get_sample_fmt_name(int sample_fmt); - -/** - * @return SAMPLE_FMT_NONE on error - */ -enum SampleFormat avcodec_get_sample_fmt(const char* name); - -/** - * @return NULL on error - */ -const char *avcodec_get_channel_name(int channel_id); - -/** - * Return description of channel layout - */ -void avcodec_get_channel_layout_string(char *buf, int buf_size, int nb_channels, int64_t channel_layout); - -/** - * Guess the channel layout - * @param nb_channels - * @param codec_id Codec identifier, or CODEC_ID_NONE if unknown - * @param fmt_name Format name, or NULL if unknown - * @return Channel layout mask - */ -int64_t avcodec_guess_channel_layout(int nb_channels, enum CodecID codec_id, const char *fmt_name); - - -struct AVAudioConvert; -typedef struct AVAudioConvert AVAudioConvert; - -/** - * Create an audio sample format converter context - * @param out_fmt Output sample format - * @param out_channels Number of output channels - * @param in_fmt Input sample format - * @param in_channels Number of input channels - * @param[in] matrix Channel mixing matrix (of dimension in_channel*out_channels). Set to NULL to ignore. - * @param flags See FF_MM_xx - * @return NULL on error - */ -AVAudioConvert *av_audio_convert_alloc(enum SampleFormat out_fmt, int out_channels, - enum SampleFormat in_fmt, int in_channels, - const float *matrix, int flags); - -/** - * Free audio sample format converter context - */ -void av_audio_convert_free(AVAudioConvert *ctx); - -/** - * Convert between audio sample formats - * @param[in] out array of output buffers for each channel. set to NULL to ignore processing of the given channel. - * @param[in] out_stride distance between consecutive input samples (measured in bytes) - * @param[in] in array of input buffers for each channel - * @param[in] in_stride distance between consecutive output samples (measured in bytes) - * @param len length of audio frame size (measured in samples) - */ -int av_audio_convert(AVAudioConvert *ctx, - void * const out[6], const int out_stride[6], - const void * const in[6], const int in_stride[6], int len); - -#endif /* AVCODEC_AUDIOCONVERT_H */ diff -Nru mlt-0.6.2/src/modules/avformat/configure mlt-0.7.2/src/modules/avformat/configure --- mlt-0.6.2/src/modules/avformat/configure 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/avformat/configure 2011-05-02 05:59:12.000000000 +0000 @@ -24,7 +24,7 @@ --avformat-no-codecs - Disable the producer and consumer to avoid the FFmpeg codecs --avformat-no-filters - Disable the filters to make a codecs+muxers-only plugin --avformat-no-devices - Disable support for libavdevice - --avformat-no-vdpau - Disable support for NVIDIA VDPAU + --avformat-vdpau - Enable support for NVIDIA VDPAU NOTE: The recommended version of FFmpeg is $([ "$svn_rev" = "0.6.1" ] && echo $svn_rev || echo SVN-r$svn_rev). @@ -65,7 +65,7 @@ export codecs=true export filters=true export devices=true - export vdpau=true + export vdpau=false pkg-config x11 > /dev/null 2>&1 export x11=$? @@ -86,6 +86,7 @@ --avformat-no-filters ) filters=false ;; --avformat-no-devices ) devices=false ;; --avformat-no-vdpau ) vdpau=false ;; + --avformat-vdpau ) vdpau=true ;; esac done @@ -169,7 +170,14 @@ elif [ "$shared_ffmpeg" != "" ] then echo "PREFIX=$shared_ffmpeg" >> config.mak - echo "CFLAGS+=-DAVDATADIR=\\\"${shared_ffmpeg}/share/ffmpeg/\\\"" >> config.mak + case $targetos in + MINGW32_NT-*) + echo "CFLAGS+=-DAVDATADIR=\\\"share/ffmpeg/\\\"" >> config.mak + ;; + *) + echo "CFLAGS+=-DAVDATADIR=\\\"${shared_ffmpeg}/share/ffmpeg/\\\"" >> config.mak + ;; + esac echo "CFLAGS+=$(pkg-config --cflags libavformat)" >> config.mak echo "LDFLAGS+=$(pkg-config --libs-only-L libavformat)" >> config.mak if [ "$devices" = "true" ] @@ -178,7 +186,7 @@ echo "LDFLAGS+=$(pkg-config --libs-only-L libavdevice)" >> config.mak fi avcodec_version=$(pkg-config --modversion libavcodec) - if [ "$swscale" != "" ] || ( [ $(echo $avcodec_version | cut -d. -f1) -ge 52 ] && [ $(echo $avcodec_version | cut -d. -f2) -ge 21 ] ) + if [ "$swscale" != "" ] || [ $(echo $avcodec_version | cut -d. -f1) -gt 52 ] || ( [ $(echo $avcodec_version | cut -d. -f1) -ge 52 ] && [ $(echo $avcodec_version | cut -d. -f2) -ge 21 ] ) then echo "CFLAGS+=$(pkg-config --cflags libswscale)" >> config.mak echo "LDFLAGS+=$(pkg-config --libs-only-L libswscale)" >> config.mak diff -Nru mlt-0.6.2/src/modules/avformat/consumer_avformat.c mlt-0.7.2/src/modules/avformat/consumer_avformat.c --- mlt-0.6.2/src/modules/avformat/consumer_avformat.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/avformat/consumer_avformat.c 2011-05-02 05:59:12.000000000 +0000 @@ -40,7 +40,6 @@ #ifdef SWSCALE #include #endif -#include #if LIBAVUTIL_VERSION_INT >= ((50<<16)+(8<<8)+0) #include #endif @@ -50,6 +49,15 @@ #define PIX_FMT_YUYV422 PIX_FMT_YUV422 #endif +#if LIBAVCODEC_VERSION_MAJOR > 52 +#include +#define CODEC_TYPE_VIDEO AVMEDIA_TYPE_VIDEO +#define CODEC_TYPE_AUDIO AVMEDIA_TYPE_AUDIO +#define PKT_FLAG_KEY AV_PKT_FLAG_KEY +#else +#include +#endif + #define MAX_AUDIO_STREAMS (8) #define AUDIO_ENCODE_BUFFER_SIZE (48000 * 2 * MAX_AUDIO_STREAMS) #define AUDIO_BUFFER_SIZE (1024 * 42) @@ -75,82 +83,82 @@ sample_fifo sample_fifo_init( int frequency, int channels ) { - sample_fifo this = calloc( 1, sizeof( sample_fifo_s ) ); - this->frequency = frequency; - this->channels = channels; - return this; + sample_fifo fifo = calloc( 1, sizeof( sample_fifo_s ) ); + fifo->frequency = frequency; + fifo->channels = channels; + return fifo; } // sample_fifo_clear and check are temporarily aborted (not working as intended) -void sample_fifo_clear( sample_fifo this, double time ) +void sample_fifo_clear( sample_fifo fifo, double time ) { - int words = ( float )( time - this->time ) * this->frequency * this->channels; - if ( ( int )( ( float )time * 100 ) < ( int )( ( float )this->time * 100 ) && this->used > words && words > 0 ) + int words = ( float )( time - fifo->time ) * fifo->frequency * fifo->channels; + if ( ( int )( ( float )time * 100 ) < ( int )( ( float )fifo->time * 100 ) && fifo->used > words && words > 0 ) { - memmove( this->buffer, &this->buffer[ words ], ( this->used - words ) * sizeof( int16_t ) ); - this->used -= words; - this->time = time; + memmove( fifo->buffer, &fifo->buffer[ words ], ( fifo->used - words ) * sizeof( int16_t ) ); + fifo->used -= words; + fifo->time = time; } - else if ( ( int )( ( float )time * 100 ) != ( int )( ( float )this->time * 100 ) ) + else if ( ( int )( ( float )time * 100 ) != ( int )( ( float )fifo->time * 100 ) ) { - this->used = 0; - this->time = time; + fifo->used = 0; + fifo->time = time; } } -void sample_fifo_check( sample_fifo this, double time ) +void sample_fifo_check( sample_fifo fifo, double time ) { - if ( this->used == 0 ) + if ( fifo->used == 0 ) { - if ( ( int )( ( float )time * 100 ) < ( int )( ( float )this->time * 100 ) ) - this->time = time; + if ( ( int )( ( float )time * 100 ) < ( int )( ( float )fifo->time * 100 ) ) + fifo->time = time; } } -void sample_fifo_append( sample_fifo this, int16_t *samples, int count ) +void sample_fifo_append( sample_fifo fifo, int16_t *samples, int count ) { - if ( ( this->size - this->used ) < count ) + if ( ( fifo->size - fifo->used ) < count ) { - this->size += count * 5; - this->buffer = realloc( this->buffer, this->size * sizeof( int16_t ) ); + fifo->size += count * 5; + fifo->buffer = realloc( fifo->buffer, fifo->size * sizeof( int16_t ) ); } - memcpy( &this->buffer[ this->used ], samples, count * sizeof( int16_t ) ); - this->used += count; + memcpy( &fifo->buffer[ fifo->used ], samples, count * sizeof( int16_t ) ); + fifo->used += count; } -int sample_fifo_used( sample_fifo this ) +int sample_fifo_used( sample_fifo fifo ) { - return this->used; + return fifo->used; } -int sample_fifo_fetch( sample_fifo this, int16_t *samples, int count ) +int sample_fifo_fetch( sample_fifo fifo, int16_t *samples, int count ) { - if ( count > this->used ) - count = this->used; + if ( count > fifo->used ) + count = fifo->used; - memcpy( samples, this->buffer, count * sizeof( int16_t ) ); - this->used -= count; - memmove( this->buffer, &this->buffer[ count ], this->used * sizeof( int16_t ) ); + memcpy( samples, fifo->buffer, count * sizeof( int16_t ) ); + fifo->used -= count; + memmove( fifo->buffer, &fifo->buffer[ count ], fifo->used * sizeof( int16_t ) ); - this->time += ( double )count / this->channels / this->frequency; + fifo->time += ( double )count / fifo->channels / fifo->frequency; return count; } -void sample_fifo_close( sample_fifo this ) +void sample_fifo_close( sample_fifo fifo ) { - free( this->buffer ); - free( this ); + free( fifo->buffer ); + free( fifo ); } // Forward references. -static int consumer_start( mlt_consumer this ); -static int consumer_stop( mlt_consumer this ); -static int consumer_is_stopped( mlt_consumer this ); +static int consumer_start( mlt_consumer consumer ); +static int consumer_stop( mlt_consumer consumer ); +static int consumer_is_stopped( mlt_consumer consumer ); static void *consumer_thread( void *arg ); -static void consumer_close( mlt_consumer this ); +static void consumer_close( mlt_consumer consumer ); /** Initialise the consumer. */ @@ -158,16 +166,16 @@ mlt_consumer consumer_avformat_init( mlt_profile profile, char *arg ) { // Allocate the consumer - mlt_consumer this = mlt_consumer_new( profile ); + mlt_consumer consumer = mlt_consumer_new( profile ); // If memory allocated and initialises without error - if ( this != NULL ) + if ( consumer != NULL ) { // Get properties from the consumer - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); + mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); // Assign close callback - this->close = consumer_close; + consumer->close = consumer_close; // Interpret the argument if ( arg != NULL ) @@ -195,24 +203,24 @@ mlt_properties_set_int( properties, "prefill", 1 ); // Set up start/stop/terminated callbacks - this->start = consumer_start; - this->stop = consumer_stop; - this->is_stopped = consumer_is_stopped; + consumer->start = consumer_start; + consumer->stop = consumer_stop; + consumer->is_stopped = consumer_is_stopped; mlt_events_register( properties, "consumer-fatal-error", NULL ); } - // Return this - return this; + // Return consumer + return consumer; } /** Start the consumer. */ -static int consumer_start( mlt_consumer this ) +static int consumer_start( mlt_consumer consumer ) { // Get the properties - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); + mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); int error = 0; // Report information about available muxers and codecs as YAML Tiny @@ -300,7 +308,7 @@ } else { - mlt_log_warning( MLT_CONSUMER_SERVICE( this ), "Invalid size property %s - ignoring.\n", size ); + mlt_log_warning( MLT_CONSUMER_SERVICE( consumer ), "Invalid size property %s - ignoring.\n", size ); } } @@ -312,7 +320,7 @@ // We need to set these on the profile as well because the s property is // an alias to mlt properties that correspond to profile settings. - mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( this ) ); + mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( consumer ) ); if ( profile ) { profile->width = width; @@ -347,7 +355,7 @@ mlt_properties_set_int( properties, "running", 1 ); // Create the thread - pthread_create( thread, NULL, consumer_thread, this ); + pthread_create( thread, NULL, consumer_thread, consumer ); } return error; } @@ -355,10 +363,10 @@ /** Stop the consumer. */ -static int consumer_stop( mlt_consumer this ) +static int consumer_stop( mlt_consumer consumer ) { // Get the properties - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); + mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); // Check that we're running if ( mlt_properties_get_int( properties, "running" ) ) @@ -379,10 +387,10 @@ /** Determine if the consumer is stopped. */ -static int consumer_is_stopped( mlt_consumer this ) +static int consumer_is_stopped( mlt_consumer consumer ) { // Get the properties - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); + mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); return !mlt_properties_get_int( properties, "running" ); } @@ -392,18 +400,19 @@ static void apply_properties( void *obj, mlt_properties properties, int flags, int alloc ) { int i; - int count = mlt_properties_count( properties ); + int count = mlt_properties_count( properties ); for ( i = 0; i < count; i++ ) { const char *opt_name = mlt_properties_get_name( properties, i ); const AVOption *opt = av_find_opt( obj, opt_name, NULL, flags, flags ); + if ( opt != NULL ) #if LIBAVCODEC_VERSION_INT >= ((52<<16)+(7<<8)+0) - av_set_string3( obj, opt_name, mlt_properties_get( properties, opt_name), alloc, NULL ); + av_set_string3( obj, opt_name, mlt_properties_get_value( properties, i), alloc, NULL ); #elif LIBAVCODEC_VERSION_INT >= ((51<<16)+(59<<8)+0) - av_set_string2( obj, opt_name, mlt_properties_get( properties, opt_name), alloc ); + av_set_string2( obj, opt_name, mlt_properties_get_value( properties, i), alloc ); #else - av_set_string( obj, opt_name, mlt_properties_get( properties, opt_name) ); + av_set_string( obj, opt_name, mlt_properties_get_value( properties, i) ); #endif } } @@ -411,10 +420,10 @@ /** Add an audio output stream */ -static AVStream *add_audio_stream( mlt_consumer this, AVFormatContext *oc, int codec_id, int channels ) +static AVStream *add_audio_stream( mlt_consumer consumer, AVFormatContext *oc, int codec_id, int channels ) { // Get the properties - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); + mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); // Create a new stream AVStream *st = av_new_stream( oc, oc->nb_streams ); @@ -437,7 +446,7 @@ if ( thread_count == 0 && getenv( "MLT_AVFORMAT_THREADS" ) ) thread_count = atoi( getenv( "MLT_AVFORMAT_THREADS" ) ); if ( thread_count > 1 ) - avcodec_thread_init( c, thread_count ); + c->thread_count = thread_count; #endif if (oc->oformat->flags & AVFMT_GLOBALHEADER) @@ -477,17 +486,22 @@ c->channels = channels; if ( mlt_properties_get( properties, "alang" ) != NULL ) +#if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(43<<8)+0) + av_metadata_set2( &oc->metadata, "language", mlt_properties_get( properties, "alang" ), 0 ); +#else + strncpy( st->language, mlt_properties_get( properties, "alang" ), sizeof( st->language ) ); +#endif } else { - mlt_log_error( MLT_CONSUMER_SERVICE( this ), "Could not allocate a stream for audio\n" ); + mlt_log_error( MLT_CONSUMER_SERVICE( consumer ), "Could not allocate a stream for audio\n" ); } return st; } -static int open_audio( AVFormatContext *oc, AVStream *st, int audio_outbuf_size ) +static int open_audio( mlt_properties properties, AVFormatContext *oc, AVStream *st, int audio_outbuf_size, const char *codec_name ) { // We will return the audio input size from here int audio_input_frame_size = 0; @@ -496,7 +510,26 @@ AVCodecContext *c = st->codec; // Find the encoder - AVCodec *codec = avcodec_find_encoder( c->codec_id ); + AVCodec *codec; + if ( codec_name ) + codec = avcodec_find_encoder_by_name( codec_name ); + else + codec = avcodec_find_encoder( c->codec_id ); + +#if LIBAVCODEC_VERSION_MAJOR > 52 + // Process properties as AVOptions on the AVCodec + if ( codec && codec->priv_class && c->priv_data ) + { + char *apre = mlt_properties_get( properties, "apre" ); + if ( apre ) + { + mlt_properties p = mlt_properties_load( apre ); + apply_properties( c->priv_data, p, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM, 1 ); + mlt_properties_close( p ); + } + apply_properties( c->priv_data, properties, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM, 0 ); + } +#endif avformat_lock(); @@ -554,10 +587,10 @@ /** Add a video output stream */ -static AVStream *add_video_stream( mlt_consumer this, AVFormatContext *oc, int codec_id ) +static AVStream *add_video_stream( mlt_consumer consumer, AVFormatContext *oc, int codec_id ) { // Get the properties - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); + mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); // Create a new stream AVStream *st = av_new_stream( oc, oc->nb_streams ); @@ -578,7 +611,7 @@ if ( thread_count == 0 && getenv( "MLT_AVFORMAT_THREADS" ) ) thread_count = atoi( getenv( "MLT_AVFORMAT_THREADS" ) ); if ( thread_count > 1 ) - avcodec_thread_init( c, thread_count ); + c->thread_count = thread_count; // Process properties as AVOptions char *vpre = mlt_properties_get( properties, "vpre" ); @@ -661,7 +694,7 @@ // for mlt properties that correspond to profile settings mlt_properties_set_int( properties, "display_aspect_num", rational.num ); mlt_properties_set_int( properties, "display_aspect_den", rational.den ); - mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( this ) ); + mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( consumer ) ); if ( profile ) { profile->display_aspect_num = rational.num; @@ -731,7 +764,7 @@ int start, end, q; int e = sscanf( rc_override, "%d,%d,%d", &start, &end, &q ); if ( e != 3 ) - mlt_log_warning( MLT_CONSUMER_SERVICE( this ), "Error parsing rc_override\n" ); + mlt_log_warning( MLT_CONSUMER_SERVICE( consumer ), "Error parsing rc_override\n" ); c->rc_override = av_realloc( c->rc_override, sizeof( RcOverride ) * ( i + 1 ) ); c->rc_override[i].start_frame = start; c->rc_override[i].end_frame = end; @@ -793,7 +826,7 @@ fseek( f, 0, SEEK_SET ); logbuffer = av_malloc( size + 1 ); if ( !logbuffer ) - mlt_log_fatal( MLT_CONSUMER_SERVICE( this ), "Could not allocate log buffer\n" ); + mlt_log_fatal( MLT_CONSUMER_SERVICE( consumer ), "Could not allocate log buffer\n" ); else { size = fread( logbuffer, 1, size, f ); @@ -808,7 +841,7 @@ } else { - mlt_log_error( MLT_CONSUMER_SERVICE( this ), "Could not allocate a stream for video\n" ); + mlt_log_error( MLT_CONSUMER_SERVICE( consumer ), "Could not allocate a stream for video\n" ); } return st; @@ -842,13 +875,32 @@ return picture; } -static int open_video(AVFormatContext *oc, AVStream *st) +static int open_video( mlt_properties properties, AVFormatContext *oc, AVStream *st, const char *codec_name ) { // Get the codec AVCodecContext *video_enc = st->codec; // find the video encoder - AVCodec *codec = avcodec_find_encoder( video_enc->codec_id ); + AVCodec *codec; + if ( codec_name ) + codec = avcodec_find_encoder_by_name( codec_name ); + else + codec = avcodec_find_encoder( video_enc->codec_id ); + +#if LIBAVCODEC_VERSION_MAJOR > 52 + // Process properties as AVOptions on the AVCodec + if ( codec && codec->priv_class && video_enc->priv_data ) + { + char *vpre = mlt_properties_get( properties, "vpre" ); + if ( vpre ) + { + mlt_properties p = mlt_properties_load( vpre ); + apply_properties( video_enc->priv_data, p, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM, 1 ); + mlt_properties_close( p ); + } + apply_properties( video_enc->priv_data, properties, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM, 0 ); + } +#endif if( codec && codec->pix_fmts ) { @@ -893,10 +945,10 @@ static void *consumer_thread( void *arg ) { // Map the argument to the object - mlt_consumer this = arg; + mlt_consumer consumer = arg; // Get the properties - mlt_properties properties = MLT_CONSUMER_PROPERTIES( this ); + mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer ); // Get the terminate on pause property int terminate_on_pause = mlt_properties_get_int( properties, "terminate_on_pause" ); @@ -1034,9 +1086,19 @@ { AVCodec *p = avcodec_find_encoder_by_name( acodec ); if ( p != NULL ) + { audio_codec_id = p->id; + if ( audio_codec_id == CODEC_ID_AC3 && avcodec_find_encoder_by_name( "ac3_fixed" ) ) + { + mlt_properties_set( properties, "_acodec", "ac3_fixed" ); + acodec = mlt_properties_get( properties, "_acodec" ); + } + } else - mlt_log_warning( MLT_CONSUMER_SERVICE( this ), "audio codec %s unrecognised - ignoring\n", acodec ); + { + audio_codec_id = CODEC_ID_NONE; + mlt_log_warning( MLT_CONSUMER_SERVICE( consumer ), "audio codec %s unrecognised - ignoring\n", acodec ); + } } // Check for video codec overides @@ -1046,12 +1108,39 @@ { AVCodec *p = avcodec_find_encoder_by_name( vcodec ); if ( p != NULL ) + { video_codec_id = p->id; + } else - mlt_log_warning( MLT_CONSUMER_SERVICE( this ), "video codec %s unrecognised - ignoring\n", vcodec ); + { + video_codec_id = CODEC_ID_NONE; + mlt_log_warning( MLT_CONSUMER_SERVICE( consumer ), "video codec %s unrecognised - ignoring\n", vcodec ); + } } // Write metadata +#if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(31<<8)+0) + for ( i = 0; i < mlt_properties_count( properties ); i++ ) + { + char *name = mlt_properties_get_name( properties, i ); + if ( name && !strncmp( name, "meta.attr.", 10 ) ) + { + char *key = strdup( name + 10 ); + char *markup = strrchr( key, '.' ); + if ( markup && !strcmp( markup, ".markup") ) + { + markup[0] = '\0'; + if ( !strstr( key, ".stream." ) ) +#if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(43<<8)+0) + av_metadata_set2( &oc->metadata, key, mlt_properties_get_value( properties, i ), 0 ); +#else + av_metadata_set( &oc->metadata, key, mlt_properties_get_value( properties, i ) ); +#endif + } + free( key ); + } + } +#else char *tmp = NULL; int metavalue; @@ -1075,13 +1164,14 @@ metavalue = mlt_properties_get_int( properties, "meta.attr.track.markup"); if (metavalue != 0) oc->track = metavalue; +#endif oc->oformat = fmt; snprintf( oc->filename, sizeof(oc->filename), "%s", filename ); // Add audio and video streams if ( video_codec_id != CODEC_ID_NONE ) - video_st = add_video_stream( this, oc, video_codec_id ); + video_st = add_video_stream( consumer, oc, video_codec_id ); if ( audio_codec_id != CODEC_ID_NONE ) { int is_multi = 0; @@ -1096,13 +1186,13 @@ { is_multi = 1; total_channels += j; - audio_st[i] = add_audio_stream( this, oc, audio_codec_id, j ); + audio_st[i] = add_audio_stream( consumer, oc, audio_codec_id, j ); } } // single track if ( !is_multi ) { - audio_st[0] = add_audio_stream( this, oc, audio_codec_id, channels ); + audio_st[0] = add_audio_stream( consumer, oc, audio_codec_id, channels ); total_channels = channels; } } @@ -1119,15 +1209,24 @@ { mlt_properties p = mlt_properties_load( fpre ); apply_properties( oc, p, AV_OPT_FLAG_ENCODING_PARAM, 1 ); +#if LIBAVFORMAT_VERSION_MAJOR > 52 + if ( oc->oformat && oc->oformat->priv_class && oc->priv_data ) + apply_properties( oc->priv_data, p, AV_OPT_FLAG_ENCODING_PARAM, 1 ); +#endif mlt_properties_close( p ); } apply_properties( oc, properties, AV_OPT_FLAG_ENCODING_PARAM, 0 ); +#if LIBAVFORMAT_VERSION_MAJOR > 52 + if ( oc->oformat && oc->oformat->priv_class && oc->priv_data ) + apply_properties( oc->priv_data, properties, AV_OPT_FLAG_ENCODING_PARAM, 1 ); +#endif - if ( video_st && !open_video( oc, video_st ) ) + if ( video_st && !open_video( properties, oc, video_st, vcodec? vcodec : NULL ) ) video_st = NULL; for ( i = 0; i < MAX_AUDIO_STREAMS && audio_st[i]; i++ ) { - audio_input_frame_size = open_audio( oc, audio_st[i], audio_outbuf_size ); + audio_input_frame_size = open_audio( properties, oc, audio_st[i], audio_outbuf_size, + acodec? acodec : NULL ); if ( !audio_input_frame_size ) audio_st[i] = NULL; } @@ -1135,9 +1234,13 @@ // Open the output file, if needed if ( !( fmt->flags & AVFMT_NOFILE ) ) { - if ( url_fopen( &oc->pb, filename, URL_WRONLY ) < 0 ) +#if LIBAVFORMAT_VERSION_MAJOR > 52 + if ( avio_open( &oc->pb, filename, AVIO_FLAG_WRITE ) < 0 ) +#else + if ( url_fopen( &oc->pb, filename, URL_WRONLY ) < 0 ) +#endif { - mlt_log_error( MLT_CONSUMER_SERVICE( this ), "Could not open '%s'\n", filename ); + mlt_log_error( MLT_CONSUMER_SERVICE( consumer ), "Could not open '%s'\n", filename ); mlt_properties_set_int( properties, "running", 0 ); } } @@ -1148,7 +1251,7 @@ } else { - mlt_log_error( MLT_CONSUMER_SERVICE( this ), "Invalid output format parameters\n" ); + mlt_log_error( MLT_CONSUMER_SERVICE( consumer ), "Invalid output format parameters\n" ); mlt_properties_set_int( properties, "running", 0 ); } @@ -1167,7 +1270,7 @@ while( mlt_properties_get_int( properties, "running" ) && ( !terminated || ( video_st && mlt_deque_count( queue ) ) ) ) { - frame = mlt_consumer_rt_frame( this ); + frame = mlt_consumer_rt_frame( consumer ); // Check that we have a frame to work with if ( frame != NULL ) @@ -1204,6 +1307,9 @@ // Append the samples sample_fifo_append( fifo, pcm, samples * channels ); total_time += ( samples * 1000000 ) / frequency; + + if ( !video_st ) + mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); } // Encode the image @@ -1329,7 +1435,7 @@ if ( codec->coded_frame && codec->coded_frame->pts != AV_NOPTS_VALUE ) { pkt.pts = av_rescale_q( codec->coded_frame->pts, codec->time_base, stream->time_base ); - mlt_log_debug( MLT_CONSUMER_SERVICE( this ), "audio stream %d pkt pts %lld frame pts %lld", + mlt_log_debug( MLT_CONSUMER_SERVICE( consumer ), "audio stream %d pkt pts %"PRId64" frame pts %"PRId64, stream->index, pkt.pts, codec->coded_frame->pts ); } pkt.flags |= PKT_FLAG_KEY; @@ -1340,13 +1446,13 @@ { if ( av_interleaved_write_frame( oc, &pkt ) ) { - mlt_log_fatal( MLT_CONSUMER_SERVICE( this ), "error writing audio frame\n" ); + mlt_log_fatal( MLT_CONSUMER_SERVICE( consumer ), "error writing audio frame\n" ); mlt_events_fire( properties, "consumer-fatal-error", NULL ); goto on_fatal_error; } } - mlt_log_debug( MLT_CONSUMER_SERVICE( this ), " frame_size %d\n", codec->frame_size ); + mlt_log_debug( MLT_CONSUMER_SERVICE( consumer ), " frame_size %d\n", codec->frame_size ); if ( i == 0 ) { audio_pts = (double)stream->pts.val * av_q2d( stream->time_base ); @@ -1374,7 +1480,6 @@ if ( mlt_properties_get_int( frame_properties, "rendered" ) ) { int i = 0; - int j = 0; uint8_t *p; uint8_t *q; @@ -1386,12 +1491,8 @@ for ( i = 0; i < height; i ++ ) { p = input->data[ 0 ] + i * input->linesize[ 0 ]; - j = width; - while( j -- ) - { - *p ++ = *q ++; - *p ++ = *q ++; - } + memcpy( p, q, width * 2 ); + q += width * 2; } // Do the colour space conversion @@ -1405,7 +1506,7 @@ #endif struct SwsContext *context = sws_getContext( width, height, PIX_FMT_YUYV422, width, height, video_st->codec->pix_fmt, flags, NULL, NULL, NULL); - sws_scale( context, input->data, input->linesize, 0, height, + sws_scale( context, (const uint8_t* const*) input->data, input->linesize, 0, height, output->data, output->linesize); sws_freeContext( context ); #else @@ -1477,7 +1578,7 @@ if ( c->coded_frame && c->coded_frame->pts != AV_NOPTS_VALUE ) pkt.pts= av_rescale_q( c->coded_frame->pts, c->time_base, video_st->time_base ); - mlt_log_debug( MLT_CONSUMER_SERVICE( this ), "video pkt pts %lld frame pts %lld", pkt.pts, c->coded_frame->pts ); + mlt_log_debug( MLT_CONSUMER_SERVICE( consumer ), "video pkt pts %"PRId64" frame pts %"PRId64, pkt.pts, c->coded_frame->pts ); if( c->coded_frame && c->coded_frame->key_frame ) pkt.flags |= PKT_FLAG_KEY; pkt.stream_index= video_st->index; @@ -1486,7 +1587,7 @@ // write the compressed frame in the media file ret = av_interleaved_write_frame(oc, &pkt); - mlt_log_debug( MLT_CONSUMER_SERVICE( this ), " frame_size %d\n", c->frame_size ); + mlt_log_debug( MLT_CONSUMER_SERVICE( consumer ), " frame_size %d\n", c->frame_size ); video_pts = (double)video_st->pts.val * av_q2d( video_st->time_base ); // Dual pass logging @@ -1495,13 +1596,13 @@ } else if ( out_size < 0 ) { - mlt_log_warning( MLT_CONSUMER_SERVICE( this ), "error with video encode %d\n", frame_count ); + mlt_log_warning( MLT_CONSUMER_SERVICE( consumer ), "error with video encode %d\n", frame_count ); } } frame_count++; if ( ret ) { - mlt_log_fatal( MLT_CONSUMER_SERVICE( this ), "error writing video frame\n" ); + mlt_log_fatal( MLT_CONSUMER_SERVICE( consumer ), "error writing video frame\n" ); mlt_events_fire( properties, "consumer-fatal-error", NULL ); goto on_fatal_error; } @@ -1513,10 +1614,10 @@ } } if ( audio_st[0] ) - mlt_log_debug( MLT_CONSUMER_SERVICE( this ), "audio pts %lld (%f) ", audio_st[0]->pts.val, audio_pts ); + mlt_log_debug( MLT_CONSUMER_SERVICE( consumer ), "audio pts %"PRId64" (%f) ", audio_st[0]->pts.val, audio_pts ); if ( video_st ) - mlt_log_debug( MLT_CONSUMER_SERVICE( this ), "video pts %lld (%f) ", video_st->pts.val, video_pts ); - mlt_log_debug( MLT_CONSUMER_SERVICE( this ), "\n" ); + mlt_log_debug( MLT_CONSUMER_SERVICE( consumer ), "video pts %"PRId64" (%f) ", video_st->pts.val, video_pts ); + mlt_log_debug( MLT_CONSUMER_SERVICE( consumer ), "\n" ); } if ( real_time_output == 1 && frames % 2 == 0 ) @@ -1556,7 +1657,7 @@ } if ( pkt.size <= 0 ) pkt.size = avcodec_encode_audio( c, audio_outbuf, audio_outbuf_size, NULL ); - mlt_log_debug( MLT_CONSUMER_SERVICE( this ), "flushing audio size %d\n", pkt.size ); + mlt_log_debug( MLT_CONSUMER_SERVICE( consumer ), "flushing audio size %d\n", pkt.size ); if ( pkt.size <= 0 ) break; @@ -1568,7 +1669,7 @@ pkt.data = audio_outbuf; if ( av_interleaved_write_frame( oc, &pkt ) != 0 ) { - mlt_log_fatal( MLT_CONSUMER_SERVICE( this ), "error writing flushed audio frame\n" ); + mlt_log_fatal( MLT_CONSUMER_SERVICE( consumer ), "error writing flushed audio frame\n" ); mlt_events_fire( properties, "consumer-fatal-error", NULL ); goto on_fatal_error; } @@ -1583,7 +1684,7 @@ // Encode the image pkt.size = avcodec_encode_video( c, video_outbuf, video_outbuf_size, NULL ); - mlt_log_debug( MLT_CONSUMER_SERVICE( this ), "flushing video size %d\n", pkt.size ); + mlt_log_debug( MLT_CONSUMER_SERVICE( consumer ), "flushing video size %d\n", pkt.size ); if ( pkt.size <= 0 ) break; @@ -1597,7 +1698,7 @@ // write the compressed frame in the media file if ( av_interleaved_write_frame( oc, &pkt ) != 0 ) { - mlt_log_fatal( MLT_CONSUMER_SERVICE(this), "error writing flushed video frame\n" ); + mlt_log_fatal( MLT_CONSUMER_SERVICE(consumer), "error writing flushed video frame\n" ); mlt_events_fire( properties, "consumer-fatal-error", NULL ); goto on_fatal_error; } @@ -1624,7 +1725,9 @@ // Close the output file if ( !( fmt->flags & AVFMT_NOFILE ) ) -#if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(0<<8)+0) +#if LIBAVFORMAT_VERSION_MAJOR > 52 + avio_close( oc->pb ); +#elif LIBAVFORMAT_VERSION_INT >= ((52<<16)+(0<<8)+0) url_fclose( oc->pb ); #else url_fclose( &oc->pb ); @@ -1646,7 +1749,7 @@ // Just in case we terminated on pause mlt_properties_set_int( properties, "running", 0 ); - mlt_consumer_stopped( this ); + mlt_consumer_stopped( consumer ); mlt_properties_close( frame_meta_properties ); if ( mlt_properties_get_int( properties, "pass" ) > 1 ) @@ -1682,14 +1785,14 @@ /** Close the consumer. */ -static void consumer_close( mlt_consumer this ) +static void consumer_close( mlt_consumer consumer ) { // Stop the consumer - mlt_consumer_stop( this ); + mlt_consumer_stop( consumer ); // Close the parent - mlt_consumer_close( this ); + mlt_consumer_close( consumer ); // Free the memory - free( this ); + free( consumer ); } diff -Nru mlt-0.6.2/src/modules/avformat/consumer_avformat.yml mlt-0.7.2/src/modules/avformat/consumer_avformat.yml --- mlt-0.6.2/src/modules/avformat/consumer_avformat.yml 1970-01-01 00:00:00.000000000 +0000 +++ mlt-0.7.2/src/modules/avformat/consumer_avformat.yml 2011-05-02 05:59:12.000000000 +0000 @@ -0,0 +1,383 @@ +schema_version: 0.1 +type: consumer +identifier: avformat +title: FFmpeg Output +version: 1 +copyright: Copyright (C) 2003-2011 Ushodaya Enterprises Limited +license: LGPL +language: en +url: http://www.ffmpeg.org/ +creator: Charles Yates +contributor: + - Dan Dennedy +tags: + - Audio + - Video +description: Write or stream audio and/or video using FFmpeg +parameters: + - identifier: argument + title: File/URI + type: string + required: yes + widget: filesave + + - identifier: target + title: File/URI + type: string + description: This is not the same thing as the ffmpeg -target option! + readonly: yes + + - identifier: profile + title: Profile + type: string + description: > + Choose a MLT basic video settings preset. + This overrides a profile that may have been set elsewhere. + +# These override the profile + - identifier: width + title: Width + type: integer + minimum: 0 + unit: pixels + - identifier: height + title: Height + type: integer + minimum: 0 + unit: pixels + - identifier: display_aspect_num + title: Display aspect ratio numerator + type: integer + minimum: 0 + - identifier: display_aspect_den + title: Display aspect ratio denominator + type: integer + minimum: 0 + - identifier: display_ratio + title: Display aspect ratio + readonly: yes + - identifier: sample_aspect_num + title: Sample aspect ratio numerator + type: integer + minimum: 0 + - identifier: sample_aspect_den + title: Sample aspect ratio denominator + type: integer + minimum: 1 + - identifier: aspect_ratio + title: Sample aspect ratio + readonly: yes + - identifier: progressive + title: Progressive + type: integer + minimum: 0 + maximum: 1 + widget: checkbox + - identifier: colorspace + title: Colorspace + type: integer + description: Set the video colorspace (Y'CbCr only). + values: + - 240 # SMPTE 240M + - 601 # ITU-R BT.601 + - 709 # ITU-R BT.709 + - identifier: frame_rate_num + title: Frame rate numerator + type: integer + minimum: 0 + unit: frames/second + - identifier: frame_rate_den + title: Frame rate denominator + type: integer + minimum: 1 + unit: frames/second + - identifier: fps + title: Frame rate + readonly: yes + unit: frames/second + +# These are common to all consumers. + - identifier: deinterlace_method + title: Deinterlacer + type: string + default: yadif + values: + - greedy + - linearblend + - onefield + - yadif + - yadif-nospatial + - identifier: rescale + title: Image scaler + type: string + description: Set the pixel interpolation mode. + values: + - nearest + - bilinear + - bicubic + - bicublin + - gauss + - sinc + - lanczos + - spline + - identifier: frequency + title: Audio sample rate + type: integer + minimum: 0 + maximum: 256000 + default: 48000 + unit: Hz + - identifier: channels + title: Audio channels + type: integer + minimum: 1 + maximum: 16 + default: 2 + - identifier: channels.0 + title: Channels on track 1 + type: integer + description: Used to map a bundle of channels to multi-track audio. + minimum: 0 + maximum: 16 + default: 0 + - identifier: channels.1 + title: Channels on track 2 + type: integer + description: Used to map a bundle of channels to multi-track audio. + minimum: 0 + maximum: 16 + default: 0 + - identifier: channels.2 + title: Channels on track 3 + type: integer + description: Used to map a bundle of channels to multi-track audio. + minimum: 0 + maximum: 16 + default: 0 + - identifier: channels.3 + title: Channels on track 4 + type: integer + description: Used to map a bundle of channels to multi-track audio. + minimum: 0 + maximum: 16 + default: 0 + - identifier: channels.4 + title: Channels on track 5 + type: integer + description: Used to map a bundle of channels to multi-track audio. + minimum: 0 + maximum: 16 + default: 0 + - identifier: channels.5 + title: Channels on track 6 + type: integer + description: Used to map a bundle of channels to multi-track audio. + minimum: 0 + maximum: 16 + default: 0 + - identifier: channels.6 + title: Channels on track 7 + type: integer + description: Used to map a bundle of channels to multi-track audio. + minimum: 0 + maximum: 16 + default: 0 + - identifier: channels.7 + title: Channels on track 8 + type: integer + description: Used to map a bundle of channels to multi-track audio. + minimum: 0 + maximum: 16 + default: 0 + +# These are common to all consumers and affect runtime behavior + - identifier: terminate_on_pause + title: File output + type: integer + description: Disable this for streaming. + minimum: 0 + maximum: 1 + default: 1 + widget: checkbox + - identifier: real_time + title: Drop frames + type: integer + description: > + Set the number of processing threads and enable frame-dropping (positive) + or disable frame-dropping (negative). + default: -1 + widget: spinner + unit: threads + - identifier: prefill + title: Pre-roll + type: integer + description: Set the number of frames to buffer before starting actual output. + minimum: 1 + default: 1 + unit: frames + - identifier: buffer + title: Buffer + type: integer + description: > + Set the maximum number of frames to buffer - process ahead of the output + position. + minimum: 1 + default: 25 + unit: frames + +# These are ffmpeg-compatible aliases to MLT properties + - identifier: s + title: Size + type: string + description: > + This is a ffmpeg-compatible equivalent to the MLT profile and width and height parameters. + format: WxH + unit: pixels + - identifier: aspect + title: Aspect ratio + type: string + description: > + This is a ffmpeg-compatible equivalent to the MLT profile and other aspect ratio parameters. + format: numerator:denominator + - identifier: deinterlace + title: Deinterlace + type: integer + description: > + This is a ffmpeg-compatible equivalent to the MLT profile and progressive parameter. + minimum: 0 + maximum: 1 + - identifier: r + title: Frame rate + type: float + description: > + This is a ffmpeg-compatible equivalent to the MLT profile and frame rate parameters. + minimum: 5.0 + - identifier: ac + title: Audio channels + type: integer + description: > + This is a ffmpeg-compatible equivalent to the channels parameter. + minimum: 1 + maximum: 16 + default: 2 + - identifier: ar + title: Audio sample rate + type: integer + description: > + This is a ffmpeg-compatible equivalent to the frequency parameter. + minimum: 0 + maximum: 256000 + default: 48000 + unit: Hz + +# These are other non-AVOption parameters specific to FFmpeg. + - identifier: threads + title: Encoding threads + type: integer + minimum: 0 + maximum: 16 + default: 1 + widget: spinner + unit: threads + - identifier: aq + title: Audio quality + type: integer + description: The meaning depends upon the codec. + - identifier: dc + title: Intra DC precision + type: integer + default: 8 + - identifier: muxdelay + title: Muxer delay + type: float + description: Set the maximum demux-decode delay. + default: 0.7 + unit: seconds + - identifier: muxpreload + title: Muxer preload + type: float + description: Set the initial demux-decode delay. + default: 0.5 + unit: seconds + - identifier: f + title: Format + type: string + description: Use "list" to see the list of formats. + default: mpeg + - identifier: acodec + title: Audio codec + description: Use "list" to see the list of audio codecs. + default: mp2 + - identifier: vcodec + title: Video codec + description: Use "list" to see the list of video codecs. + default: mpeg2video + - identifier: atag + title: Audio FourCC + type: string + - identifier: apre + title: Audio codec preset + type: string + - identifier: vpre + title: Video codec preset + type: string + - identifier: fpre + title: Format preset + type: string + - identifier: alang + title: Audio language + type: string + description: Set the 3-character ISO 639 language code of the current audio stream. + - identifier: pix_fmt + title: Pixel format + type: string + description: > + See 'ffmpeg -pix_fmt list' to see a list of values. + Normally, this is not required, but some codecs support multiple pixel + formats, especially chroma bit-depth. + - identifier: qscale + title: Video quantizer + type: float + description: Set a fixed video quantizer scale for constant quality VBR output. + - identifier: vtag + title: Video FourCC + type: string + - identifier: rc_override + title: Rate control + type: string + format: start_frame,end_frame,qscale/... + description: This is an override for specific intervals. + - identifier: pass + title: Pass + type: integer + description: Select the pass number for two-pass encoding. + minimum: 1 + maximum: 2 + - identifier: passlogfile + title: Two-pass log file + type: string + - identifier: b + title: Video bitrate + type: string + unit: bits/second + description: > + Normally this is an integer, but you can append a K suffix for convenience. + minimum: 0 + - identifier: ab + title: Audio bitrate + type: string + unit: bits/second + description: > + Normally this is an integer, but you can append a K suffix for convenience. + - identifier: an + title: Disable audio + type: integer + minimum: 0 + maximum: 1 + widget: checkbox + - identifier: vn + title: Disable video + type: integer + minimum: 0 + maximum: 1 + widget: checkbox diff -Nru mlt-0.6.2/src/modules/avformat/factory.c mlt-0.7.2/src/modules/avformat/factory.c --- mlt-0.6.2/src/modules/avformat/factory.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/avformat/factory.c 2011-05-02 05:59:12.000000000 +0000 @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -36,6 +37,11 @@ #ifdef AVDEVICE #include #endif +#if LIBAVCODEC_VERSION_MAJOR > 52 +#include +#else +#include +#endif // A static flag used to determine if avformat has been initialised static int avformat_initialised = 0; @@ -129,10 +135,154 @@ return NULL; } +static void add_parameters( mlt_properties params, void *object, int req_flags, const char *unit, const char *subclass ) +{ + const AVOption *opt = NULL; + + // For each AVOption on the AVClass object + while ( ( opt = av_next_option( object, opt ) ) ) + { + // If matches flags and not a binary option (not supported by Mlt) + if ( !( opt->flags & req_flags ) || ( opt->type == FF_OPT_TYPE_BINARY ) ) + continue; + + // Ignore constants (keyword values) + if ( !unit && opt->type == FF_OPT_TYPE_CONST ) + continue; + // When processing a groups of options (unit)... + // ...ignore non-constants + else if ( unit && opt->type != FF_OPT_TYPE_CONST ) + continue; + // ...ignore constants not in this group + else if ( unit && opt->type == FF_OPT_TYPE_CONST && strcmp( unit, opt->unit ) ) + continue; + // ..add constants to the 'values' sequence + else if ( unit && opt->type == FF_OPT_TYPE_CONST ) + { + char key[20]; + snprintf( key, 20, "%d", mlt_properties_count( params ) ); + mlt_properties_set( params, key, opt->name ); + continue; + } + + // Create a map for this option. + mlt_properties p = mlt_properties_new(); + char key[20]; + snprintf( key, 20, "%d", mlt_properties_count( params ) ); + // Add the map to the 'parameters' sequence. + mlt_properties_set_data( params, key, p, 0, (mlt_destructor) mlt_properties_close, NULL ); + + // Add the parameter metadata for this AVOption. + mlt_properties_set( p, "identifier", opt->name ); + if ( subclass ) + { + char *s = malloc( strlen( opt->help ) + strlen( subclass ) + 4 ); + strcpy( s, opt->help ); + strcat( s, " (" ); + strcat( s, subclass ); + strcat( s, ")" ); + mlt_properties_set( p, "description", s ); + free( s ); + } + else + mlt_properties_set( p, "description", opt->help ); + + + switch ( opt->type ) + { + case FF_OPT_TYPE_FLAGS: + mlt_properties_set( p, "type", "string" ); + mlt_properties_set( p, "format", "flags" ); + break; + case FF_OPT_TYPE_INT: + if ( !opt->unit ) + { + mlt_properties_set( p, "type", "integer" ); + if ( opt->min != INT_MIN ) + mlt_properties_set_int( p, "minimum", (int) opt->min ); + if ( opt->max != INT_MAX ) + mlt_properties_set_int( p, "maximum", (int) opt->max ); +#if LIBAVUTIL_VERSION_MAJOR > 50 + mlt_properties_set_int( p, "default", (int) opt->default_val.dbl ); +#endif + } + else + { + mlt_properties_set( p, "type", "string" ); + mlt_properties_set( p, "format", "integer or keyword" ); + } + break; + case FF_OPT_TYPE_INT64: + mlt_properties_set( p, "type", "integer" ); + mlt_properties_set( p, "format", "64-bit" ); + if ( opt->min != INT64_MIN ) + mlt_properties_set_int64( p, "minimum", (int64_t) opt->min ); + if ( opt->max != INT64_MAX ) + mlt_properties_set_int64( p, "maximum", (int64_t) opt->max ); +#if LIBAVUTIL_VERSION_MAJOR > 50 + mlt_properties_set_int64( p, "default", (int64_t) opt->default_val.dbl ); +#endif + break; + case FF_OPT_TYPE_FLOAT: + mlt_properties_set( p, "type", "float" ); + if ( opt->min != FLT_MIN && opt->min != -340282346638528859811704183484516925440.0 ) + mlt_properties_set_double( p, "minimum", opt->min ); + if ( opt->max != FLT_MAX ) + mlt_properties_set_double( p, "maximum", opt->max ); +#if LIBAVUTIL_VERSION_MAJOR > 50 + mlt_properties_set_double( p, "default", opt->default_val.dbl ); +#endif + break; + case FF_OPT_TYPE_DOUBLE: + mlt_properties_set( p, "type", "float" ); + mlt_properties_set( p, "format", "double" ); + if ( opt->min != DBL_MIN ) + mlt_properties_set_double( p, "minimum", opt->min ); + if ( opt->max != DBL_MAX ) + mlt_properties_set_double( p, "maximum", opt->max ); +#if LIBAVUTIL_VERSION_MAJOR > 50 + mlt_properties_set_double( p, "default", opt->default_val.dbl ); +#endif + break; + case FF_OPT_TYPE_STRING: + mlt_properties_set( p, "type", "string" ); +#if LIBAVUTIL_VERSION_MAJOR > 50 + mlt_properties_set( p, "default", opt->default_val.str ); +#endif + break; + case FF_OPT_TYPE_RATIONAL: + mlt_properties_set( p, "type", "string" ); + mlt_properties_set( p, "format", "numerator:denominator" ); + break; + case FF_OPT_TYPE_CONST: + default: + mlt_properties_set( p, "type", "integer" ); + mlt_properties_set( p, "format", "constant" ); + break; + } + // If the option belongs to a group (unit) and is not a constant (keyword value) + if ( opt->unit && opt->type != FF_OPT_TYPE_CONST ) + { + // Create a 'values' sequence. + mlt_properties values = mlt_properties_new(); + + // Recurse to add constants in this group to the 'values' sequence. + add_parameters( values, object, req_flags, opt->unit, NULL ); + if ( mlt_properties_count( values ) ) + mlt_properties_set_data( p, "values", values, 0, (mlt_destructor) mlt_properties_close, NULL ); + else + mlt_properties_close( values ); + } + } +} + static mlt_properties avformat_metadata( mlt_service_type type, const char *id, void *data ) { char file[ PATH_MAX ]; const char *service_type = NULL; + mlt_properties result = NULL; + + // Convert the service type to a string. switch ( type ) { case consumer_type: @@ -150,8 +300,38 @@ default: return NULL; } + // Load the yaml file snprintf( file, PATH_MAX, "%s/avformat/%s_%s.yml", mlt_environment( "MLT_DATA" ), service_type, id ); - return mlt_properties_parse_yaml( file ); + result = mlt_properties_parse_yaml( file ); + if ( result && ( type == consumer_type || type == producer_type ) ) + { + // Annotate the yaml properties with AVOptions. + mlt_properties params = (mlt_properties) mlt_properties_get_data( result, "parameters", NULL ); + AVFormatContext *avformat = avformat_alloc_context(); + AVCodecContext *avcodec = avcodec_alloc_context(); + int flags = ( type == consumer_type )? AV_OPT_FLAG_ENCODING_PARAM : AV_OPT_FLAG_DECODING_PARAM; + + add_parameters( params, avformat, flags, NULL, NULL ); +#if LIBAVFORMAT_VERSION_MAJOR > 52 + avformat_init(); + AVOutputFormat *f = NULL; + while ( ( f = av_oformat_next( f ) ) ) + if ( f->priv_class ) + add_parameters( params, &f->priv_class, flags, NULL, f->name ); +#endif + + add_parameters( params, avcodec, flags, NULL, NULL ); +#if LIBAVCODEC_VERSION_MAJOR > 52 + AVCodec *c = NULL; + while ( ( c = av_codec_next( c ) ) ) + if ( c->priv_class ) + add_parameters( params, &c->priv_class, flags, NULL, c->name ); +#endif + + av_free( avformat ); + av_free( avcodec ); + } + return result; } MLT_REPOSITORY @@ -160,6 +340,7 @@ MLT_REGISTER( consumer_type, "avformat", create_service ); MLT_REGISTER( producer_type, "avformat", create_service ); MLT_REGISTER( producer_type, "avformat-novalidate", create_service ); + MLT_REGISTER_METADATA( consumer_type, "avformat", avformat_metadata, NULL ); MLT_REGISTER_METADATA( producer_type, "avformat", avformat_metadata, NULL ); #endif #ifdef FILTERS diff -Nru mlt-0.6.2/src/modules/avformat/filter_avcolour_space.c mlt-0.7.2/src/modules/avformat/filter_avcolour_space.c --- mlt-0.6.2/src/modules/avformat/filter_avcolour_space.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/avformat/filter_avcolour_space.c 2011-05-02 05:59:12.000000000 +0000 @@ -77,6 +77,7 @@ { #if defined(SWSCALE) && (LIBSWSCALE_VERSION_INT >= ((0<<16)+(7<<8)+2)) int *coefficients; + const int *new_coefficients; int full_range; int brightness, contrast, saturation; @@ -92,16 +93,19 @@ case 470: case 601: case 624: - coefficients = sws_getCoefficients( SWS_CS_ITU601 ); + new_coefficients = sws_getCoefficients( SWS_CS_ITU601 ); break; case 240: - coefficients = sws_getCoefficients( SWS_CS_SMPTE240M ); + new_coefficients = sws_getCoefficients( SWS_CS_SMPTE240M ); break; case 709: - coefficients = sws_getCoefficients( SWS_CS_ITU709 ); + new_coefficients = sws_getCoefficients( SWS_CS_ITU709 ); + break; + default: + new_coefficients = coefficients; break; } - sws_setColorspaceDetails( context, coefficients, full_range, coefficients, full_range, + sws_setColorspaceDetails( context, new_coefficients, full_range, new_coefficients, full_range, brightness, contrast, saturation ); } #endif @@ -133,7 +137,7 @@ struct SwsContext *context = sws_getContext( width, height, in_fmt, width, height, out_fmt, flags, NULL, NULL, NULL); set_luma_transfer( context, colorspace, use_full_range ); - sws_scale( context, input.data, input.linesize, 0, height, + sws_scale( context, (const uint8_t* const*) input.data, input.linesize, 0, height, output.data, output.linesize); sws_freeContext( context ); #else @@ -190,7 +194,7 @@ } while ( --n > 0 ); } - mlt_properties_set_data( properties, "alpha", alpha, len, mlt_pool_release, NULL ); + mlt_frame_set_alpha( frame, alpha, len, mlt_pool_release ); frame->get_alpha_mask = NULL; } } @@ -208,7 +212,7 @@ av_convert_image( output, *image, out_fmt, in_fmt, width, height, colorspace, force_full_luma ); *image = output; *format = output_format; - mlt_properties_set_data( properties, "image", output, size, mlt_pool_release, NULL ); + mlt_frame_set_image( frame, output, size, mlt_pool_release ); mlt_properties_set_int( properties, "format", output_format ); if ( output_format == mlt_image_rgb24a || output_format == mlt_image_opengl ) @@ -246,7 +250,7 @@ /* TODO: The below is not working because swscale does not have * adjustable coefficients yet for RGB->YUV */ - +#if 0 static int get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { int error = 0; @@ -282,6 +286,7 @@ return error; } +#endif /** Filter processing. */ @@ -325,9 +330,9 @@ return NULL; #endif #endif - mlt_filter this = mlt_filter_new( ); - if ( this != NULL ) - this->process = filter_process; - return this; + mlt_filter filter = mlt_filter_new( ); + if ( filter != NULL ) + filter->process = filter_process; + return filter; } diff -Nru mlt-0.6.2/src/modules/avformat/filter_avdeinterlace.c mlt-0.7.2/src/modules/avformat/filter_avdeinterlace.c --- mlt-0.6.2/src/modules/avformat/filter_avdeinterlace.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/avformat/filter_avdeinterlace.c 2011-05-02 05:59:12.000000000 +0000 @@ -297,21 +297,21 @@ /** Do it :-). */ -static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) +static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { int error = 0; - int deinterlace = mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "consumer_deinterlace" ); + int deinterlace = mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "consumer_deinterlace" ); // Determine if we need a writable version or not if ( deinterlace && !writable ) - writable = !mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "progressive" ); + writable = !mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "progressive" ); // Get the input image *format = mlt_image_yuv422; - error = mlt_frame_get_image( this, image, format, width, height, 1 ); + error = mlt_frame_get_image( frame, image, format, width, height, 1 ); // Check that we want progressive and we aren't already progressive - if ( deinterlace && *format == mlt_image_yuv422 && *image != NULL && !mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "progressive" ) ) + if ( deinterlace && *format == mlt_image_yuv422 && *image != NULL && !mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "progressive" ) ) { // Create a picture AVPicture *output = mlt_pool_alloc( sizeof( AVPicture ) ); @@ -324,7 +324,7 @@ mlt_pool_release( output ); // Make sure that others know the frame is deinterlaced - mlt_properties_set_int( MLT_FRAME_PROPERTIES( this ), "progressive", 1 ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "progressive", 1 ); } return error; @@ -333,7 +333,7 @@ /** Deinterlace filter processing - this should be lazy evaluation here... */ -static mlt_frame deinterlace_process( mlt_filter this, mlt_frame frame ) +static mlt_frame deinterlace_process( mlt_filter filter, mlt_frame frame ) { // Push the get_image method on to the stack mlt_frame_push_get_image( frame, filter_get_image ); @@ -346,9 +346,9 @@ mlt_filter filter_avdeinterlace_init( void *arg ) { - mlt_filter this = mlt_filter_new( ); - if ( this != NULL ) - this->process = deinterlace_process; - return this; + mlt_filter filter = mlt_filter_new( ); + if ( filter != NULL ) + filter->process = deinterlace_process; + return filter; } diff -Nru mlt-0.6.2/src/modules/avformat/filter_avresample.c mlt-0.7.2/src/modules/avformat/filter_avresample.c --- mlt-0.6.2/src/modules/avformat/filter_avresample.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/avformat/filter_avresample.c 2011-05-02 05:59:12.000000000 +0000 @@ -33,15 +33,14 @@ static int resample_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { - // Get the properties of the frame - mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); - // Get the filter service mlt_filter filter = mlt_frame_pop_audio( frame ); // Get the filter properties mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); + mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); + // Get the resample information int output_rate = mlt_properties_get_int( filter_properties, "frequency" ); int16_t *sample_buffer = mlt_properties_get_data( filter_properties, "buffer", NULL ); @@ -52,9 +51,6 @@ // Used to return number of channels in the source int channels_avail = *channels; - // Loop variable - int i; - // If no resample frequency is specified, default to requested value if ( output_rate == 0 ) output_rate = *frequency; @@ -66,9 +62,9 @@ // Duplicate channels as necessary if ( channels_avail < *channels ) { - int size = *channels * *samples * sizeof( int16_t ); + int size = mlt_audio_format_size( *format, *samples, *channels ); int16_t *new_buffer = mlt_pool_alloc( size ); - int j, k = 0; + int i, j, k; // Duplicate the existing channels for ( i = 0; i < *samples; i++ ) @@ -81,26 +77,26 @@ } // Update the audio buffer now - destroys the old - mlt_properties_set_data( properties, "audio", new_buffer, size, ( mlt_destructor )mlt_pool_release, NULL ); - + mlt_frame_set_audio( frame, new_buffer, *format, size, mlt_pool_release ); + *buffer = new_buffer; } - else if ( channels_avail == 6 && *channels == 2 ) + else if ( channels_avail > *channels ) { - // Nasty hack for ac3 5.1 audio - may be a cause of failure? - int size = *channels * *samples * sizeof( int16_t ); + int size = mlt_audio_format_size( *format, *samples, *channels ); int16_t *new_buffer = mlt_pool_alloc( size ); + int i, j; // Drop all but the first *channels for ( i = 0; i < *samples; i++ ) { - new_buffer[ ( i * *channels ) + 0 ] = ((int16_t*)(*buffer))[ ( i * channels_avail ) + 2 ]; - new_buffer[ ( i * *channels ) + 1 ] = ((int16_t*)(*buffer))[ ( i * channels_avail ) + 3 ]; + for ( j = 0; j < *channels; j++ ) + new_buffer[ ( i * *channels ) + j ] = ((int16_t*)(*buffer))[ ( i * channels_avail ) + j ]; } // Update the audio buffer now - destroys the old - mlt_properties_set_data( properties, "audio", new_buffer, size, ( mlt_destructor )mlt_pool_release, NULL ); - + mlt_frame_set_audio( frame, new_buffer, *format, size, mlt_pool_release ); + *buffer = new_buffer; } @@ -128,6 +124,8 @@ mlt_properties_set_int( filter_properties, "last_frequency", *frequency ); } + mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); + // Resample the audio used = audio_resample( resample, sample_buffer, *buffer, *samples ); int size = used * *channels * sizeof( int16_t ); @@ -146,6 +144,10 @@ *samples = used; *frequency = output_rate; } + else + { + mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); + } return 0; } @@ -153,13 +155,13 @@ /** Filter processing. */ -static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) +static mlt_frame filter_process( mlt_filter filter, mlt_frame frame ) { // Only call this if we have a means to get audio if ( mlt_frame_is_test_audio( frame ) == 0 ) { // Push the filter on to the stack - mlt_frame_push_audio( frame, this ); + mlt_frame_push_audio( frame, filter ); // Assign our get_audio method mlt_frame_push_audio( frame, resample_get_audio ); @@ -174,10 +176,10 @@ mlt_filter filter_avresample_init( char *arg ) { // Create a filter - mlt_filter this = mlt_filter_new( ); + mlt_filter filter = mlt_filter_new( ); // Initialise if successful - if ( this != NULL ) + if ( filter != NULL ) { // Calculate size of the buffer int size = AVCODEC_MAX_AUDIO_FRAME_SIZE * sizeof( int16_t ); @@ -186,18 +188,18 @@ int16_t *buffer = mlt_pool_alloc( size ); // Assign the process method - this->process = filter_process; + filter->process = filter_process; // Deal with argument if ( arg != NULL ) - mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "frequency", arg ); + mlt_properties_set( MLT_FILTER_PROPERTIES( filter ), "frequency", arg ); // Default to 2 channel output - mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "channels", 2 ); + mlt_properties_set_int( MLT_FILTER_PROPERTIES( filter ), "channels", 2 ); // Store the buffer - mlt_properties_set_data( MLT_FILTER_PROPERTIES( this ), "buffer", buffer, size, mlt_pool_release, NULL ); + mlt_properties_set_data( MLT_FILTER_PROPERTIES( filter ), "buffer", buffer, size, mlt_pool_release, NULL ); } - return this; + return filter; } diff -Nru mlt-0.6.2/src/modules/avformat/filter_swscale.c mlt-0.7.2/src/modules/avformat/filter_swscale.c --- mlt-0.6.2/src/modules/avformat/filter_swscale.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/avformat/filter_swscale.c 2011-05-02 05:59:12.000000000 +0000 @@ -47,7 +47,7 @@ break; case mlt_image_rgb24a: case mlt_image_opengl: - value = PIX_FMT_RGB32; + value = PIX_FMT_RGBA; break; case mlt_image_yuv422: value = PIX_FMT_YUYV422; @@ -63,10 +63,10 @@ return value; } -static int filter_scale( mlt_frame this, uint8_t **image, mlt_image_format *format, int iwidth, int iheight, int owidth, int oheight ) +static int filter_scale( mlt_frame frame, uint8_t **image, mlt_image_format *format, int iwidth, int iheight, int owidth, int oheight ) { // Get the properties - mlt_properties properties = MLT_FRAME_PROPERTIES( this ); + mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); // Get the requested interpolation method char *interps = mlt_properties_get( properties, "rescale.interp" ); @@ -95,19 +95,19 @@ // Determine the bytes per pixel int bpp; + mlt_image_format_size( *format, 0, 0, &bpp ); + + // Set swscale flags to get good quality switch ( *format ) { case mlt_image_yuv422: - bpp = 2; interp |= SWS_FULL_CHR_H_INP; break; case mlt_image_rgb24: - bpp = 3; interp |= SWS_FULL_CHR_H_INT; break; case mlt_image_rgb24a: case mlt_image_opengl: - bpp = 4; interp |= SWS_FULL_CHR_H_INT; break; default: @@ -142,13 +142,11 @@ if ( context ) { // Perform the scaling - sws_scale( context, input.data, input.linesize, 0, iheight, output.data, output.linesize); + sws_scale( context, (const uint8_t* const*) input.data, input.linesize, 0, iheight, output.data, output.linesize); sws_freeContext( context ); // Now update the frame - mlt_properties_set_data( properties, "image", output.data[0], owidth * ( oheight + 1 ) * bpp, ( mlt_destructor )mlt_pool_release, NULL ); - mlt_properties_set_int( properties, "width", owidth ); - mlt_properties_set_int( properties, "height", oheight ); + mlt_frame_set_image( frame, output.data[0], owidth * ( oheight + 1 ) * bpp, mlt_pool_release ); // Return the output *image = output.data[0]; @@ -159,7 +157,7 @@ if ( alpha_size > 0 && alpha_size != ( owidth * oheight ) ) { // Create the context and output image - uint8_t *alpha = mlt_frame_get_alpha_mask( this ); + uint8_t *alpha = mlt_frame_get_alpha_mask( frame ); if ( alpha ) { avformat = PIX_FMT_GRAY8; @@ -169,11 +167,11 @@ avpicture_fill( &output, outbuf, avformat, owidth, oheight ); // Perform the scaling - sws_scale( context, input.data, input.linesize, 0, iheight, output.data, output.linesize); + sws_scale( context, (const uint8_t* const*) input.data, input.linesize, 0, iheight, output.data, output.linesize); sws_freeContext( context ); // Set it back on the frame - mlt_properties_set_data( MLT_FRAME_PROPERTIES( this ), "alpha", output.data[0], owidth * oheight, mlt_pool_release, NULL ); + mlt_frame_set_alpha( frame, output.data[0], owidth * oheight, mlt_pool_release ); } } @@ -202,13 +200,13 @@ } // Create a new scaler - mlt_filter this = mlt_factory_filter( profile, "rescale", NULL ); + mlt_filter filter = mlt_factory_filter( profile, "rescale", NULL ); // If successful, then initialise it - if ( this != NULL ) + if ( filter != NULL ) { // Get the properties - mlt_properties properties = MLT_FILTER_PROPERTIES( this ); + mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); // Set the inerpolation mlt_properties_set( properties, "interpolation", "bilinear" ); @@ -217,5 +215,5 @@ mlt_properties_set_data( properties, "method", filter_scale, 0, NULL, NULL ); } - return this; + return filter; } diff -Nru mlt-0.6.2/src/modules/avformat/Makefile mlt-0.7.2/src/modules/avformat/Makefile --- mlt-0.6.2/src/modules/avformat/Makefile 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/avformat/Makefile 2011-05-02 05:59:12.000000000 +0000 @@ -56,6 +56,11 @@ SRCS := $(OBJS:.o=.c) +ifeq ($(targetos), MinGW) +OBJS += ../../win32/win32.o +SRCS += ../../win32/win32.c +endif + all: $(TARGET) $(LOCAL_FFMPEG_OBJS): diff -Nru mlt-0.6.2/src/modules/avformat/producer_avformat.c mlt-0.7.2/src/modules/avformat/producer_avformat.c --- mlt-0.6.2/src/modules/avformat/producer_avformat.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/avformat/producer_avformat.c 2011-05-02 05:59:12.000000000 +0000 @@ -31,15 +31,19 @@ // ffmpeg Header files #include -#include #ifdef SWSCALE # include #endif -#if (LIBAVCODEC_VERSION_INT >= ((51<<16)+(71<<8)+0)) -# include "audioconvert.h" +#if LIBAVCODEC_VERSION_MAJOR > 52 +#include +#elif (LIBAVCODEC_VERSION_INT >= ((51<<16)+(71<<8)+0)) +const char *avcodec_get_sample_fmt_name(int sample_fmt); #endif #ifdef VDPAU -#include +# include +#endif +#if (LIBAVUTIL_VERSION_INT > ((50<<16)+(7<<8)+0)) +# include #endif // System header files @@ -53,6 +57,15 @@ #define PIX_FMT_YUYV422 PIX_FMT_YUV422 #endif +#if LIBAVCODEC_VERSION_MAJOR > 52 +#include +#define CODEC_TYPE_VIDEO AVMEDIA_TYPE_VIDEO +#define CODEC_TYPE_AUDIO AVMEDIA_TYPE_AUDIO +#define PKT_FLAG_KEY AV_PKT_FLAG_KEY +#else +#include +#endif + #define POSITION_INITIAL (-2) #define POSITION_INVALID (-1) @@ -96,6 +109,8 @@ double resample_factor; mlt_cache image_cache; int colorspace; + pthread_mutex_t video_mutex; + pthread_mutex_t audio_mutex; #ifdef VDPAU struct { @@ -114,10 +129,14 @@ typedef struct producer_avformat_s *producer_avformat; // Forward references. -static int producer_open( producer_avformat this, mlt_profile profile, char *file ); -static int producer_get_frame( mlt_producer this, mlt_frame_ptr frame, int index ); +static int producer_open( producer_avformat self, mlt_profile profile, char *file ); +static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ); static void producer_avformat_close( producer_avformat ); static void producer_close( mlt_producer parent ); +static void producer_set_up_video( producer_avformat self, mlt_frame frame ); +static void producer_set_up_audio( producer_avformat self, mlt_frame frame ); +static void apply_properties( void *obj, mlt_properties properties, int flags ); +static int video_codec_init( producer_avformat self, int index, mlt_properties properties ); #ifdef VDPAU #include "vdpau.c" @@ -166,12 +185,12 @@ { // Construct the producer mlt_producer producer = calloc( 1, sizeof( struct mlt_producer_s ) ); - producer_avformat this = calloc( 1, sizeof( struct producer_avformat_s ) ); + producer_avformat self = calloc( 1, sizeof( struct producer_avformat_s ) ); // Initialise it - if ( mlt_producer_init( producer, this ) == 0 ) + if ( mlt_producer_init( producer, self ) == 0 ) { - this->parent = producer; + self->parent = producer; // Get the properties mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); @@ -188,7 +207,7 @@ if ( strcmp( service, "avformat-novalidate" ) ) { // Open the file - if ( producer_open( this, profile, file ) != 0 ) + if ( producer_open( self, profile, file ) != 0 ) { // Clean up mlt_producer_close( producer ); @@ -198,25 +217,25 @@ { // Close the file to release resources for large playlists - reopen later as needed avformat_lock(); - if ( this->dummy_context ) - av_close_input_file( this->dummy_context ); - this->dummy_context = NULL; - if ( this->audio_format ) - av_close_input_file( this->audio_format ); - this->audio_format = NULL; - if ( this->video_format ) - av_close_input_file( this->video_format ); - this->video_format = NULL; + if ( self->dummy_context ) + av_close_input_file( self->dummy_context ); + self->dummy_context = NULL; + if ( self->audio_format ) + av_close_input_file( self->audio_format ); + self->audio_format = NULL; + if ( self->video_format ) + av_close_input_file( self->video_format ); + self->video_format = NULL; avformat_unlock(); // Default the user-selectable indices from the auto-detected indices - mlt_properties_set_int( properties, "audio_index", this->audio_index ); - mlt_properties_set_int( properties, "video_index", this->video_index ); + mlt_properties_set_int( properties, "audio_index", self->audio_index ); + mlt_properties_set_int( properties, "video_index", self->video_index ); #ifdef VDPAU mlt_service_cache_set_size( MLT_PRODUCER_SERVICE(producer), "producer_avformat", 5 ); #endif - mlt_service_cache_put( MLT_PRODUCER_SERVICE(producer), "producer_avformat", this, 0, (mlt_destructor) producer_avformat_close ); + mlt_service_cache_put( MLT_PRODUCER_SERVICE(producer), "producer_avformat", self, 0, (mlt_destructor) producer_avformat_close ); } } else @@ -224,7 +243,7 @@ #ifdef VDPAU mlt_service_cache_set_size( MLT_PRODUCER_SERVICE(producer), "producer_avformat", 5 ); #endif - mlt_service_cache_put( MLT_PRODUCER_SERVICE(producer), "producer_avformat", this, 0, (mlt_destructor) producer_avformat_close ); + mlt_service_cache_put( MLT_PRODUCER_SERVICE(producer), "producer_avformat", self, 0, (mlt_destructor) producer_avformat_close ); } return producer; } @@ -239,6 +258,7 @@ { int i; char key[200]; + AVMetadataTag *tag = NULL; mlt_properties_set_int( meta_media, "meta.media.nb_streams", context->nb_streams ); @@ -265,7 +285,8 @@ snprintf( key, sizeof(key), "meta.media.%d.stream.frame_rate", i ); #if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(42<<8)+0) double ffmpeg_fps = av_q2d( context->streams[ i ]->avg_frame_rate ); - if (ffmpeg_fps == 0) ffmpeg_fps = av_q2d( context->streams[ i ]->r_frame_rate ); + if ( isnan( ffmpeg_fps ) || ffmpeg_fps == 0 ) + ffmpeg_fps = av_q2d( context->streams[ i ]->r_frame_rate ); mlt_properties_set_double( meta_media, key, ffmpeg_fps ); #else mlt_properties_set_double( meta_media, key, av_q2d( context->streams[ i ]->r_frame_rate ) ); @@ -307,7 +328,10 @@ if ( *audio_index < 0 ) *audio_index = i; mlt_properties_set( meta_media, key, "audio" ); -#if (LIBAVCODEC_VERSION_INT >= ((51<<16)+(71<<8)+0)) +#if LIBAVCODEC_VERSION_MAJOR > 52 + snprintf( key, sizeof(key), "meta.media.%d.codec.sample_fmt", i ); + mlt_properties_set( meta_media, key, av_get_sample_fmt_name( codec_context->sample_fmt ) ); +#elif (LIBAVCODEC_VERSION_INT >= ((51<<16)+(71<<8)+0)) snprintf( key, sizeof(key), "meta.media.%d.codec.sample_fmt", i ); mlt_properties_set( meta_media, key, avcodec_get_sample_fmt_name( codec_context->sample_fmt ) ); #endif @@ -335,7 +359,44 @@ // mlt_properties_set_int( meta_media, key, codec_context->profile ); // snprintf( key, sizeof(key), "meta.media.%d.codec.level", i ); // mlt_properties_set_int( meta_media, key, codec_context->level ); + + // Read Metadata +#if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(31<<8)+0) + while ( ( tag = av_metadata_get( stream->metadata, "", tag, AV_METADATA_IGNORE_SUFFIX ) ) ) + { + if ( tag->value && strcmp( tag->value, "" ) && strcmp( tag->value, "und" ) ) + { + snprintf( key, sizeof(key), "meta.attr.%d.stream.%s.markup", i, tag->key ); + mlt_properties_set( meta_media, key, tag->value ); + } + } +#endif } +#if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(31<<8)+0) + while ( ( tag = av_metadata_get( context->metadata, "", tag, AV_METADATA_IGNORE_SUFFIX ) ) ) + { + if ( tag->value && strcmp( tag->value, "" ) && strcmp( tag->value, "und" ) ) + { + snprintf( key, sizeof(key), "meta.attr.%s.markup", tag->key ); + mlt_properties_set( meta_media, key, tag->value ); + } + } +#else + if ( context->title && strcmp( context->title, "" ) ) + mlt_properties_set(properties, "meta.attr.title.markup", context->title ); + if ( context->author && strcmp( context->author, "" ) ) + mlt_properties_set(properties, "meta.attr.author.markup", context->author ); + if ( context->copyright && strcmp( context->copyright, "" ) ) + mlt_properties_set(properties, "meta.attr.copyright.markup", context->copyright ); + if ( context->comment ) + mlt_properties_set(properties, "meta.attr.comment.markup", context->comment ); + if ( context->album ) + mlt_properties_set(properties, "meta.attr.album.markup", context->album ); + if ( context->year ) + mlt_properties_set_int(properties, "meta.attr.year.markup", context->year ); + if ( context->track ) + mlt_properties_set_int(properties, "meta.attr.track.markup", context->track ); +#endif return meta_media; } @@ -470,7 +531,7 @@ /** Open the file. */ -static int producer_open( producer_avformat this, mlt_profile profile, char *file ) +static int producer_open( producer_avformat self, mlt_profile profile, char *file ) { // Return an error code (0 == no error) int error = 0; @@ -479,13 +540,16 @@ AVFormatContext *context = NULL; // Get the properties - mlt_properties properties = MLT_PRODUCER_PROPERTIES( this->parent ); + mlt_properties properties = MLT_PRODUCER_PROPERTIES( self->parent ); // We will treat everything with the producer fps double fps = mlt_profile_fps( profile ); - // Lock the mutex now - avformat_lock( ); + // Lock the service + pthread_mutex_init( &self->audio_mutex, NULL ); + pthread_mutex_init( &self->video_mutex, NULL ); + pthread_mutex_lock( &self->audio_mutex ); + pthread_mutex_lock( &self->video_mutex ); // If "MRL", then create AVInputFormat AVInputFormat *format = NULL; @@ -497,7 +561,11 @@ int av = 0; // Only if there is not a protocol specification that avformat can handle +#if LIBAVFORMAT_VERSION_MAJOR > 52 + if ( mrl && !avio_check( file, 0 ) ) +#else if ( mrl && !url_exist( file ) ) +#endif { // 'file' becomes format abbreviation mrl[0] = 0; @@ -517,7 +585,6 @@ params->width = 640; params->height = 480; params->time_base= (AVRational){1,25}; - // params->device = file; params->channels = 2; params->sample_rate = 48000; } @@ -542,8 +609,14 @@ params->time_base.num = atoi( value ); else if ( !strcmp( name, "sample_rate" ) ) params->sample_rate = atoi( value ); + else if ( !strcmp( name, "channel" ) ) + params->channel = atoi( value ); else if ( !strcmp( name, "channels" ) ) params->channels = atoi( value ); +#if (LIBAVUTIL_VERSION_INT > ((50<<16)+(7<<8)+0)) + else if ( !strcmp( name, "pix_fmt" ) ) + params->pix_fmt = av_get_pix_fmt( value ); +#endif else if ( !strcmp( name, "width" ) ) params->width = atoi( value ); else if ( !strcmp( name, "height" ) ) @@ -581,42 +654,56 @@ int audio_index = -1; int video_index = -1; + // Find default audio and video streams + find_default_streams( properties, context, &audio_index, &video_index ); + // Now set properties where we can (use default unknowns if required) if ( context->duration != AV_NOPTS_VALUE ) { // This isn't going to be accurate for all formats - mlt_position frames = ( mlt_position )( ( ( double )context->duration / ( double )AV_TIME_BASE ) * fps + 0.5 ); + // Workaround some clips whose estimated duration cause problems: + // http://www.kdenlive.org/mantis/view.php?id=2003 + int adjust = -3; + if ( mlt_properties_get( properties, "adjust_length" ) ) + adjust = mlt_properties_get_int( properties, "adjust_length" ); + mlt_position frames = ( mlt_position )( ( ( double )context->duration / ( double )AV_TIME_BASE ) * fps + adjust ); + if ( mlt_properties_get_position( properties, "force_length" ) > 0 ) + frames = mlt_properties_get_position( properties, "force_length" ); mlt_properties_set_position( properties, "out", frames - 1 ); mlt_properties_set_position( properties, "length", frames ); } - // Find default audio and video streams - find_default_streams( properties, context, &audio_index, &video_index ); - if ( context->start_time != AV_NOPTS_VALUE ) - this->start_time = context->start_time; + self->start_time = context->start_time; - // Check if we're seekable (something funny about mpeg here :-/) - if ( strncmp( file, "pipe:", 5 ) && - strncmp( file, "/dev/", 5 ) && - strncmp( file, "http:", 5 ) && - strncmp( file, "udp:", 4 ) && - strncmp( file, "tcp:", 4 ) && - strncmp( file, "rtsp:", 5 ) && - strncmp( file, "rtp:", 4 ) ) - { - this->seekable = av_seek_frame( context, -1, this->start_time, AVSEEK_FLAG_BACKWARD ) >= 0; - mlt_properties_set_int( properties, "seekable", this->seekable ); - this->dummy_context = context; + // Check if we're seekable + // avdevices are typically AVFMT_NOFILE and not seekable + self->seekable = !format || !( format->flags & AVFMT_NOFILE ); + if ( context->pb ) + { + // protocols can indicate if they support seeking +#if LIBAVFORMAT_VERSION_MAJOR > 52 + self->seekable = context->pb->seekable; +#else + URLContext *uc = url_fileno( context->pb ); + if ( uc ) + self->seekable = !uc->is_streamed; +#endif + } + if ( self->seekable ) + { + self->seekable = av_seek_frame( context, -1, self->start_time, AVSEEK_FLAG_BACKWARD ) >= 0; + mlt_properties_set_int( properties, "seekable", self->seekable ); + self->dummy_context = context; av_open_input_file( &context, file, NULL, 0, NULL ); av_find_stream_info( context ); } // Store selected audio and video indexes on properties - this->audio_index = audio_index; - this->video_index = video_index; - this->first_pts = -1; - this->last_position = POSITION_INITIAL; + self->audio_index = audio_index; + self->video_index = video_index; + self->first_pts = -1; + self->last_position = POSITION_INITIAL; // Fetch the width, height and aspect ratio if ( video_index != -1 ) @@ -654,44 +741,28 @@ #endif } - // Read Metadata - if ( context->title ) - mlt_properties_set(properties, "meta.attr.title.markup", context->title ); - if ( context->author ) - mlt_properties_set(properties, "meta.attr.author.markup", context->author ); - if ( context->copyright ) - mlt_properties_set(properties, "meta.attr.copyright.markup", context->copyright ); - if ( context->comment ) - mlt_properties_set(properties, "meta.attr.comment.markup", context->comment ); - if ( context->album ) - mlt_properties_set(properties, "meta.attr.album.markup", context->album ); - if ( context->year ) - mlt_properties_set_int(properties, "meta.attr.year.markup", context->year ); - if ( context->track ) - mlt_properties_set_int(properties, "meta.attr.track.markup", context->track ); - // We're going to cheat here - for a/v files, we will have two contexts (reasoning will be clear later) if ( av == 0 && audio_index != -1 && video_index != -1 ) { // We'll use the open one as our video_format - this->video_format = context; + self->video_format = context; // And open again for our audio context av_open_input_file( &context, file, NULL, 0, NULL ); av_find_stream_info( context ); // Audio context - this->audio_format = context; + self->audio_format = context; } else if ( av != 2 && video_index != -1 ) { // We only have a video context - this->video_format = context; + self->video_format = context; } else if ( audio_index != -1 ) { // We only have an audio context - this->audio_format = context; + self->audio_format = context; } else { @@ -701,26 +772,79 @@ } } - // Unlock the mutex now - avformat_unlock( ); + // Unlock the service + pthread_mutex_unlock( &self->audio_mutex ); + pthread_mutex_unlock( &self->video_mutex ); return error; } +void reopen_video( producer_avformat self, mlt_producer producer, mlt_properties properties ) +{ + mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) ); + pthread_mutex_lock( &self->audio_mutex ); + + if ( self->video_codec ) + { + avformat_lock(); + avcodec_close( self->video_codec ); + avformat_unlock(); + } + self->video_codec = NULL; + if ( self->dummy_context ) + av_close_input_file( self->dummy_context ); + self->dummy_context = NULL; + if ( self->video_format ) + av_close_input_file( self->video_format ); + self->video_format = NULL; + + int audio_index = self->audio_index; + int video_index = self->video_index; + + mlt_events_block( properties, producer ); + pthread_mutex_unlock( &self->audio_mutex ); + pthread_mutex_unlock( &self->video_mutex ); + producer_open( self, mlt_service_profile( MLT_PRODUCER_SERVICE(producer) ), + mlt_properties_get( properties, "resource" ) ); + pthread_mutex_lock( &self->video_mutex ); + pthread_mutex_lock( &self->audio_mutex ); + if ( self->dummy_context ) + { + av_close_input_file( self->dummy_context ); + self->dummy_context = NULL; + } + mlt_events_unblock( properties, producer ); + apply_properties( self->video_format, properties, AV_OPT_FLAG_DECODING_PARAM ); +#if LIBAVFORMAT_VERSION_MAJOR > 52 + if ( self->video_format->iformat && self->video_format->iformat->priv_class && self->video_format->priv_data ) + apply_properties( self->video_format->priv_data, properties, AV_OPT_FLAG_DECODING_PARAM ); +#endif + + self->audio_index = audio_index; + if ( self->video_format && video_index > -1 ) + { + self->video_index = video_index; + video_codec_init( self, video_index, properties ); + } + + pthread_mutex_unlock( &self->audio_mutex ); + mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) ); +} + /** Convert a frame position to a time code. */ -static double producer_time_of_frame( mlt_producer this, mlt_position position ) +static double producer_time_of_frame( mlt_producer producer, mlt_position position ) { - return ( double )position / mlt_producer_get_fps( this ); + return ( double )position / mlt_producer_get_fps( producer ); } - // Collect information about all audio streams +// Collect information about all audio streams -static void get_audio_streams_info( producer_avformat this ) +static void get_audio_streams_info( producer_avformat self ) { // Fetch the audio format context - AVFormatContext *context = this->audio_format; + AVFormatContext *context = self->audio_format; int i; for ( i = 0; @@ -736,29 +860,30 @@ avformat_lock( ); if ( codec && avcodec_open( codec_context, codec ) >= 0 ) { - this->audio_streams++; - this->audio_max_stream = i; - this->total_channels += codec_context->channels; - if ( codec_context->channels > this->max_channel ) - this->max_channel = codec_context->channels; - if ( codec_context->sample_rate > this->max_frequency ) - this->max_frequency = codec_context->sample_rate; + self->audio_streams++; + self->audio_max_stream = i; + self->total_channels += codec_context->channels; + if ( codec_context->channels > self->max_channel ) + self->max_channel = codec_context->channels; + if ( codec_context->sample_rate > self->max_frequency ) + self->max_frequency = codec_context->sample_rate; avcodec_close( codec_context ); } avformat_unlock( ); } } mlt_log_verbose( NULL, "[producer avformat] audio: total_streams %d max_stream %d total_channels %d max_channels %d\n", - this->audio_streams, this->audio_max_stream, this->total_channels, this->max_channel ); + self->audio_streams, self->audio_max_stream, self->total_channels, self->max_channel ); // Other audio-specific initializations - this->resample_factor = 1.0; + self->resample_factor = 1.0; } static void set_luma_transfer( struct SwsContext *context, int colorspace, int use_full_range ) { #if defined(SWSCALE) && (LIBSWSCALE_VERSION_INT >= ((0<<16)+(7<<8)+2)) int *coefficients; + const int *new_coefficients; int full_range; int brightness, contrast, saturation; @@ -774,16 +899,19 @@ case 470: case 601: case 624: - coefficients = sws_getCoefficients( SWS_CS_ITU601 ); + new_coefficients = sws_getCoefficients( SWS_CS_ITU601 ); break; case 240: - coefficients = sws_getCoefficients( SWS_CS_SMPTE240M ); + new_coefficients = sws_getCoefficients( SWS_CS_SMPTE240M ); break; case 709: - coefficients = sws_getCoefficients( SWS_CS_ITU709 ); + new_coefficients = sws_getCoefficients( SWS_CS_ITU709 ); + break; + default: + new_coefficients = coefficients; break; } - sws_setColorspaceDetails( context, coefficients, full_range, coefficients, full_range, + sws_setColorspaceDetails( context, new_coefficients, full_range, new_coefficients, full_range, brightness, contrast, saturation ); } #endif @@ -811,7 +939,7 @@ AVPicture output; avpicture_fill( &output, buffer, PIX_FMT_RGBA, width, height ); set_luma_transfer( context, colorspace, full_range ); - sws_scale( context, frame->data, frame->linesize, 0, height, + sws_scale( context, (const uint8_t* const*) frame->data, frame->linesize, 0, height, output.data, output.linesize); sws_freeContext( context ); } @@ -827,7 +955,7 @@ output.linesize[1] = width >> 1; output.linesize[2] = width >> 1; set_luma_transfer( context, colorspace, full_range ); - sws_scale( context, frame->data, frame->linesize, 0, height, + sws_scale( context, (const uint8_t* const*) frame->data, frame->linesize, 0, height, output.data, output.linesize); sws_freeContext( context ); } @@ -838,7 +966,7 @@ AVPicture output; avpicture_fill( &output, buffer, PIX_FMT_RGB24, width, height ); set_luma_transfer( context, colorspace, full_range ); - sws_scale( context, frame->data, frame->linesize, 0, height, + sws_scale( context, (const uint8_t* const*) frame->data, frame->linesize, 0, height, output.data, output.linesize); sws_freeContext( context ); } @@ -849,7 +977,7 @@ AVPicture output; avpicture_fill( &output, buffer, PIX_FMT_RGBA, width, height ); set_luma_transfer( context, colorspace, full_range ); - sws_scale( context, frame->data, frame->linesize, 0, height, + sws_scale( context, (const uint8_t* const*) frame->data, frame->linesize, 0, height, output.data, output.linesize); sws_freeContext( context ); } @@ -860,7 +988,7 @@ AVPicture output; avpicture_fill( &output, buffer, PIX_FMT_YUYV422, width, height ); set_luma_transfer( context, colorspace, full_range ); - sws_scale( context, frame->data, frame->linesize, 0, height, + sws_scale( context, (const uint8_t* const*) frame->data, frame->linesize, 0, height, output.data, output.linesize); sws_freeContext( context ); } @@ -900,7 +1028,7 @@ /** Allocate the image buffer and set it on the frame. */ -static int allocate_buffer( mlt_properties frame_properties, AVCodecContext *codec_context, uint8_t **buffer, mlt_image_format *format, int *width, int *height ) +static int allocate_buffer( mlt_frame frame, AVCodecContext *codec_context, uint8_t **buffer, mlt_image_format *format, int *width, int *height ) { int size = 0; @@ -912,28 +1040,13 @@ if ( codec_context->pix_fmt == PIX_FMT_RGB32 ) size = *width * ( *height + 1 ) * 4; - else switch ( *format ) - { - case mlt_image_yuv420p: - size = *width * 3 * ( *height + 1 ) / 2; - break; - case mlt_image_rgb24: - size = *width * ( *height + 1 ) * 3; - break; - case mlt_image_rgb24a: - case mlt_image_opengl: - size = *width * ( *height + 1 ) * 4; - break; - default: - *format = mlt_image_yuv422; - size = *width * ( *height + 1 ) * 2; - break; - } + else + size = mlt_image_format_size( *format, *width, *height, NULL ); // Construct the output image *buffer = mlt_pool_alloc( size ); if ( *buffer ) - mlt_properties_set_data( frame_properties, "image", *buffer, size, mlt_pool_release, NULL ); + mlt_frame_set_image( frame, *buffer, size, mlt_pool_release ); else size = 0; @@ -946,8 +1059,8 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { // Get the producer - producer_avformat this = mlt_frame_pop_service( frame ); - mlt_producer producer = this->parent; + producer_avformat self = mlt_frame_pop_service( frame ); + mlt_producer producer = self->parent; // Get the properties from the frame mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); @@ -958,21 +1071,23 @@ // Get the producer properties mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); + pthread_mutex_lock( &self->video_mutex ); + // Fetch the video format context - AVFormatContext *context = this->video_format; + AVFormatContext *context = self->video_format; // Get the video stream - AVStream *stream = context->streams[ this->video_index ]; + AVStream *stream = context->streams[ self->video_index ]; // Get codec context AVCodecContext *codec_context = stream->codec; // Get the image cache - if ( ! this->image_cache && ! mlt_properties_get_int( properties, "noimagecache" ) ) - this->image_cache = mlt_cache_init(); - if ( this->image_cache ) + if ( ! self->image_cache && ! mlt_properties_get_int( properties, "noimagecache" ) ) + self->image_cache = mlt_cache_init(); + if ( self->image_cache ) { - mlt_cache_item item = mlt_cache_get( this->image_cache, (void*) position ); + mlt_cache_item item = mlt_cache_get( self->image_cache, (void*) position ); *buffer = mlt_cache_item_data( item, (int*) format ); if ( *buffer ) { @@ -985,28 +1100,11 @@ *height = 1080; // Cache hit - int size; - switch ( *format ) - { - case mlt_image_yuv420p: - size = *width * 3 * ( *height + 1 ) / 2; - break; - case mlt_image_rgb24: - size = *width * ( *height + 1 ) * 3; - break; - case mlt_image_rgb24a: - case mlt_image_opengl: - size = *width * ( *height + 1 ) * 4; - break; - default: - *format = mlt_image_yuv422; - size = *width * ( *height + 1 ) * 2; - break; - } + int size = mlt_image_format_size( *format, *width, *height, NULL ); mlt_properties_set_data( frame_properties, "avformat.image_cache", item, 0, ( mlt_destructor )mlt_cache_item_close, NULL ); - mlt_properties_set_data( frame_properties, "image", *buffer, size, NULL, NULL ); - // this->top_field_first = mlt_properties_get_int( frame_properties, "top_field_first" ); - this->got_picture = 1; + mlt_frame_set_image( frame, *buffer, size, NULL ); + // self->top_field_first = mlt_properties_get_int( frame_properties, "top_field_first" ); + self->got_picture = 1; goto exit_get_image; } @@ -1014,8 +1112,6 @@ // Cache miss int image_size = 0; - avformat_lock(); - // Packet AVPacket pkt; @@ -1041,7 +1137,7 @@ strcmp( codec_context->codec->name, "mjpeg" ) && strcmp( codec_context->codec->name, "rawvideo" ); - int last_position = this->last_position; + int last_position = self->last_position; // Turn on usage of new seek API and PTS for seeking int use_new_seek = codec_context->codec_id == CODEC_ID_H264 && !strcmp( context->iformat->name, "mpegts" ); @@ -1049,20 +1145,20 @@ use_new_seek = mlt_properties_get_int( properties, "new_seek" ); // Seek if necessary - if ( position != this->video_expected || last_position < 0 ) + if ( position != self->video_expected || last_position < 0 ) { - if ( this->av_frame && position + 1 == this->video_expected ) + if ( self->av_frame && position + 1 == self->video_expected ) { // We're paused - use last image paused = 1; } - else if ( !this->seekable && position > this->video_expected && ( position - this->video_expected ) < 250 ) + else if ( !self->seekable && position > self->video_expected && ( position - self->video_expected ) < 250 ) { // Fast forward - seeking is inefficient for small distances - just ignore following frames - ignore = ( int )( ( position - this->video_expected ) / fps * source_fps ); + ignore = ( int )( ( position - self->video_expected ) / fps * source_fps ); codec_context->skip_loop_filter = AVDISCARD_NONREF; } - else if ( this->seekable && ( position < this->video_expected || position - this->video_expected >= 12 || last_position < 0 ) ) + else if ( self->seekable && ( position < self->video_expected || position - self->video_expected >= 12 || last_position < 0 ) ) { if ( use_new_seek && last_position == POSITION_INITIAL ) { @@ -1073,10 +1169,10 @@ while ( ret >= 0 && toscan-- > 0 ) { ret = av_read_frame( context, &pkt ); - if ( ret >= 0 && ( pkt.flags & PKT_FLAG_KEY ) && pkt.stream_index == this->video_index ) + if ( ret >= 0 && ( pkt.flags & PKT_FLAG_KEY ) && pkt.stream_index == self->video_index ) { - mlt_log_verbose( MLT_PRODUCER_SERVICE(producer), "first_pts %lld dts %lld pts_dts_delta %d\n", pkt.pts, pkt.dts, (int)(pkt.pts - pkt.dts) ); - this->first_pts = pkt.pts; + mlt_log_verbose( MLT_PRODUCER_SERVICE(producer), "first_pts %"PRId64" dts %"PRId64" pts_dts_delta %d\n", pkt.pts, pkt.dts, (int)(pkt.pts - pkt.dts) ); + self->first_pts = pkt.pts; toscan = 0; } av_free_packet( &pkt ); @@ -1091,9 +1187,9 @@ { timestamp = ( req_position - 0.1 / source_fps ) / ( av_q2d( stream->time_base ) * source_fps ); - mlt_log_verbose( MLT_PRODUCER_SERVICE(producer), "pos %d pts %lld ", req_position, timestamp ); - if ( this->first_pts > 0 ) - timestamp += this->first_pts; + mlt_log_verbose( MLT_PRODUCER_SERVICE(producer), "pos %d pts %"PRId64" ", req_position, timestamp ); + if ( self->first_pts > 0 ) + timestamp += self->first_pts; else if ( context->start_time != AV_NOPTS_VALUE ) timestamp += context->start_time; } @@ -1107,24 +1203,34 @@ timestamp -= AV_TIME_BASE; if ( timestamp < 0 ) timestamp = 0; - mlt_log_debug( MLT_PRODUCER_SERVICE(producer), "seeking timestamp %lld position %d expected %d last_pos %d\n", - timestamp, position, this->video_expected, last_position ); + mlt_log_debug( MLT_PRODUCER_SERVICE(producer), "seeking timestamp %"PRId64" position %d expected %d last_pos %d\n", + timestamp, position, self->video_expected, last_position ); // Seek to the timestamp if ( use_new_seek ) { codec_context->skip_loop_filter = AVDISCARD_NONREF; - av_seek_frame( context, this->video_index, timestamp, AVSEEK_FLAG_BACKWARD ); + av_seek_frame( context, self->video_index, timestamp, AVSEEK_FLAG_BACKWARD ); } - else + else if ( req_position > 0 || last_position <= 0 ) { av_seek_frame( context, -1, timestamp, AVSEEK_FLAG_BACKWARD ); } + else + { + // Re-open video stream when rewinding to beginning from somewhere else. + // This is rather ugly, and I prefer not to do it this way, but ffmpeg is + // not reliably seeking to the first frame across formats. + reopen_video( self, producer, properties ); + context = self->video_format; + stream = context->streams[ self->video_index ]; + codec_context = stream->codec; + } // Remove the cached info relating to the previous position - this->current_position = POSITION_INVALID; - this->last_position = POSITION_INVALID; - av_freep( &this->av_frame ); + self->current_position = POSITION_INVALID; + self->last_position = POSITION_INVALID; + av_freep( &self->av_frame ); if ( use_new_seek ) { @@ -1134,35 +1240,35 @@ } } - // Duplicate the last image if necessary (see comment on rawvideo below) - if ( this->av_frame && this->av_frame->linesize[0] && this->got_picture && this->seekable + // Duplicate the last image if necessary + if ( self->av_frame && self->av_frame->linesize[0] && self->got_picture && self->seekable && ( paused - || this->current_position == req_position - || ( !use_new_seek && this->current_position > req_position ) ) ) + || self->current_position == req_position + || ( !use_new_seek && self->current_position > req_position ) ) ) { // Duplicate it - if ( ( image_size = allocate_buffer( frame_properties, codec_context, buffer, format, width, height ) ) ) + if ( ( image_size = allocate_buffer( frame, codec_context, buffer, format, width, height ) ) ) { // Workaround 1088 encodings missing cropping info. if ( *height == 1088 && mlt_profile_dar( mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ) ) == 16.0/9.0 ) *height = 1080; #ifdef VDPAU - if ( this->vdpau && this->vdpau->buffer ) + if ( self->vdpau && self->vdpau->buffer ) { AVPicture picture; - picture.data[0] = this->vdpau->buffer; - picture.data[2] = this->vdpau->buffer + codec_context->width * codec_context->height; - picture.data[1] = this->vdpau->buffer + codec_context->width * codec_context->height * 5 / 4; + picture.data[0] = self->vdpau->buffer; + picture.data[2] = self->vdpau->buffer + codec_context->width * codec_context->height; + picture.data[1] = self->vdpau->buffer + codec_context->width * codec_context->height * 5 / 4; picture.linesize[0] = codec_context->width; picture.linesize[1] = codec_context->width / 2; picture.linesize[2] = codec_context->width / 2; convert_image( (AVFrame*) &picture, *buffer, - PIX_FMT_YUV420P, format, *width, *height, this->colorspace ); + PIX_FMT_YUV420P, format, *width, *height, self->colorspace ); } else #endif - convert_image( this->av_frame, *buffer, codec_context->pix_fmt, - format, *width, *height, this->colorspace ); + convert_image( self->av_frame, *buffer, codec_context->pix_fmt, + format, *width, *height, self->colorspace ); } else mlt_frame_get_image( frame, buffer, format, width, height, writable ); @@ -1177,8 +1283,8 @@ av_init_packet( &pkt ); // Construct an AVFrame for YUV422 conversion - if ( !this->av_frame ) - this->av_frame = avcodec_alloc_frame( ); + if ( !self->av_frame ) + self->av_frame = avcodec_alloc_frame( ); while( ret >= 0 && !got_picture ) { @@ -1186,21 +1292,21 @@ ret = av_read_frame( context, &pkt ); // We only deal with video from the selected video_index - if ( ret >= 0 && pkt.stream_index == this->video_index && pkt.size > 0 ) + if ( ret >= 0 && pkt.stream_index == self->video_index && pkt.size > 0 ) { // Determine time code of the packet if ( use_new_seek ) { int64_t pts = pkt.pts; - if ( this->first_pts > 0 ) - pts -= this->first_pts; + if ( self->first_pts > 0 ) + pts -= self->first_pts; else if ( context->start_time != AV_NOPTS_VALUE ) pts -= context->start_time; int_position = ( int )( av_q2d( stream->time_base ) * pts * source_fps + 0.1 ); if ( pkt.pts == AV_NOPTS_VALUE ) { - this->invalid_pts_counter++; - if ( this->invalid_pts_counter > 20 ) + self->invalid_pts_counter++; + if ( self->invalid_pts_counter > 20 ) { mlt_log_panic( MLT_PRODUCER_SERVICE(producer), "\ainvalid PTS; DISABLING NEW_SEEK!\n" ); mlt_properties_set_int( properties, "new_seek", 0 ); @@ -1210,19 +1316,19 @@ } else { - this->invalid_pts_counter = 0; + self->invalid_pts_counter = 0; } - mlt_log_debug( MLT_PRODUCER_SERVICE(producer), "pkt.pts %llu req_pos %d cur_pos %d pkt_pos %d\n", - pkt.pts, req_position, this->current_position, int_position ); + mlt_log_debug( MLT_PRODUCER_SERVICE(producer), "pkt.pts %"PRId64" req_pos %d cur_pos %d pkt_pos %d\n", + pkt.pts, req_position, self->current_position, int_position ); } else { - if ( pkt.dts != AV_NOPTS_VALUE ) + if ( self->seekable && pkt.dts != AV_NOPTS_VALUE ) { int_position = ( int )( av_q2d( stream->time_base ) * pkt.dts * source_fps + 0.5 ); if ( context->start_time != AV_NOPTS_VALUE ) int_position -= ( int )( context->start_time * source_fps / AV_TIME_BASE + 0.5 ); - last_position = this->last_position; + last_position = self->last_position; if ( int_position == last_position ) int_position = last_position + 1; } @@ -1230,8 +1336,8 @@ { int_position = req_position; } - mlt_log_debug( MLT_PRODUCER_SERVICE(producer), "pkt.dts %llu req_pos %d cur_pos %d pkt_pos %d\n", - pkt.dts, req_position, this->current_position, int_position ); + mlt_log_debug( MLT_PRODUCER_SERVICE(producer), "pkt.dts %"PRId64" req_pos %d cur_pos %d pkt_pos %d\n", + pkt.dts, req_position, self->current_position, int_position ); // Make a dumb assumption on streams that contain wild timestamps if ( abs( req_position - int_position ) > 999 ) { @@ -1239,30 +1345,30 @@ mlt_log_debug( MLT_PRODUCER_SERVICE(producer), " WILD TIMESTAMP!" ); } } - this->last_position = int_position; + self->last_position = int_position; // Decode the image if ( must_decode || int_position >= req_position ) { #ifdef VDPAU - if ( g_vdpau && this->vdpau ) + if ( g_vdpau && self->vdpau ) { - if ( g_vdpau->producer != this ) + if ( g_vdpau->producer != self ) { vdpau_decoder_close(); - vdpau_decoder_init( this ); + vdpau_decoder_init( self ); } - if ( this->vdpau ) - this->vdpau->is_decoded = 0; + if ( self->vdpau ) + self->vdpau->is_decoded = 0; } #endif codec_context->reordered_opaque = pkt.pts; if ( int_position >= req_position ) codec_context->skip_loop_filter = AVDISCARD_NONE; #if (LIBAVCODEC_VERSION_INT >= ((52<<16)+(26<<8)+0)) - ret = avcodec_decode_video2( codec_context, this->av_frame, &got_picture, &pkt ); + ret = avcodec_decode_video2( codec_context, self->av_frame, &got_picture, &pkt ); #else - ret = avcodec_decode_video( codec_context, this->av_frame, &got_picture, pkt.data, pkt.size ); + ret = avcodec_decode_video( codec_context, self->av_frame, &got_picture, pkt.data, pkt.size ); #endif // Note: decode may fail at the beginning of MPEGfile (B-frames referencing before first I-frame), so allow a few errors. if ( ret < 0 ) @@ -1281,13 +1387,13 @@ if ( use_new_seek ) { // Determine time code of the packet - int64_t pts = this->av_frame->reordered_opaque; - if ( this->first_pts > 0 ) - pts -= this->first_pts; + int64_t pts = self->av_frame->reordered_opaque; + if ( self->first_pts > 0 ) + pts -= self->first_pts; else if ( context->start_time != AV_NOPTS_VALUE ) pts -= context->start_time; int_position = ( int )( av_q2d( stream->time_base) * pts * source_fps + 0.1 ); - mlt_log_debug( MLT_PRODUCER_SERVICE(producer), "got frame %d, key %d\n", int_position, this->av_frame->key_frame ); + mlt_log_debug( MLT_PRODUCER_SERVICE(producer), "got frame %d, key %d\n", int_position, self->av_frame->key_frame ); } // Handle ignore if ( int_position < req_position ) @@ -1311,56 +1417,55 @@ // Now handle the picture if we have one if ( got_picture ) { - if ( ( image_size = allocate_buffer( frame_properties, codec_context, buffer, format, width, height ) ) ) + if ( ( image_size = allocate_buffer( frame, codec_context, buffer, format, width, height ) ) ) { // Workaround 1088 encodings missing cropping info. if ( *height == 1088 && mlt_profile_dar( mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ) ) == 16.0/9.0 ) *height = 1080; #ifdef VDPAU - if ( this->vdpau ) + if ( self->vdpau ) { - if ( this->vdpau->is_decoded ) + if ( self->vdpau->is_decoded ) { - struct vdpau_render_state *render = (struct vdpau_render_state*) this->av_frame->data[0]; + struct vdpau_render_state *render = (struct vdpau_render_state*) self->av_frame->data[0]; void *planes[3]; uint32_t pitches[3]; VdpYCbCrFormat dest_format = VDP_YCBCR_FORMAT_YV12; - AVPicture picture; - if ( !this->vdpau->buffer ) - this->vdpau->buffer = mlt_pool_alloc( codec_context->width * codec_context->height * 3 / 2 ); - picture.data[0] = planes[0] = this->vdpau->buffer; - picture.data[2] = planes[1] = this->vdpau->buffer + codec_context->width * codec_context->height; - picture.data[1] = planes[2] = this->vdpau->buffer + codec_context->width * codec_context->height * 5 / 4; - picture.linesize[0] = pitches[0] = codec_context->width; - picture.linesize[1] = pitches[1] = codec_context->width / 2; - picture.linesize[2] = pitches[2] = codec_context->width / 2; + if ( !self->vdpau->buffer ) + self->vdpau->buffer = mlt_pool_alloc( codec_context->width * codec_context->height * 3 / 2 ); + self->av_frame->data[0] = planes[0] = self->vdpau->buffer; + self->av_frame->data[2] = planes[1] = self->vdpau->buffer + codec_context->width * codec_context->height; + self->av_frame->data[1] = planes[2] = self->vdpau->buffer + codec_context->width * codec_context->height * 5 / 4; + self->av_frame->linesize[0] = pitches[0] = codec_context->width; + self->av_frame->linesize[1] = pitches[1] = codec_context->width / 2; + self->av_frame->linesize[2] = pitches[2] = codec_context->width / 2; VdpStatus status = vdp_surface_get_bits( render->surface, dest_format, planes, pitches ); if ( status == VDP_STATUS_OK ) { - convert_image( (AVFrame*) &picture, *buffer, PIX_FMT_YUV420P, - format, *width, *height, this->colorspace ); + convert_image( self->av_frame, *buffer, PIX_FMT_YUV420P, + format, *width, *height, self->colorspace ); } else { mlt_log_error( MLT_PRODUCER_SERVICE(producer), "VDPAU Error: %s\n", vdp_get_error_string( status ) ); - this->vdpau->is_decoded = 0; + image_size = self->vdpau->is_decoded = 0; } } else { mlt_log_error( MLT_PRODUCER_SERVICE(producer), "VDPAU error in VdpDecoderRender\n" ); - got_picture = 0; + image_size = got_picture = 0; } } else #endif - convert_image( this->av_frame, *buffer, codec_context->pix_fmt, - format, *width, *height, this->colorspace ); - this->top_field_first |= this->av_frame->top_field_first; - this->current_position = int_position; - this->got_picture = 1; + convert_image( self->av_frame, *buffer, codec_context->pix_fmt, + format, *width, *height, self->colorspace ); + self->top_field_first |= self->av_frame->top_field_first; + self->current_position = int_position; + self->got_picture = 1; } else { @@ -1372,37 +1477,71 @@ } } - avformat_unlock(); - - if ( this->got_picture && image_size > 0 && this->image_cache ) + if ( self->got_picture && image_size > 0 && self->image_cache ) { // Copy buffer to image cache uint8_t *image = mlt_pool_alloc( image_size ); memcpy( image, *buffer, image_size ); - mlt_cache_put( this->image_cache, (void*) position, image, *format, mlt_pool_release ); + mlt_cache_put( self->image_cache, (void*) position, image, *format, mlt_pool_release ); + } + // Try to duplicate last image if there was a decoding failure + else if ( !image_size && self->av_frame && self->av_frame->linesize[0] ) + { + // Duplicate it + if ( ( image_size = allocate_buffer( frame, codec_context, buffer, format, width, height ) ) ) + { + // Workaround 1088 encodings missing cropping info. + if ( *height == 1088 && mlt_profile_dar( mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ) ) == 16.0/9.0 ) + *height = 1080; +#ifdef VDPAU + if ( self->vdpau && self->vdpau->buffer ) + { + AVPicture picture; + picture.data[0] = self->vdpau->buffer; + picture.data[2] = self->vdpau->buffer + codec_context->width * codec_context->height; + picture.data[1] = self->vdpau->buffer + codec_context->width * codec_context->height * 5 / 4; + picture.linesize[0] = codec_context->width; + picture.linesize[1] = codec_context->width / 2; + picture.linesize[2] = codec_context->width / 2; + convert_image( (AVFrame*) &picture, *buffer, + PIX_FMT_YUV420P, format, *width, *height, self->colorspace ); + } + else +#endif + convert_image( self->av_frame, *buffer, codec_context->pix_fmt, + format, *width, *height, self->colorspace ); + self->got_picture = 1; + } + else + mlt_frame_get_image( frame, buffer, format, width, height, writable ); } // Regardless of speed, we expect to get the next frame (cos we ain't too bright) - this->video_expected = position + 1; + self->video_expected = position + 1; exit_get_image: + + pthread_mutex_unlock( &self->video_mutex ); + // Set the progressive flag if ( mlt_properties_get( properties, "force_progressive" ) ) mlt_properties_set_int( frame_properties, "progressive", !!mlt_properties_get_int( properties, "force_progressive" ) ); - else if ( this->av_frame ) - mlt_properties_set_int( frame_properties, "progressive", !this->av_frame->interlaced_frame ); + else if ( self->av_frame ) + mlt_properties_set_int( frame_properties, "progressive", !self->av_frame->interlaced_frame ); // Set the field order property for this frame if ( mlt_properties_get( properties, "force_tff" ) ) mlt_properties_set_int( frame_properties, "top_field_first", !!mlt_properties_get_int( properties, "force_tff" ) ); else - mlt_properties_set_int( frame_properties, "top_field_first", this->top_field_first ); + mlt_properties_set_int( frame_properties, "top_field_first", self->top_field_first ); // Set immutable properties of the selected track's (or overridden) source attributes. - mlt_properties_set_int( properties, "meta.media.top_field_first", this->top_field_first ); + mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) ); + mlt_properties_set_int( properties, "meta.media.top_field_first", self->top_field_first ); mlt_properties_set_int( properties, "meta.media.progressive", mlt_properties_get_int( frame_properties, "progressive" ) ); + mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) ); - return !this->got_picture; + return !self->got_picture; } /** Process properties as AVOptions and apply to AV context obj @@ -1433,13 +1572,13 @@ /** Initialize the video codec context. */ -static int video_codec_init( producer_avformat this, int index, mlt_properties properties ) +static int video_codec_init( producer_avformat self, int index, mlt_properties properties ) { // Initialise the codec if necessary - if ( !this->video_codec ) + if ( !self->video_codec ) { // Get the video stream - AVStream *stream = this->video_format->streams[ index ]; + AVStream *stream = self->video_format->streams[ index ]; // Get codec context AVCodecContext *codec_context = stream->codec; @@ -1451,14 +1590,14 @@ { if ( ( codec = avcodec_find_decoder_by_name( "h264_vdpau" ) ) ) { - if ( vdpau_init( this ) ) + if ( vdpau_init( self ) ) { - this->video_codec = codec_context; - if ( !vdpau_decoder_init( this ) ) + self->video_codec = codec_context; + if ( !vdpau_decoder_init( self ) ) vdpau_decoder_close(); } } - if ( !this->vdpau ) + if ( !self->vdpau ) codec = avcodec_find_decoder( codec_context->codec_id ); } #endif @@ -1468,38 +1607,41 @@ if ( thread_count == 0 && getenv( "MLT_AVFORMAT_THREADS" ) ) thread_count = atoi( getenv( "MLT_AVFORMAT_THREADS" ) ); if ( thread_count > 1 ) - { - avcodec_thread_init( codec_context, thread_count ); codec_context->thread_count = thread_count; - } // If we don't have a codec and we can't initialise it, we can't do much more... avformat_lock( ); if ( codec && avcodec_open( codec_context, codec ) >= 0 ) { // Now store the codec with its destructor - this->video_codec = codec_context; + self->video_codec = codec_context; } else { // Remember that we can't use this later - this->video_index = -1; + self->video_index = -1; + avformat_unlock( ); + return 0; } avformat_unlock( ); // Process properties as AVOptions apply_properties( codec_context, properties, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM ); +#if LIBAVCODEC_VERSION_MAJOR > 52 + if ( codec->priv_class && codec_context->priv_data ) + apply_properties( codec_context->priv_data, properties, AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM ); +#endif // Reset some image properties - mlt_properties_set_int( properties, "width", this->video_codec->width ); - mlt_properties_set_int( properties, "height", this->video_codec->height ); + mlt_properties_set_int( properties, "width", self->video_codec->width ); + mlt_properties_set_int( properties, "height", self->video_codec->height ); // For DV, we'll just use the saved aspect ratio if ( codec_context->codec_id != CODEC_ID_DVVIDEO ) - get_aspect_ratio( properties, stream, this->video_codec, NULL ); + get_aspect_ratio( properties, stream, self->video_codec, NULL ); // Determine the fps first from the codec - double source_fps = (double) this->video_codec->time_base.den / - ( this->video_codec->time_base.num == 0 ? 1 : this->video_codec->time_base.num ); + double source_fps = (double) self->video_codec->time_base.den / + ( self->video_codec->time_base.num == 0 ? 1 : self->video_codec->time_base.num ); if ( mlt_properties_get( properties, "force_fps" ) ) { @@ -1513,7 +1655,8 @@ // If the muxer reports a frame rate different than the codec #if LIBAVFORMAT_VERSION_INT >= ((52<<16)+(42<<8)+0) double muxer_fps = av_q2d( stream->avg_frame_rate ); - if ( muxer_fps == 0 ) muxer_fps = av_q2d( stream->r_frame_rate ); + if ( isnan( muxer_fps ) || muxer_fps == 0 ) + muxer_fps = av_q2d( stream->r_frame_rate ); #else double muxer_fps = av_q2d( stream->r_frame_rate ); #endif @@ -1521,8 +1664,8 @@ source_fps = FFMIN( source_fps, muxer_fps ); if ( source_fps >= 1.0 && ( source_fps < muxer_fps || isnan( muxer_fps ) ) ) { - mlt_properties_set_int( properties, "meta.media.frame_rate_num", this->video_codec->time_base.den ); - mlt_properties_set_int( properties, "meta.media.frame_rate_den", this->video_codec->time_base.num == 0 ? 1 : this->video_codec->time_base.num ); + mlt_properties_set_int( properties, "meta.media.frame_rate_num", self->video_codec->time_base.den ); + mlt_properties_set_int( properties, "meta.media.frame_rate_den", self->video_codec->time_base.num == 0 ? 1 : self->video_codec->time_base.num ); } else if ( muxer_fps > 0 ) { @@ -1541,7 +1684,7 @@ } else { - source_fps = mlt_producer_get_fps( this->parent ); + source_fps = mlt_producer_get_fps( self->parent ); AVRational frame_rate = av_d2q( source_fps, 255 ); mlt_properties_set_int( properties, "meta.media.frame_rate_num", frame_rate.num ); mlt_properties_set_int( properties, "meta.media.frame_rate_den", frame_rate.den ); @@ -1552,51 +1695,51 @@ if ( source_fps > 0 ) mlt_properties_set_double( properties, "source_fps", source_fps ); else - mlt_properties_set_double( properties, "source_fps", mlt_producer_get_fps( this->parent ) ); + mlt_properties_set_double( properties, "source_fps", mlt_producer_get_fps( self->parent ) ); // Set the YUV colorspace from override or detect - this->colorspace = mlt_properties_get_int( properties, "force_colorspace" ); + self->colorspace = mlt_properties_get_int( properties, "force_colorspace" ); #if LIBAVCODEC_VERSION_INT > ((52<<16)+(28<<8)+0) - if ( ! this->colorspace ) + if ( ! self->colorspace ) { - switch ( this->video_codec->colorspace ) + switch ( self->video_codec->colorspace ) { case AVCOL_SPC_SMPTE240M: - this->colorspace = 240; + self->colorspace = 240; break; case AVCOL_SPC_BT470BG: case AVCOL_SPC_SMPTE170M: - this->colorspace = 601; + self->colorspace = 601; break; case AVCOL_SPC_BT709: - this->colorspace = 709; + self->colorspace = 709; break; default: // This is a heuristic Charles Poynton suggests in "Digital Video and HDTV" - this->colorspace = this->video_codec->width * this->video_codec->height > 750000 ? 709 : 601; + self->colorspace = self->video_codec->width * self->video_codec->height > 750000 ? 709 : 601; break; } } #endif // Let apps get chosen colorspace - mlt_properties_set_int( properties, "meta.media.colorspace", this->colorspace ); + mlt_properties_set_int( properties, "meta.media.colorspace", self->colorspace ); } - return this->video_codec && this->video_index > -1; + return self->video_codec && self->video_index > -1; } /** Set up video handling. */ -static void producer_set_up_video( producer_avformat this, mlt_frame frame ) +static void producer_set_up_video( producer_avformat self, mlt_frame frame ) { // Get the producer - mlt_producer producer = this->parent; + mlt_producer producer = self->parent; // Get the properties mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); // Fetch the video format context - AVFormatContext *context = this->video_format; + AVFormatContext *context = self->video_format; // Get the video_index int index = mlt_properties_get_int( properties, "video_index" ); @@ -1605,22 +1748,27 @@ if ( !context && index > -1 ) { mlt_events_block( properties, producer ); - producer_open( this, mlt_service_profile( MLT_PRODUCER_SERVICE(producer) ), + producer_open( self, mlt_service_profile( MLT_PRODUCER_SERVICE(producer) ), mlt_properties_get( properties, "resource" ) ); - context = this->video_format; - if ( this->dummy_context ) + context = self->video_format; + if ( self->dummy_context ) { - avformat_lock(); - av_close_input_file( this->dummy_context ); - avformat_unlock(); + av_close_input_file( self->dummy_context ); + self->dummy_context = NULL; } - this->dummy_context = NULL; mlt_events_unblock( properties, producer ); - if ( this->audio_format ) - get_audio_streams_info( this ); + if ( self->audio_format && !self->audio_streams ) + get_audio_streams_info( self ); // Process properties as AVOptions - apply_properties( context, properties, AV_OPT_FLAG_DECODING_PARAM ); + if ( context ) + { + apply_properties( context, properties, AV_OPT_FLAG_DECODING_PARAM ); +#if LIBAVFORMAT_VERSION_MAJOR > 52 + if ( context->iformat && context->iformat->priv_class && context->priv_data ) + apply_properties( context->priv_data, properties, AV_OPT_FLAG_DECODING_PARAM ); +#endif + } } // Exception handling for video_index @@ -1640,24 +1788,24 @@ } // Update the video properties if the index changed - if ( index != this->video_index ) + if ( index != self->video_index ) { // Reset the video properties if the index changed - this->video_index = index; - if ( this->video_codec ) + self->video_index = index; + if ( self->video_codec ) { avformat_lock(); - avcodec_close( this->video_codec ); + avcodec_close( self->video_codec ); avformat_unlock(); } - this->video_codec = NULL; + self->video_codec = NULL; } // Get the frame properties mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); // Get the codec - if ( context && index > -1 && video_codec_init( this, index, properties ) ) + if ( context && index > -1 && video_codec_init( self, index, properties ) ) { // Set the frame properties double force_aspect_ratio = mlt_properties_get_double( properties, "force_aspect_ratio" ); @@ -1665,25 +1813,25 @@ force_aspect_ratio : mlt_properties_get_double( properties, "aspect_ratio" ); // Set the width and height - mlt_properties_set_int( frame_properties, "width", this->video_codec->width ); - mlt_properties_set_int( frame_properties, "height", this->video_codec->height ); + mlt_properties_set_int( frame_properties, "width", self->video_codec->width ); + mlt_properties_set_int( frame_properties, "height", self->video_codec->height ); // real_width and real_height are deprecated in favor of meta.media.width and .height - mlt_properties_set_int( properties, "meta.media.width", this->video_codec->width ); - mlt_properties_set_int( properties, "meta.media.height", this->video_codec->height ); - mlt_properties_set_int( frame_properties, "real_width", this->video_codec->width ); - mlt_properties_set_int( frame_properties, "real_height", this->video_codec->height ); + mlt_properties_set_int( properties, "meta.media.width", self->video_codec->width ); + mlt_properties_set_int( properties, "meta.media.height", self->video_codec->height ); + mlt_properties_set_int( frame_properties, "real_width", self->video_codec->width ); + mlt_properties_set_int( frame_properties, "real_height", self->video_codec->height ); mlt_properties_set_double( frame_properties, "aspect_ratio", aspect_ratio ); - mlt_properties_set_int( frame_properties, "colorspace", this->colorspace ); + mlt_properties_set_int( frame_properties, "colorspace", self->colorspace ); // Workaround 1088 encodings missing cropping info. - if ( this->video_codec->height == 1088 && mlt_profile_dar( mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ) ) == 16.0/9.0 ) + if ( self->video_codec->height == 1088 && mlt_profile_dar( mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ) ) == 16.0/9.0 ) { mlt_properties_set_int( properties, "meta.media.height", 1080 ); mlt_properties_set_int( frame_properties, "real_height", 1080 ); } // Add our image operation - mlt_frame_push_service( frame, this ); + mlt_frame_push_service( frame, self ); mlt_frame_push_get_image( frame, producer_get_image ); } else @@ -1693,26 +1841,26 @@ } } -static int seek_audio( producer_avformat this, mlt_position position, double timecode, int *ignore ) +static int seek_audio( producer_avformat self, mlt_position position, double timecode, int *ignore ) { int paused = 0; // Seek if necessary - if ( position != this->audio_expected ) + if ( position != self->audio_expected ) { - if ( position + 1 == this->audio_expected ) + if ( position + 1 == self->audio_expected ) { // We're paused - silence required paused = 1; } - else if ( !this->seekable && position > this->audio_expected && ( position - this->audio_expected ) < 250 ) + else if ( !self->seekable && position > self->audio_expected && ( position - self->audio_expected ) < 250 ) { // Fast forward - seeking is inefficient for small distances - just ignore following frames - *ignore = position - this->audio_expected; + *ignore = position - self->audio_expected; } - else if ( position < this->audio_expected || position - this->audio_expected >= 12 ) + else if ( position < self->audio_expected || position - self->audio_expected >= 12 ) { - AVFormatContext *context = this->audio_format; + AVFormatContext *context = self->audio_format; int64_t timestamp = ( int64_t )( timecode * AV_TIME_BASE + 0.5 ); if ( context->start_time != AV_NOPTS_VALUE ) timestamp += context->start_time; @@ -1726,31 +1874,31 @@ // Clear the usage in the audio buffer int i = MAX_AUDIO_STREAMS + 1; while ( --i ) - this->audio_used[i - 1] = 0; + self->audio_used[i - 1] = 0; } } return paused; } -static int decode_audio( producer_avformat this, int *ignore, AVPacket pkt, int channels, int samples, double timecode, double fps ) +static int decode_audio( producer_avformat self, int *ignore, AVPacket pkt, int channels, int samples, double timecode, double fps ) { // Fetch the audio_format - AVFormatContext *context = this->audio_format; + AVFormatContext *context = self->audio_format; // Get the current stream index int index = pkt.stream_index; // Get codec context - AVCodecContext *codec_context = this->audio_codec[ index ]; + AVCodecContext *codec_context = self->audio_codec[ index ]; // Obtain the resample context if it exists (not always needed) - ReSampleContext *resample = this->audio_resample[ index ]; + ReSampleContext *resample = self->audio_resample[ index ]; // Obtain the audio buffers - int16_t *audio_buffer = this->audio_buffer[ index ]; - int16_t *decode_buffer = this->decode_buffer[ index ]; + int16_t *audio_buffer = self->audio_buffer[ index ]; + int16_t *decode_buffer = self->decode_buffer[ index ]; - int audio_used = this->audio_used[ index ]; + int audio_used = self->audio_used[ index ]; uint8_t *ptr = pkt.data; int len = pkt.size; int ret = 0; @@ -1769,7 +1917,7 @@ #endif if ( ret < 0 ) { - mlt_log_warning( MLT_PRODUCER_SERVICE(this->parent), "audio decoding error %d\n", ret ); + mlt_log_warning( MLT_PRODUCER_SERVICE(self->parent), "audio decoding error %d\n", ret ); break; } @@ -1780,14 +1928,18 @@ if ( data_size > 0 ) { // Figure out how many samples will be needed after resampling +#if LIBAVCODEC_VERSION_MAJOR > 52 + int convert_samples = data_size / codec_context->channels / ( av_get_bits_per_sample_fmt( codec_context->sample_fmt ) / 8 ); +#else int convert_samples = data_size / codec_context->channels / ( av_get_bits_per_sample_format( codec_context->sample_fmt ) / 8 ); - int samples_needed = this->resample_factor * convert_samples + 1; +#endif + int samples_needed = self->resample_factor * convert_samples + 1; // Resize audio buffer to prevent overflow - if ( audio_used * channels + samples_needed > this->audio_buffer_size[ index ] ) + if ( audio_used * channels + samples_needed > self->audio_buffer_size[ index ] ) { - this->audio_buffer_size[ index ] *= 2; - audio_buffer = this->audio_buffer[ index ] = mlt_pool_realloc( audio_buffer, this->audio_buffer_size[ index ] * sizeof(int16_t) ); + self->audio_buffer_size[ index ] *= 2; + audio_buffer = self->audio_buffer[ index ] = mlt_pool_realloc( audio_buffer, self->audio_buffer_size[ index ] * sizeof(int16_t) ); } if ( resample ) { @@ -1823,99 +1975,101 @@ if ( context->start_time != AV_NOPTS_VALUE ) int_position -= ( int )( fps * context->start_time / AV_TIME_BASE + 0.5 ); - if ( this->seekable && *ignore == 0 ) + if ( self->seekable && *ignore == 0 ) { if ( int_position < req_position ) // We are behind, so skip some *ignore = 1; else if ( int_position > req_position + 2 ) // We are ahead, so seek backwards some more - seek_audio( this, req_position, timecode - 1.0, ignore ); + seek_audio( self, req_position, timecode - 1.0, ignore ); } } - this->audio_used[ index ] = audio_used; + self->audio_used[ index ] = audio_used; return ret; } /** Get the audio from a frame. */ - static int producer_get_audio( mlt_frame frame, void **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { // Get the producer - producer_avformat this = mlt_frame_pop_audio( frame ); + producer_avformat self = mlt_frame_pop_audio( frame ); + pthread_mutex_lock( &self->audio_mutex ); + // Obtain the frame number of this frame mlt_position position = mlt_properties_get_position( MLT_FRAME_PROPERTIES( frame ), "avformat_position" ); // Calculate the real time code - double real_timecode = producer_time_of_frame( this->parent, position ); + double real_timecode = producer_time_of_frame( self->parent, position ); // Get the producer fps - double fps = mlt_producer_get_fps( this->parent ); + double fps = mlt_producer_get_fps( self->parent ); // Number of frames to ignore (for ffwd) int ignore = 0; // Flag for paused (silence) - int paused = seek_audio( this, position, real_timecode, &ignore ); + int paused = seek_audio( self, position, real_timecode, &ignore ); // Fetch the audio_format - AVFormatContext *context = this->audio_format; + AVFormatContext *context = self->audio_format; // Determine the tracks to use - int index = this->audio_index; - int index_max = this->audio_index + 1; - if ( this->audio_index == INT_MAX ) + int index = self->audio_index; + int index_max = self->audio_index + 1; + if ( self->audio_index == INT_MAX ) { index = 0; index_max = context->nb_streams; - *channels = this->total_channels; - *frequency = this->max_frequency; + *channels = self->total_channels; + *samples = *samples * FFMAX( self->max_frequency, *frequency ) / *frequency; + *frequency = FFMAX( self->max_frequency, *frequency ); } // Initialize the resamplers and buffers for ( ; index < index_max; index++ ) { // Get codec context - AVCodecContext *codec_context = this->audio_codec[ index ]; + AVCodecContext *codec_context = self->audio_codec[ index ]; - if ( codec_context && !this->audio_buffer[ index ] ) + if ( codec_context && !self->audio_buffer[ index ] ) { // Check for resample and create if necessary if ( codec_context->channels <= 2 ) { // Determine by how much resampling will increase number of samples - double resample_factor = this->audio_index == INT_MAX ? 1 : (double) *channels / codec_context->channels; + double resample_factor = self->audio_index == INT_MAX ? 1 : (double) *channels / codec_context->channels; resample_factor *= (double) *frequency / codec_context->sample_rate; - if ( resample_factor > this->resample_factor ) - this->resample_factor = resample_factor; + if ( resample_factor > self->resample_factor ) + self->resample_factor = resample_factor; // Create the resampler #if (LIBAVCODEC_VERSION_INT >= ((52<<16)+(15<<8)+0)) - this->audio_resample[ index ] = av_audio_resample_init( - this->audio_index == INT_MAX ? codec_context->channels : *channels, + self->audio_resample[ index ] = av_audio_resample_init( + self->audio_index == INT_MAX ? codec_context->channels : *channels, codec_context->channels, *frequency, codec_context->sample_rate, SAMPLE_FMT_S16, codec_context->sample_fmt, 16, 10, 0, 0.8 ); #else - this->audio_resample[ index ] = audio_resample_init( - this->audio_index == INT_MAX ? codec_context->channels : *channels, + self->audio_resample[ index ] = audio_resample_init( + self->audio_index == INT_MAX ? codec_context->channels : *channels, codec_context->channels, *frequency, codec_context->sample_rate ); #endif } else { - codec_context->request_channels = this->audio_index == INT_MAX ? codec_context->channels : *channels; + codec_context->request_channels = self->audio_index == INT_MAX ? codec_context->channels : *channels; } // Check for audio buffer and create if necessary - this->audio_buffer_size[ index ] = AVCODEC_MAX_AUDIO_FRAME_SIZE; - this->audio_buffer[ index ] = mlt_pool_alloc( this->audio_buffer_size[ index ] * sizeof( int16_t ) ); + self->audio_buffer_size[ index ] = AVCODEC_MAX_AUDIO_FRAME_SIZE; + self->audio_buffer[ index ] = mlt_pool_alloc( self->audio_buffer_size[ index ] * sizeof( int16_t ) ); // Check for decoder buffer and create if necessary - this->decode_buffer[ index ] = av_malloc( AVCODEC_MAX_AUDIO_FRAME_SIZE * sizeof( int16_t ) ); + self->decode_buffer[ index ] = av_malloc( AVCODEC_MAX_AUDIO_FRAME_SIZE * sizeof( int16_t ) ); } } @@ -1931,13 +2085,13 @@ // If not resampling, give consumer more than requested. // It requested number samples based on requested frame rate. // Do not clean this up with a samples *= ...! - if ( this->audio_index != INT_MAX && ! this->audio_resample[ this->audio_index ] ) - *samples = *samples * this->audio_codec[ this->audio_index ]->sample_rate / *frequency; + if ( self->audio_index != INT_MAX && ! self->audio_resample[ self->audio_index ] ) + *samples = *samples * self->audio_codec[ self->audio_index ]->sample_rate / *frequency; while ( ret >= 0 && !got_audio ) { // Check if the buffer already contains the samples required - if ( this->audio_index != INT_MAX && this->audio_used[ this->audio_index ] >= *samples && ignore == 0 ) + if ( self->audio_index != INT_MAX && self->audio_used[ self->audio_index ] >= *samples && ignore == 0 ) { got_audio = 1; break; @@ -1947,26 +2101,33 @@ ret = av_read_frame( context, &pkt ); // We only deal with audio from the selected audio index - if ( ret >= 0 && pkt.data && pkt.size > 0 && ( pkt.stream_index == this->audio_index || - ( this->audio_index == INT_MAX && context->streams[ pkt.stream_index ]->codec->codec_type == CODEC_TYPE_AUDIO ) ) ) + if ( ret >= 0 && pkt.data && pkt.size > 0 && ( pkt.stream_index == self->audio_index || + ( self->audio_index == INT_MAX && context->streams[ pkt.stream_index ]->codec->codec_type == CODEC_TYPE_AUDIO ) ) ) { - int channels2 = this->audio_index == INT_MAX ? this->audio_codec[pkt.stream_index]->channels : *channels; - ret = decode_audio( this, &ignore, pkt, channels2, *samples, real_timecode, fps ); + int channels2 = self->audio_index == INT_MAX ? self->audio_codec[pkt.stream_index]->channels : *channels; + ret = decode_audio( self, &ignore, pkt, channels2, *samples, real_timecode, fps ); } av_free_packet( &pkt ); - if ( this->audio_index == INT_MAX && ret >= 0 ) + if ( self->audio_index == INT_MAX && ret >= 0 ) { // Determine if there is enough audio for all streams got_audio = 1; for ( index = 0; index < context->nb_streams; index++ ) { - if ( this->audio_codec[ index ] && this->audio_used[ index ] < *samples ) + if ( self->audio_codec[ index ] && self->audio_used[ index ] < *samples ) got_audio = 0; } } } - + + // Set some additional return values + if ( self->audio_index != INT_MAX && !self->audio_resample[ self->audio_index ] ) + { + *channels = self->audio_codec[ self->audio_index ]->channels; + *frequency = self->audio_codec[ self->audio_index ]->sample_rate; + } + // Allocate and set the frame's audio buffer int size = *samples * *channels * sizeof(int16_t); *buffer = mlt_pool_alloc( size ); @@ -1974,55 +2135,49 @@ mlt_frame_set_audio( frame, *buffer, *format, size, mlt_pool_release ); // Interleave tracks if audio_index=all - if ( this->audio_index == INT_MAX ) + if ( self->audio_index == INT_MAX ) { int16_t *dest = *buffer; int i; for ( i = 0; i < *samples; i++ ) { for ( index = 0; index < index_max; index++ ) - if ( this->audio_codec[ index ] ) + if ( self->audio_codec[ index ] ) { - int current_channels = this->audio_codec[ index ]->channels; - int16_t *src = this->audio_buffer[ index ] + i * current_channels; + int current_channels = self->audio_codec[ index ]->channels; + int16_t *src = self->audio_buffer[ index ] + i * current_channels; memcpy( dest, src, current_channels * sizeof(int16_t) ); dest += current_channels; } } for ( index = 0; index < index_max; index++ ) - if ( this->audio_codec[ index ] && this->audio_used[ index ] >= *samples ) + if ( self->audio_codec[ index ] && self->audio_used[ index ] >= *samples ) { - int current_channels = this->audio_codec[ index ]->channels; - int16_t *src = this->audio_buffer[ index ] + *samples * current_channels; - this->audio_used[index] -= *samples; - memmove( this->audio_buffer[ index ], src, this->audio_used[ index ] * current_channels * sizeof(int16_t) ); + int current_channels = self->audio_codec[ index ]->channels; + int16_t *src = self->audio_buffer[ index ] + *samples * current_channels; + self->audio_used[index] -= *samples; + memmove( self->audio_buffer[ index ], src, self->audio_used[ index ] * current_channels * sizeof(int16_t) ); } } // Copy a single track to the output buffer else { - index = this->audio_index; + index = self->audio_index; // Now handle the audio if we have enough - if ( this->audio_used[ index ] > 0 ) + if ( self->audio_used[ index ] > 0 ) { - int16_t *src = this->audio_buffer[ index ]; - *samples = this->audio_used[ index ] < *samples ? this->audio_used[ index ] : *samples; + int16_t *src = self->audio_buffer[ index ]; + *samples = self->audio_used[ index ] < *samples ? self->audio_used[ index ] : *samples; memcpy( *buffer, src, *samples * *channels * sizeof(int16_t) ); - this->audio_used[ index ] -= *samples; - memmove( src, &src[ *samples * *channels ], this->audio_used[ index ] * *channels * sizeof(int16_t) ); + self->audio_used[ index ] -= *samples; + memmove( src, &src[ *samples * *channels ], self->audio_used[ index ] * *channels * sizeof(int16_t) ); } else { // Otherwise fill with silence memset( *buffer, 0, *samples * *channels * sizeof(int16_t) ); } - if ( !this->audio_resample[ index ] ) - { - // TODO: uncomment and remove following line when full multi-channel support is ready - // *channels = codec_context->channels; - *frequency = this->audio_codec[ index ]->sample_rate; - } } } else @@ -2033,7 +2188,9 @@ // Regardless of speed (other than paused), we expect to get the next frame if ( !paused ) - this->audio_expected = position + 1; + self->audio_expected = position + 1; + + pthread_mutex_unlock( &self->audio_mutex ); return 0; } @@ -2041,13 +2198,13 @@ /** Initialize the audio codec context. */ -static int audio_codec_init( producer_avformat this, int index, mlt_properties properties ) +static int audio_codec_init( producer_avformat self, int index, mlt_properties properties ) { // Initialise the codec if necessary - if ( !this->audio_codec[ index ] ) + if ( !self->audio_codec[ index ] ) { // Get codec context - AVCodecContext *codec_context = this->audio_format->streams[index]->codec; + AVCodecContext *codec_context = self->audio_format->streams[index]->codec; // Find the codec AVCodec *codec = avcodec_find_decoder( codec_context->codec_id ); @@ -2057,36 +2214,40 @@ if ( codec && avcodec_open( codec_context, codec ) >= 0 ) { // Now store the codec with its destructor - if ( this->audio_codec[ index ] ) - avcodec_close( this->audio_codec[ index ] ); - this->audio_codec[ index ] = codec_context; + if ( self->audio_codec[ index ] ) + avcodec_close( self->audio_codec[ index ] ); + self->audio_codec[ index ] = codec_context; } else { - // Remember that we can't use this later - this->audio_index = -1; + // Remember that we can't use self later + self->audio_index = -1; } avformat_unlock( ); // Process properties as AVOptions apply_properties( codec_context, properties, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM ); +#if LIBAVCODEC_VERSION_MAJOR > 52 + if ( codec && codec->priv_class && codec_context->priv_data ) + apply_properties( codec_context->priv_data, properties, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM ); +#endif } - return this->audio_codec[ index ] && this->audio_index > -1; + return self->audio_codec[ index ] && self->audio_index > -1; } /** Set up audio handling. */ -static void producer_set_up_audio( producer_avformat this, mlt_frame frame ) +static void producer_set_up_audio( producer_avformat self, mlt_frame frame ) { // Get the producer - mlt_producer producer = this->parent; + mlt_producer producer = self->parent; // Get the properties mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); // Fetch the audio format context - AVFormatContext *context = this->audio_format; + AVFormatContext *context = self->audio_format; mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); @@ -2094,27 +2255,26 @@ int index = mlt_properties_get_int( properties, "audio_index" ); // Handle all audio tracks - if ( this->audio_index > -1 && + if ( self->audio_index > -1 && mlt_properties_get( properties, "audio_index" ) && !strcmp( mlt_properties_get( properties, "audio_index" ), "all" ) ) index = INT_MAX; // Reopen the file if necessary - if ( !context && this->audio_index > -1 && index > -1 ) + if ( !context && self->audio_index > -1 && index > -1 ) { mlt_events_block( properties, producer ); - producer_open( this, mlt_service_profile( MLT_PRODUCER_SERVICE(producer) ), + producer_open( self, mlt_service_profile( MLT_PRODUCER_SERVICE(producer) ), mlt_properties_get( properties, "resource" ) ); - context = this->audio_format; - if ( this->dummy_context ) + context = self->audio_format; + if ( self->dummy_context ) { - avformat_lock(); - av_close_input_file( this->dummy_context ); - avformat_unlock(); + av_close_input_file( self->dummy_context ); + self->dummy_context = NULL; } - this->dummy_context = NULL; mlt_events_unblock( properties, producer ); - get_audio_streams_info( this ); + if ( self->audio_format ) + get_audio_streams_info( self ); } // Exception handling for audio_index @@ -2128,50 +2288,50 @@ if ( context && index > -1 && index < INT_MAX && context->streams[ index ]->codec->codec_type != CODEC_TYPE_AUDIO ) { - index = this->audio_index; + index = self->audio_index; mlt_properties_set_int( properties, "audio_index", index ); } // Update the audio properties if the index changed - if ( context && index > -1 && index != this->audio_index ) + if ( context && index > -1 && index != self->audio_index ) { - if ( this->audio_codec[ this->audio_index ] ) + if ( self->audio_codec[ self->audio_index ] ) { avformat_lock(); - avcodec_close( this->audio_codec[ this->audio_index ] ); + avcodec_close( self->audio_codec[ self->audio_index ] ); avformat_unlock(); } - this->audio_codec[ this->audio_index ] = NULL; + self->audio_codec[ self->audio_index ] = NULL; } - if ( this->audio_index != -1 ) - this->audio_index = index; + if ( self->audio_index != -1 ) + self->audio_index = index; else index = -1; // Get the codec(s) if ( context && index == INT_MAX ) { - mlt_properties_set_int( frame_properties, "frequency", this->max_frequency ); - mlt_properties_set_int( frame_properties, "channels", this->total_channels ); + mlt_properties_set_int( frame_properties, "frequency", self->max_frequency ); + mlt_properties_set_int( frame_properties, "channels", self->total_channels ); for ( index = 0; index < context->nb_streams; index++ ) { if ( context->streams[ index ]->codec->codec_type == CODEC_TYPE_AUDIO ) - audio_codec_init( this, index, properties ); + audio_codec_init( self, index, properties ); } } - else if ( context && index > -1 && audio_codec_init( this, index, properties ) ) + else if ( context && index > -1 && audio_codec_init( self, index, properties ) ) { // Set the frame properties if ( index < INT_MAX ) { - mlt_properties_set_int( frame_properties, "frequency", this->audio_codec[ index ]->sample_rate ); - mlt_properties_set_int( frame_properties, "channels", this->audio_codec[ index ]->channels ); + mlt_properties_set_int( frame_properties, "frequency", self->audio_codec[ index ]->sample_rate ); + mlt_properties_set_int( frame_properties, "channels", self->audio_codec[ index ]->channels ); } } if ( context && index > -1 ) { // Add our audio operation - mlt_frame_push_audio( frame, this ); + mlt_frame_push_audio( frame, self ); mlt_frame_push_audio( frame, producer_get_audio ); } } @@ -2184,15 +2344,15 @@ // Access the private data mlt_service service = MLT_PRODUCER_SERVICE( producer ); mlt_cache_item cache_item = mlt_service_cache_get( service, "producer_avformat" ); - producer_avformat this = mlt_cache_item_data( cache_item, NULL ); + producer_avformat self = mlt_cache_item_data( cache_item, NULL ); // If cache miss - if ( !this ) + if ( !self ) { - this = calloc( 1, sizeof( struct producer_avformat_s ) ); - producer->child = this; - this->parent = producer; - mlt_service_cache_put( service, "producer_avformat", this, 0, (mlt_destructor) producer_avformat_close ); + self = calloc( 1, sizeof( struct producer_avformat_s ) ); + producer->child = self; + self->parent = producer; + mlt_service_cache_put( service, "producer_avformat", self, 0, (mlt_destructor) producer_avformat_close ); cache_item = mlt_service_cache_get( service, "producer_avformat" ); } @@ -2216,10 +2376,10 @@ mlt_properties_set_position( MLT_FRAME_PROPERTIES( *frame ), "avformat_position", mlt_producer_frame( producer ) ); // Set up the video - producer_set_up_video( this, *frame ); + producer_set_up_video( self, *frame ); // Set up the audio - producer_set_up_audio( this, *frame ); + producer_set_up_audio( self, *frame ); // Calculate the next timecode mlt_producer_prepare_next( producer ); @@ -2227,37 +2387,39 @@ return 0; } -static void producer_avformat_close( producer_avformat this ) +static void producer_avformat_close( producer_avformat self ) { mlt_log_debug( NULL, "producer_avformat_close\n" ); // Close the file - av_free( this->av_frame ); + av_free( self->av_frame ); avformat_lock(); int i; for ( i = 0; i < MAX_AUDIO_STREAMS; i++ ) { - if ( this->audio_resample[i] ) - audio_resample_close( this->audio_resample[i] ); - mlt_pool_release( this->audio_buffer[i] ); - av_free( this->decode_buffer[i] ); - if ( this->audio_codec[i] ) - avcodec_close( this->audio_codec[i] ); - } - if ( this->video_codec ) - avcodec_close( this->video_codec ); - if ( this->dummy_context ) - av_close_input_file( this->dummy_context ); - if ( this->audio_format ) - av_close_input_file( this->audio_format ); - if ( this->video_format ) - av_close_input_file( this->video_format ); + if ( self->audio_resample[i] ) + audio_resample_close( self->audio_resample[i] ); + mlt_pool_release( self->audio_buffer[i] ); + av_free( self->decode_buffer[i] ); + if ( self->audio_codec[i] ) + avcodec_close( self->audio_codec[i] ); + } + if ( self->video_codec ) + avcodec_close( self->video_codec ); + if ( self->dummy_context ) + av_close_input_file( self->dummy_context ); + if ( self->audio_format ) + av_close_input_file( self->audio_format ); + if ( self->video_format ) + av_close_input_file( self->video_format ); avformat_unlock(); #ifdef VDPAU - vdpau_producer_close( this ); + vdpau_producer_close( self ); #endif - if ( this->image_cache ) - mlt_cache_close( this->image_cache ); - free( this ); + if ( self->image_cache ) + mlt_cache_close( self->image_cache ); + pthread_mutex_destroy( &self->audio_mutex ); + pthread_mutex_destroy( &self->video_mutex ); + free( self ); } static void producer_close( mlt_producer parent ) diff -Nru mlt-0.6.2/src/modules/avformat/producer_avformat.yml mlt-0.7.2/src/modules/avformat/producer_avformat.yml --- mlt-0.6.2/src/modules/avformat/producer_avformat.yml 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/avformat/producer_avformat.yml 2011-05-02 05:59:12.000000000 +0000 @@ -1,9 +1,9 @@ schema_version: 0.1 -type: producer # consumer, filter, producer, or transition +type: producer identifier: avformat title: FFmpeg Reader -version: 0.2.5 -copyright: Copyright (C) 2003-2008 Ushodaya Enterprises Limited +version: 1 +copyright: Copyright (C) 2003-2011 Ushodaya Enterprises Limited license: LGPL language: en url: http://www.ffmpeg.org/ @@ -11,52 +11,21 @@ contributor: - Dan Dennedy tags: - - Audio # this may produce audio - - Video # this may produce video + - Audio + - Video description: Read an audio and/or video file using FFmpeg -icon: - filename: avformat/producer.png # relative to $MLT_DATA/modules/ - content-type: image/png - content-encoding: base64 # could also be hex or none if inline SVG - content: | - iVBORw0KGgoAAAANSUhEUgAAABgAAAAPCAYAAAD+pA/bAAAABmJLR0QA/wD/AP+gvaeTAAAACXBI - WXMAAAsSAAALEgHS3X78AAAAB3RJTUUH1gsBEgMLZIL+swAAAB10RVh0Q29tbWVudABDcmVhdGVk - IHdpdGggVGhlIEdJTVDvZCVuAAAEgUlEQVQ4y2VUSWwbZRT+5p/xP4v3eIntceLEThOylKgkB070 - UAUOCNFDFYkIVeqBijMHQKiCAwLEDbVIPVQCUalFQggph6pUoWKRWoS6RCGJ04biOG7sOI638TJe - xjM/FwwRfKf3vve99+kd3uNubNxgVb0Km2W7Tbt06fQLpwv4G8u3k6/88nvJcXYhnJ+dGfsRR/Dl - 8tqpfKkZJ736d++cf6nU53Nra0utTOarVrMpdCj9XFhJr2C1sQq1pZ6ac8zNAljpi7ezzc+e5Lvx - je29H8rlyk8DA14GAOl05tT1n6tf39uqBM69GFgAsNjvaezsvKVfuyZkKxXIi4tvknn/PCQi4cA4 - QMQf+aIv3Nvbm0sVTGe9zfDg8eGxUrk83689eFQcyhStQLluYG+/NNfny6VSsLW5Ge3pOjSHAy2e - /4TwjP84KAfBKRzW99f59G7aAQCVav20SZQAtdlQbfGxteTuNACkd/dsguR8W9NNiKKEVFbjisUi - BQAtnz8rFAq+LgAWDjN/IpEkk97JzYQjAdkhI2fkwtVG9X0AWN+pwTA5iJSH1qEoaMZC8tFjfv3J - IckcdiYNk0GUZVRbXKipt5YAoP7wYZDXNKHOGKR4fCs+NbVGBpwDt3zw3VEUBbqo437qvjuXy7kr - HbtqWQzUJgC8Ar2Dpe1UXpgZC763W+RAOAaR2tAxRTmV3kvsJJPjSrf7umEYqAoC1NnZVCAY3CLD - 6nBpfnC+4hJc4B08DGqc1xr1l5126RzAIHAWqCjjj1wb8eHQq9uZ6nS9a4PAmaACD8bLWN16itrG - hoJ8Ptw2TVjRKAZjsWUAIABACHk3RmOQ7BIyegbpg/1oqWGBoAc0U5BFAt20o1CqXSk26YLZM8Aa - u5AEAwKV4XQNLHpGRq5zpRJ0QuCdmUGpUPgGAAQAoKBPJ5wTyDfzKLMyGMGntRZAmIHxMA/TTnDA - e3FvM+siXhfMdgXjIQbmUpCvMjTa7fFG5imUdhtNSYIcCCxHx8Y6/2zgUTwNq2Nd8FIvYAHFch1d - RmHjuhhVfdnjI1LPYVeQaw3gsMZAmYYTk+oT1SdBkiSU6z3U6k30AHR9PrhU9WYoHP7XYHR41Jpw - TxSDQhAuzgXLtIMQG0RioFwuX3IrwiWPnUByDsKyGPxKB5S3Phj0UkgiRdMQ0FYcqBECFgj8GY7F - 7vZvg/QDl+S66mg5fg2IATDBC45jkPgOJhODLa8dN4d8BJQKYN06RgfF/eNTibRpWVcdsg2MV1An - FJrbDfXEiWxEVdf/ZxCPxVvTnmkjqgzB4p0gMGGnPUyMjUANupNusXNHpDxYt4wR1XtrKBq9a3W0 - B047hSg7ofUIxMlJePz+K0d/FjmahLyh146rzyUNw0Jby8LGWvckSbwcjUayx1RpzWZWELR3jZln - Eh8CwDFVgcLr4HpNVDtMi588ecEbCHx7dKZwNBkODed+W318Zipk3Rx1iTG9GbwYiUQMAAj53Zef - H2u/Ua16L4ZCgykA8A94vn/W1DdH3dK0wIdXwkNDH+E/+Avfv/E5LPIz8wAAAABJRU5ErkJggg== - -notes: Implementation or additional usage notes go here. -bugs: # this can be just for documentation, or the tool may disclose it to help user avoid pitfalls +bugs: - Audio sync discrepancy with some content. - Not all libavformat supported formats are seekable. - > Seeking is not always accurate. Sometimes it doesn't seek to I-frames so you may get junk for a few frames. - > - Fails to play beyond first frame of video of sources with PTS not starting - at 0 (video4linux). + More than 2 channels of audio more than 16 bits is not supported. parameters: - identifier: argument # 'argument' is a reserved name for a value supplied to the factory - title: File # the title can be used as a label for the widget + title: File/URI type: string description: | A file name specification or URL in the form: @@ -73,19 +42,21 @@ widget: fileopen # could provide a button to use a file-open dialog - identifier: audio_index # the name is the mlt_properties name - title: Audio Index + title: Audio index type: integer - # the description can be used in a tool tip - description: Choose the index of audio stream to use (-1 is off) + description: > + Choose the index of audio stream to use (-1 is off). + When this value is equal to the maximum size of a 32-bit signed integer + or the string "all" then all audio tracks are coalesced into a bundle of + channels on one audio track. readonly: no mutable: no minimum: -1 - # when maximum not specified, the scalar limit is used default: 0 widget: spinner - identifier: video_index - title: Video Index + title: Video index type: integer description: Choose the index of video stream to use (-1 is off) readonly: no @@ -95,8 +66,8 @@ widget: spinner - identifier: in - title: In Point - type: time # time is not implemented, but it will correspond to the mlt_position replacement + title: In point + type: time description: Set the start time offset to use within the clip readonly: no mutable: no @@ -105,7 +76,7 @@ widget: timecode # this is a special form of time value/code entry (e.g. see Kino) - identifier: out - title: Out Point + title: Out point type: time description: Set the ending time offset to use within the clip readonly: no @@ -114,7 +85,7 @@ widget: timecode # as opposed to time, which could be confused for a wallclock-style time widget - identifier: threads - title: Decoding Threads + title: Decoding threads type: integer description: Choose the number of threads to use in the decoder(s) readonly: no @@ -126,7 +97,7 @@ unit: threads # the unit is a label that appears after the widget - identifier: force_aspect_ratio - title: Sample Aspect Ratio + title: Sample aspect ratio type: float description: Optionally override a (mis)detected aspect ratio readonly: no @@ -136,13 +107,13 @@ # no default property means it should be blank in the UI and not applied unless provided - identifier: resource - title: File + title: File/URI type: string description: file or protocol specification readonly: yes - identifier: source_fps - title: Frame Rate + title: Frame rate type: float scale: 2 # scale is the number of digits to display after the decimal point description: the framerate of the resource @@ -150,8 +121,7 @@ unit: frames/second - identifier: aspect_ratio - title: Sample Aspect Ratio - type: float + title: Sample aspect ratio description: > The sample aspect ratio of the resource. This is determined on every frame read. @@ -161,11 +131,77 @@ title: Duration type: time description: duration - readonly: yes widget: timecode - identifier: seekable - title: Supports Seek - type: integer + title: Supports seeking description: if the resource can seek readonly: yes + + - identifier: adjust_length + title: Adjust length + type: time + description: Adjust the detected length. + + - identifier: width + title: Width + type: integer + unit: pixels + readonly: yes + + - identifier: height + title: Height + type: integer + unit: pixels + readonly: yes + + - identifier: noimagecache + title: Disable image caching + type: integer + minimum: 0 + maximum: 0 + default: 0 + widget: checkbox + + - identifier: new_seek + title: Use new seeking + description: > + When this is not provided (recommended), it is enabled only for H.264 in + MPEG-2 Transport Streams. + type: integer + minimum: 0 + maximum: 1 + widget: checkbox + + - identifier: force_progressive + title: Force progressive + description: When provided, this overrides the detection of progressive video. + type: integer + minimum: 0 + maximum: 1 + widget: checkbox + + - identifier: force_tff + title: Force top field first + description: When provided, this overrides the detected field order of interlaced video. + type: integer + minimum: 0 + maximum: 1 + widget: checkbox + + - identifier: force_fps + title: Force frame rate + description: When provided, this attempts to override the detected frame rate of the video. + type: integer + minimum: 0 + maximum: 1 + widget: checkbox + + - identifer: force_colorspace + title: Force colorspace + description: When provided, this overrides the detected colorspace of the video (Y'CbCr only). + type: integer + values: + - 240 # SMPTE 240M + - 601 # ITU-R BT.601 + - 709 # ITU-R BT.709 diff -Nru mlt-0.6.2/src/modules/avformat/vdpau.c mlt-0.7.2/src/modules/avformat/vdpau.c --- mlt-0.6.2/src/modules/avformat/vdpau.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/avformat/vdpau.c 2011-05-02 05:59:12.000000000 +0000 @@ -47,11 +47,11 @@ static void vdpau_decoder_close(); -static int vdpau_init( producer_avformat this ) +static int vdpau_init( producer_avformat self ) { - mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "vdpau_init\n" ); + mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "vdpau_init\n" ); int success = 0; - mlt_properties properties = MLT_PRODUCER_PROPERTIES( this->parent ); + mlt_properties properties = MLT_PRODUCER_PROPERTIES( self->parent ); Display *display = XOpenDisplay( NULL ); if ( !display || mlt_properties_get_int( properties, "novdpau" ) @@ -73,7 +73,7 @@ int screen = mlt_properties_get_int( properties, "x11_screen" ); VdpDevice device; - mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "X11 Display = %p\n", display ); + mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "X11 Display = %p\n", display ); if ( VDP_STATUS_OK == create_device( display, screen, &device, &vdp_get_proc_address ) ) { // Allocate the global VDPAU context @@ -82,7 +82,7 @@ { g_vdpau->device = device; g_vdpau->decoder = VDP_INVALID_HANDLE; - g_vdpau->producer = this; + g_vdpau->producer = self; vdp_get_proc_address( g_vdpau->device, VDP_FUNC_ID_GET_ERROR_STRING, (void**) &vdp_get_error_string ); vdp_get_proc_address( g_vdpau->device, VDP_FUNC_ID_GET_API_VERSION, (void**) &vdp_get_api_version ); vdp_get_proc_address( g_vdpau->device, VDP_FUNC_ID_GET_INFORMATION_STRING, (void**) &vdp_get_information_string ); @@ -98,22 +98,22 @@ } if ( !success ) { - mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "VDPAU failed to initialize device\n" ); + mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "VDPAU failed to initialize device\n" ); dlclose( object ); } } else { - mlt_log( MLT_PRODUCER_SERVICE(this->parent), MLT_LOG_WARNING, "%s: failed to dlopen libvdpau.so\n (%s)\n", __FUNCTION__, dlerror() ); + mlt_log( MLT_PRODUCER_SERVICE(self->parent), MLT_LOG_WARNING, "%s: failed to dlopen libvdpau.so\n (%s)\n", __FUNCTION__, dlerror() ); } } else { success = 1; - mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "VDPAU already initialized\n" ); + mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "VDPAU already initialized\n" ); } - if ( g_vdpau && g_vdpau->producer != this ) + if ( g_vdpau && g_vdpau->producer != self ) vdpau_decoder_close(); return success; @@ -127,12 +127,12 @@ static int vdpau_get_buffer( AVCodecContext *codec_context, AVFrame *frame ) { int error = 0; - producer_avformat this = codec_context->opaque; - mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "vdpau_get_buffer\n" ); + producer_avformat self = codec_context->opaque; + mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "vdpau_get_buffer\n" ); - if ( g_vdpau->producer == this && mlt_deque_count( this->vdpau->deque ) ) + if ( g_vdpau->producer == self && self->vdpau && mlt_deque_count( self->vdpau->deque ) ) { - struct vdpau_render_state *render = mlt_deque_pop_front( this->vdpau->deque ); + struct vdpau_render_state *render = mlt_deque_pop_front( self->vdpau->deque ); if ( render ) { @@ -147,28 +147,28 @@ frame->reordered_opaque = codec_context->reordered_opaque; if ( frame->reference ) { - frame->age = this->vdpau->ip_age[0]; - this->vdpau->ip_age[0] = this->vdpau->ip_age[1] + 1; - this->vdpau->ip_age[1] = 1; - this->vdpau->b_age++; + frame->age = self->vdpau->ip_age[0]; + self->vdpau->ip_age[0] = self->vdpau->ip_age[1] + 1; + self->vdpau->ip_age[1] = 1; + self->vdpau->b_age++; } else { - frame->age = this->vdpau->b_age; - this->vdpau->ip_age[0] ++; - this->vdpau->ip_age[1] ++; - this->vdpau->b_age = 1; + frame->age = self->vdpau->b_age; + self->vdpau->ip_age[0] ++; + self->vdpau->ip_age[1] ++; + self->vdpau->b_age = 1; } } else { - mlt_log_warning( MLT_PRODUCER_SERVICE(this->parent), "VDPAU surface underrun\n" ); + mlt_log_warning( MLT_PRODUCER_SERVICE(self->parent), "VDPAU surface underrun\n" ); error = -1; } } else { - mlt_log_warning( MLT_PRODUCER_SERVICE(this->parent), "VDPAU surface underrun\n" ); + mlt_log_warning( MLT_PRODUCER_SERVICE(self->parent), "VDPAU surface underrun\n" ); error = -1; } @@ -177,125 +177,132 @@ static void vdpau_release_buffer( AVCodecContext *codec_context, AVFrame *frame ) { - producer_avformat this = codec_context->opaque; - struct vdpau_render_state *render = (struct vdpau_render_state*) frame->data[0]; - mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "vdpau_release_buffer (%x)\n", render->surface ); - int i; - - render->state &= ~FF_VDPAU_STATE_USED_FOR_REFERENCE; - for ( i = 0; i < 4; i++ ) - frame->data[i] = NULL; - mlt_deque_push_back( this->vdpau->deque, render ); + producer_avformat self = codec_context->opaque; + if ( self->vdpau ) + { + struct vdpau_render_state *render = (struct vdpau_render_state*) frame->data[0]; + mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "vdpau_release_buffer (%x)\n", render->surface ); + int i; + + render->state &= ~FF_VDPAU_STATE_USED_FOR_REFERENCE; + for ( i = 0; i < 4; i++ ) + frame->data[i] = NULL; + mlt_deque_push_back( self->vdpau->deque, render ); + } } static void vdpau_draw_horiz( AVCodecContext *codec_context, const AVFrame *frame, int offset[4], int y, int type, int height ) { - producer_avformat this = codec_context->opaque; - struct vdpau_render_state *render = (struct vdpau_render_state*) frame->data[0]; - VdpVideoSurface surface = render->surface; - VdpStatus status = vdp_decoder_render( g_vdpau->decoder, surface, (void*) &render->info, - render->bitstream_buffers_used, render->bitstream_buffers ); - - if ( status != VDP_STATUS_OK ) + producer_avformat self = codec_context->opaque; + if ( self->vdpau ) { - this->vdpau->is_decoded = 0; - mlt_log_warning( MLT_PRODUCER_SERVICE(this->parent), "VDPAU failed to decode (%s)\n", - vdp_get_error_string( status ) ); - } - else - { - this->vdpau->is_decoded = 1; + struct vdpau_render_state *render = (struct vdpau_render_state*) frame->data[0]; + VdpVideoSurface surface = render->surface; + VdpStatus status = vdp_decoder_render( g_vdpau->decoder, surface, (void*) &render->info, + render->bitstream_buffers_used, render->bitstream_buffers ); + + if ( status != VDP_STATUS_OK ) + { + self->vdpau->is_decoded = 0; + mlt_log_warning( MLT_PRODUCER_SERVICE(self->parent), "VDPAU failed to decode (%s)\n", + vdp_get_error_string( status ) ); + } + else + { + self->vdpau->is_decoded = 1; + } } } -static int vdpau_decoder_init( producer_avformat this ) +static int vdpau_decoder_init( producer_avformat self ) { - mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "vdpau_decoder_init\n" ); + mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "vdpau_decoder_init\n" ); int success = 1; - this->video_codec->opaque = this; - this->video_codec->get_format = vdpau_get_format; - this->video_codec->get_buffer = vdpau_get_buffer; - this->video_codec->release_buffer = vdpau_release_buffer; - this->video_codec->draw_horiz_band = vdpau_draw_horiz; - this->video_codec->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD; - this->video_codec->pix_fmt = PIX_FMT_VDPAU_H264; + self->video_codec->opaque = self; + self->video_codec->get_format = vdpau_get_format; + self->video_codec->get_buffer = vdpau_get_buffer; + self->video_codec->release_buffer = vdpau_release_buffer; + self->video_codec->draw_horiz_band = vdpau_draw_horiz; + self->video_codec->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD; + self->video_codec->pix_fmt = PIX_FMT_VDPAU_H264; VdpDecoderProfile profile = VDP_DECODER_PROFILE_H264_HIGH; - uint32_t max_references = this->video_codec->refs; + uint32_t max_references = self->video_codec->refs; pthread_mutex_lock( &mlt_sdl_mutex ); VdpStatus status = vdp_decoder_create( g_vdpau->device, - profile, this->video_codec->width, this->video_codec->height, max_references, &g_vdpau->decoder ); + profile, self->video_codec->width, self->video_codec->height, max_references, &g_vdpau->decoder ); pthread_mutex_unlock( &mlt_sdl_mutex ); if ( status == VDP_STATUS_OK ) { - if ( !this->vdpau ) + if ( !self->vdpau ) { - int i, n = FFMIN( this->video_codec->refs + 2, MAX_VDPAU_SURFACES ); + int i, n = FFMIN( self->video_codec->refs + 2, MAX_VDPAU_SURFACES ); - this->vdpau = calloc( 1, sizeof( *this->vdpau ) ); - this->vdpau->deque = mlt_deque_init(); + self->vdpau = calloc( 1, sizeof( *self->vdpau ) ); + self->vdpau->deque = mlt_deque_init(); for ( i = 0; i < n; i++ ) { if ( VDP_STATUS_OK == vdp_surface_create( g_vdpau->device, VDP_CHROMA_TYPE_420, - this->video_codec->width, this->video_codec->height, &this->vdpau->render_states[i].surface ) ) + self->video_codec->width, self->video_codec->height, &self->vdpau->render_states[i].surface ) ) { - mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "successfully created VDPAU surface %x\n", - this->vdpau->render_states[i].surface ); - mlt_deque_push_back( this->vdpau->deque, &this->vdpau->render_states[i] ); + mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "successfully created VDPAU surface %x\n", + self->vdpau->render_states[i].surface ); + mlt_deque_push_back( self->vdpau->deque, &self->vdpau->render_states[i] ); } else { - mlt_log_info( MLT_PRODUCER_SERVICE(this->parent), "failed to create VDPAU surface %dx%d\n", - this->video_codec->width, this->video_codec->height ); - while ( mlt_deque_count( this->vdpau->deque ) ) + mlt_log_info( MLT_PRODUCER_SERVICE(self->parent), "failed to create VDPAU surface %dx%d\n", + self->video_codec->width, self->video_codec->height ); + while ( mlt_deque_count( self->vdpau->deque ) ) { - struct vdpau_render_state *render = mlt_deque_pop_front( this->vdpau->deque ); + struct vdpau_render_state *render = mlt_deque_pop_front( self->vdpau->deque ); vdp_surface_destroy( render->surface ); } - mlt_deque_close( this->vdpau->deque ); - free( this->vdpau ); - this->vdpau = NULL; + mlt_deque_close( self->vdpau->deque ); + free( self->vdpau ); + self->vdpau = NULL; vdp_decoder_destroy( g_vdpau->decoder ); g_vdpau->decoder = VDP_INVALID_HANDLE; success = 0; break; } } - this->vdpau->b_age = this->vdpau->ip_age[0] = this->vdpau->ip_age[1] = 256*256*256*64; // magic from Avidemux + if ( self->vdpau ) + self->vdpau->b_age = self->vdpau->ip_age[0] = self->vdpau->ip_age[1] = 256*256*256*64; // magic from Avidemux } - g_vdpau->producer = this; + g_vdpau->producer = self; } else { success = 0; g_vdpau->decoder = VDP_INVALID_HANDLE; - mlt_log_error( MLT_PRODUCER_SERVICE(this->parent), "VDPAU failed to initialize decoder (%s)\n", + mlt_log_error( MLT_PRODUCER_SERVICE(self->parent), "VDPAU failed to initialize decoder (%s)\n", vdp_get_error_string( status ) ); } return success; } -static void vdpau_producer_close( producer_avformat this ) +static void vdpau_producer_close( producer_avformat self ) { - if ( this->vdpau ) + if ( self->vdpau ) { - mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "vdpau_producer_close\n" ); + mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "vdpau_producer_close\n" ); int i; for ( i = 0; i < MAX_VDPAU_SURFACES; i++ ) { - if ( this->vdpau->render_states[i].surface != VDP_INVALID_HANDLE ) - vdp_surface_destroy( this->vdpau->render_states[i].surface ); - this->vdpau->render_states[i].surface = VDP_INVALID_HANDLE; + if ( self->vdpau->render_states[i].surface != VDP_INVALID_HANDLE ) + vdp_surface_destroy( self->vdpau->render_states[i].surface ); + self->vdpau->render_states[i].surface = VDP_INVALID_HANDLE; } - mlt_deque_close( this->vdpau->deque ); - if ( this->vdpau->buffer ) - mlt_pool_release( this->vdpau->buffer ); - this->vdpau->buffer = NULL; - free( this->vdpau ); - this->vdpau = NULL; + mlt_deque_close( self->vdpau->deque ); + if ( self->vdpau->buffer ) + mlt_pool_release( self->vdpau->buffer ); + self->vdpau->buffer = NULL; + free( self->vdpau ); + self->vdpau = NULL; } } diff -Nru mlt-0.6.2/src/modules/configure mlt-0.7.2/src/modules/configure --- mlt-0.6.2/src/modules/configure 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/configure 2011-05-02 05:59:12.000000000 +0000 @@ -19,7 +19,7 @@ do if [ -d $i -a \( "$help" = "1" -o ! -f disable-$i \) ] then - if [ "$gpl" = "true" -o ! -f $i/gpl ] + if [ "$gpl" = "true" -o ! -f $i/gpl -o "$help" = "1" ] then [ -f $i/Makefile -a "$help" = "0" ] && echo "Configuring modules/$i:" if [ -x $i/configure ] diff -Nru mlt-0.6.2/src/modules/core/filter_audioconvert.c mlt-0.7.2/src/modules/core/filter_audioconvert.c --- mlt-0.6.2/src/modules/core/filter_audioconvert.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/core/filter_audioconvert.c 2011-05-02 05:59:12.000000000 +0000 @@ -27,11 +27,11 @@ static int convert_audio( mlt_frame frame, void **audio, mlt_audio_format *format, mlt_audio_format requested_format ) { - int error = 0; + int error = 1; mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); int channels = mlt_properties_get_int( properties, "audio_channels" ); int samples = mlt_properties_get_int( properties, "audio_samples" ); - int size = 0; + int size = mlt_audio_format_size( requested_format, samples, channels ); if ( *format != requested_format ) { @@ -45,7 +45,6 @@ { case mlt_audio_s32: { - size = channels * samples * sizeof(int32_t); int32_t *buffer = mlt_pool_alloc( size ); int32_t *p = buffer; int c; @@ -60,11 +59,11 @@ } } *audio = buffer; + error = 0; break; } case mlt_audio_float: { - size = channels * samples * sizeof(float); float *buffer = mlt_pool_alloc( size ); float *p = buffer; int c; @@ -79,10 +78,11 @@ } } *audio = buffer; + error = 0; break; } default: - error = 1; + break; } break; case mlt_audio_s32: @@ -90,7 +90,6 @@ { case mlt_audio_s16: { - size = channels * samples * sizeof(int16_t); int16_t *buffer = mlt_pool_alloc( size ); int16_t *p = buffer; int32_t *q = (int32_t*) *audio; @@ -99,11 +98,11 @@ for ( c = 0; c < channels; c++ ) *p++ = *( q + c * samples + s ) >> 16; *audio = buffer; + error = 0; break; } case mlt_audio_float: { - size = channels * samples * sizeof(float); float *buffer = mlt_pool_alloc( size ); float *p = buffer; int32_t *q = (int32_t*) *audio; @@ -111,10 +110,11 @@ while ( --i ) *p++ = (float)( *q++ ) / 2147483648.0; *audio = buffer; + error = 0; break; } default: - error = 1; + break; } break; case mlt_audio_float: @@ -122,7 +122,6 @@ { case mlt_audio_s16: { - size = channels * samples * sizeof(int16_t); int16_t *buffer = mlt_pool_alloc( size ); int16_t *p = buffer; float *q = (float*) *audio; @@ -135,11 +134,11 @@ *p++ = 32767 * f; } *audio = buffer; + error = 0; break; } case mlt_audio_s32: { - size = channels * samples * sizeof(int32_t); int32_t *buffer = mlt_pool_alloc( size ); int32_t *p = buffer; float *q = (float*) *audio; @@ -151,17 +150,18 @@ *p++ = ( f > 0 ? 2147483647LL : 2147483648LL ) * f; } *audio = buffer; + error = 0; break; } default: - error = 1; + break; } break; default: - error = 1; + break; } } - if ( size ) + if ( !error ) { mlt_frame_set_audio( frame, *audio, requested_format, size, mlt_pool_release ); *format = requested_format; diff -Nru mlt-0.6.2/src/modules/core/filter_audiowave.c mlt-0.7.2/src/modules/core/filter_audiowave.c --- mlt-0.6.2/src/modules/core/filter_audiowave.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/core/filter_audiowave.c 2011-05-02 05:59:12.000000000 +0000 @@ -32,7 +32,7 @@ int size = *width * *height * 2; *format = mlt_image_yuv422; *image = mlt_pool_alloc( size ); - mlt_properties_set_data( MLT_FRAME_PROPERTIES(this), "image", *image, size, mlt_pool_release, NULL ); + mlt_frame_set_image( this, *image, size, mlt_pool_release ); uint8_t *wave = mlt_frame_get_waveform( this, *width, *height ); if ( wave ) { diff -Nru mlt-0.6.2/src/modules/core/filter_brightness.c mlt-0.7.2/src/modules/core/filter_brightness.c --- mlt-0.6.2/src/modules/core/filter_brightness.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/core/filter_brightness.c 2011-05-02 05:59:12.000000000 +0000 @@ -74,12 +74,8 @@ if ( mlt_properties_get( MLT_FILTER_PROPERTIES( this ), "end" ) != NULL ) { // Determine the time position of this frame in the transition duration - mlt_position in = mlt_filter_get_in( this ); - mlt_position out = mlt_filter_get_out( this ); - mlt_position time = mlt_frame_get_position( frame ); - double position = ( double )( time - in ) / ( double )( out - in + 1 ); double end = fabs( mlt_properties_get_double( MLT_FILTER_PROPERTIES( this ), "end" ) ); - level += ( end - level ) * position; + level += ( end - level ) * mlt_filter_get_progress( this, frame ); } // Push the frame filter diff -Nru mlt-0.6.2/src/modules/core/filter_crop.c mlt-0.7.2/src/modules/core/filter_crop.c --- mlt-0.6.2/src/modules/core/filter_crop.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/core/filter_crop.c 2011-05-02 05:59:12.000000000 +0000 @@ -94,22 +94,6 @@ mlt_log_debug( NULL, "[filter crop] %s %dx%d -> %dx%d\n", mlt_image_format_name(*format), *width, *height, owidth, oheight); - switch ( *format ) - { - case mlt_image_yuv422: - bpp = 2; - break; - case mlt_image_rgb24: - bpp = 3; - break; - case mlt_image_rgb24a: - case mlt_image_opengl: - bpp = 4; - break; - default: - // XXX: we only know how to crop packed formats - return 1; - } // Provides a manual override for misreported field order if ( mlt_properties_get( properties, "meta.top_field_first" ) ) @@ -122,17 +106,16 @@ mlt_properties_set_int( properties, "top_field_first", !mlt_properties_get_int( properties, "top_field_first" ) ); // Create the output image - uint8_t *output = mlt_pool_alloc( owidth * ( oheight + 1 ) * bpp ); + int size = mlt_image_format_size( *format, owidth, oheight, &bpp ); + uint8_t *output = mlt_pool_alloc( size ); if ( output ) { // Call the generic resize crop( *image, output, bpp, *width, *height, left, right, top, bottom ); // Now update the frame + mlt_frame_set_image( this, output, size, mlt_pool_release ); *image = output; - mlt_properties_set_data( properties, "image", output, owidth * ( oheight + 1 ) * bpp, ( mlt_destructor )mlt_pool_release, NULL ); - mlt_properties_set_int( properties, "width", owidth ); - mlt_properties_set_int( properties, "height", oheight ); } // We should resize the alpha too @@ -145,7 +128,7 @@ if ( newalpha ) { crop( alpha, newalpha, 1, *width, *height, left, right, top, bottom ); - mlt_properties_set_data( properties, "alpha", newalpha, owidth * oheight, ( mlt_destructor )mlt_pool_release, NULL ); + mlt_frame_set_alpha( this, newalpha, owidth * oheight, mlt_pool_release ); this->get_alpha_mask = NULL; } } @@ -176,7 +159,16 @@ int bottom = mlt_properties_get_int( filter_props, "bottom" ); int width = mlt_properties_get_int( frame_props, "real_width" ); int height = mlt_properties_get_int( frame_props, "real_height" ); + int use_profile = mlt_properties_get_int( filter_props, "use_profile" ); + mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( this ) ); + if ( use_profile ) + { + top = top * height / profile->height; + bottom = bottom * height / profile->height; + left = left * width / profile->width; + right = right * width / profile->width; + } if ( mlt_properties_get_int( filter_props, "center" ) ) { double aspect_ratio = mlt_frame_get_aspect_ratio( frame ); @@ -191,6 +183,8 @@ left = right = ( width - rint( output_ar * height / aspect_ratio ) ) / 2; if ( abs(bias) > left ) bias = bias < 0 ? -left : left; + else if ( use_profile ) + bias = bias * width / profile->width; left -= bias; right += bias; } @@ -199,6 +193,8 @@ top = bottom = ( height - rint( aspect_ratio * width / output_ar ) ) / 2; if ( abs(bias) > top ) bias = bias < 0 ? -top : top; + else if ( use_profile ) + bias = bias * height / profile->height; top -= bias; bottom += bias; } diff -Nru mlt-0.6.2/src/modules/core/filter_data_show.c mlt-0.7.2/src/modules/core/filter_data_show.c --- mlt-0.6.2/src/modules/core/filter_data_show.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/core/filter_data_show.c 2011-05-02 05:59:12.000000000 +0000 @@ -300,12 +300,16 @@ // Get the frame properties mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); + mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); + // Track specific process_queue( mlt_properties_get_data( frame_properties, "data_queue", NULL ), frame, filter ); // Global process_queue( mlt_properties_get_data( frame_properties, "global_queue", NULL ), frame, filter ); + mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); + // Need to get the image return mlt_frame_get_image( frame, image, format, width, height, 1 ); } diff -Nru mlt-0.6.2/src/modules/core/filter_imageconvert.c mlt-0.7.2/src/modules/core/filter_imageconvert.c --- mlt-0.6.2/src/modules/core/filter_imageconvert.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/core/filter_imageconvert.c 2011-05-02 05:59:12.000000000 +0000 @@ -343,9 +343,9 @@ if ( !( error = converter( *buffer, image, alpha, width, height ) ) ) { - mlt_properties_set_data( properties, "image", image, size, mlt_pool_release, NULL ); + mlt_frame_set_image( frame, image, size, mlt_pool_release ); if ( alpha && ( *format == mlt_image_rgb24a || *format == mlt_image_opengl ) ) - mlt_properties_set_data( properties, "alpha", alpha, alpha_size, mlt_pool_release, NULL ); + mlt_frame_set_alpha( frame, alpha, alpha_size, mlt_pool_release ); *buffer = image; *format = requested_format; } @@ -361,8 +361,6 @@ error = 1; } } - if ( !error ) - mlt_properties_set_int( properties, "format", *format ); return error; } diff -Nru mlt-0.6.2/src/modules/core/filter_luma.c mlt-0.7.2/src/modules/core/filter_luma.c --- mlt-0.6.2/src/modules/core/filter_luma.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/core/filter_luma.c 2011-05-02 05:59:12.000000000 +0000 @@ -37,14 +37,16 @@ int error = 0; mlt_filter filter = mlt_frame_pop_service( this ); mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); + + mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); + mlt_transition luma = mlt_properties_get_data( properties, "luma", NULL ); mlt_frame b_frame = mlt_properties_get_data( properties, "frame", NULL ); mlt_properties b_frame_props = b_frame ? MLT_FRAME_PROPERTIES( b_frame ) : NULL; int out = mlt_properties_get_int( properties, "period" ); int cycle = mlt_properties_get_int( properties, "cycle" ); int duration = mlt_properties_get_int( properties, "duration" ); - char *name = mlt_properties_get( properties, "_unique_id" ); - mlt_position position = mlt_properties_get_position( MLT_FRAME_PROPERTIES(this), name ); + mlt_position position = mlt_filter_get_position( filter, this ); out = out? out + 1 : 25; if ( cycle ) @@ -104,13 +106,15 @@ mlt_log_debug( MLT_FILTER_SERVICE(filter), "copying frame %d\n", modulo_pos ); mlt_properties b_props = MLT_FRAME_PROPERTIES( b_frame ); memcpy( dst, src, size ); - mlt_properties_set_data( b_props, "image", dst, size, mlt_pool_release, NULL ); + mlt_frame_set_image( b_frame, dst, size, mlt_pool_release ); mlt_properties_set_int( b_props, "width", *width ); mlt_properties_set_int( b_props, "height", *height ); mlt_properties_set_int( b_props, "format", *format ); } } + mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); + return error; } @@ -119,12 +123,6 @@ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { - // Get a unique name to store the frame position - char *name = mlt_properties_get( MLT_FILTER_PROPERTIES( this ), "_unique_id" ); - - // Assign the current position to the name - mlt_properties_set_position( MLT_FRAME_PROPERTIES( frame ), name, mlt_frame_get_position( frame ) ); - // Push the filter on to the stack mlt_frame_push_service( frame, this ); diff -Nru mlt-0.6.2/src/modules/core/filter_mono.c mlt-0.7.2/src/modules/core/filter_mono.c --- mlt-0.6.2/src/modules/core/filter_mono.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/core/filter_mono.c 2011-05-02 05:59:12.000000000 +0000 @@ -40,13 +40,12 @@ if ( channels_out == -1 ) channels_out = *channels; - size = *samples * channels_out; + size = mlt_audio_format_size( *format, *samples, channels_out ); switch ( *format ) { case mlt_audio_s16: { - size *= sizeof( int16_t ); int16_t *new_buffer = mlt_pool_alloc( size ); for ( i = 0; i < *samples; i++ ) { @@ -61,7 +60,6 @@ } case mlt_audio_s32: { - size *= sizeof( int32_t ); int32_t *new_buffer = mlt_pool_alloc( size ); for ( i = 0; i < *samples; i++ ) { @@ -76,7 +74,6 @@ } case mlt_audio_float: { - size *= sizeof( float ); float *new_buffer = mlt_pool_alloc( size ); for ( i = 0; i < *samples; i++ ) { diff -Nru mlt-0.6.2/src/modules/core/filter_obscure.c mlt-0.7.2/src/modules/core/filter_obscure.c --- mlt-0.6.2/src/modules/core/filter_obscure.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/core/filter_obscure.c 2011-05-02 05:59:12.000000000 +0000 @@ -131,22 +131,6 @@ output->mask_h = lerp( in->mask_h + ( out->mask_h - in->mask_h ) * position, 1, -1 ); } -/** Calculate the position for this frame. -*/ - -static float position_calculate( mlt_filter this, mlt_frame frame ) -{ - // Get the in and out position - mlt_position in = mlt_filter_get_in( this ); - mlt_position out = mlt_filter_get_out( this ); - - // Get the position of the frame - mlt_position position = mlt_frame_get_position( frame ); - - // Now do the calcs - return ( float )( position - in ) / ( float )( out - in + 1 ); -} - /** The averaging function... */ @@ -257,7 +241,7 @@ struct geometry_s end; // Retrieve the position - float position = mlt_properties_get_double(frame_properties, "filter_position"); + float position = mlt_filter_get_progress( this, frame ); // Now parse the geometries geometry_parse( &start, NULL, mlt_properties_get( properties, "start" ), normalised_width, normalised_height ); @@ -282,10 +266,6 @@ // Push this on to the service stack mlt_frame_push_service( frame, this ); - // Calculate the position for the filter effect - float position = position_calculate( this, frame ); - mlt_properties_set_double( MLT_FRAME_PROPERTIES( frame ), "filter_position", position ); - // Push the get image call mlt_frame_push_get_image( frame, filter_get_image ); diff -Nru mlt-0.6.2/src/modules/core/filter_rescale.c mlt-0.7.2/src/modules/core/filter_rescale.c --- mlt-0.6.2/src/modules/core/filter_rescale.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/core/filter_rescale.c 2011-05-02 05:59:12.000000000 +0000 @@ -41,9 +41,6 @@ static int filter_scale( mlt_frame this, uint8_t **image, mlt_image_format *format, int iwidth, int iheight, int owidth, int oheight ) { - // Get the properties - mlt_properties properties = MLT_FRAME_PROPERTIES( this ); - // Create the output image uint8_t *output = mlt_pool_alloc( owidth * ( oheight + 1 ) * 2 ); @@ -106,11 +103,9 @@ } // Now update the frame - mlt_properties_set_data( properties, "image", output, owidth * ( oheight + 1 ) * 2, ( mlt_destructor ) mlt_pool_release, NULL ); - mlt_properties_set_int( properties, "width", owidth ); - mlt_properties_set_int( properties, "height", oheight ); - + mlt_frame_set_image( this, output, owidth * ( oheight + 1 ) * 2, mlt_pool_release ); *image = output; + return 0; } @@ -139,7 +134,7 @@ } // Set it back on the frame - mlt_properties_set_data( MLT_FRAME_PROPERTIES( this ), "alpha", output, owidth * oheight, mlt_pool_release, NULL ); + mlt_frame_set_alpha( this, output, owidth * oheight, mlt_pool_release ); } } @@ -174,8 +169,10 @@ { int iwidth = *width; int iheight = *height; - int owidth = *width; - int oheight = *height; + double factor = mlt_properties_get_double( filter_properties, "factor" ); + factor = factor > 0 ? factor : 1.0; + int owidth = *width * factor; + int oheight = *height * factor; char *interps = mlt_properties_get( properties, "rescale.interp" ); // Default from the scaler if not specifed on the frame diff -Nru mlt-0.6.2/src/modules/core/filter_resize.c mlt-0.7.2/src/modules/core/filter_resize.c --- mlt-0.6.2/src/modules/core/filter_resize.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/core/filter_resize.c 2011-05-02 05:59:12.000000000 +0000 @@ -147,7 +147,7 @@ int iheight = mlt_properties_get_int( properties, "height" ); // If width and height are correct, don't do anything - if ( iwidth != owidth || iheight != oheight ) + if ( iwidth < owidth || iheight < oheight ) { uint8_t alpha_value = mlt_properties_get_int( properties, "resize_alpha" ); @@ -158,9 +158,7 @@ resize_image( output, owidth, oheight, input, iwidth, iheight, bpp ); // Now update the frame - mlt_properties_set_data( properties, "image", output, owidth * ( oheight + 1 ) * bpp, ( mlt_destructor )mlt_pool_release, NULL ); - mlt_properties_set_int( properties, "width", owidth ); - mlt_properties_set_int( properties, "height", oheight ); + mlt_frame_set_image( this, output, owidth * ( oheight + 1 ) * bpp, mlt_pool_release ); // We should resize the alpha too if ( alpha && alpha_size >= iwidth * iheight ) @@ -168,7 +166,7 @@ alpha = resize_alpha( alpha, owidth, oheight, iwidth, iheight, alpha_value ); if ( alpha ) { - mlt_properties_set_data( properties, "alpha", alpha, owidth * oheight, ( mlt_destructor )mlt_pool_release, NULL ); + mlt_frame_set_alpha( this, alpha, owidth * oheight, mlt_pool_release ); this->get_alpha_mask = NULL; } } @@ -271,23 +269,7 @@ // Get the requested scale operation char *op = mlt_properties_get( MLT_FILTER_PROPERTIES( filter ), "scale" ); int bpp; - - switch ( *format ) - { - case mlt_image_yuv422: - bpp = 2; - break; - case mlt_image_rgb24: - bpp = 3; - break; - case mlt_image_rgb24a: - case mlt_image_opengl: - bpp = 4; - break; - default: - // XXX: we only know how to resize packed formats - return 1; - } + int size = mlt_image_format_size( *format, owidth, oheight, &bpp ); // Provides a manual override for misreported field order if ( mlt_properties_get( properties, "meta.top_field_first" ) ) @@ -299,12 +281,11 @@ mlt_properties_get_int( properties, "progressive" ) == 0 ) { // Get the input image, width and height - int size = owidth * oheight * bpp; uint8_t *new_image = mlt_pool_alloc( size ); - mlt_properties_set_data( properties, "image", new_image, size, ( mlt_destructor )mlt_pool_release, NULL ); + mlt_frame_set_image( this, new_image, size, mlt_pool_release ); uint8_t *ptr = new_image + owidth * bpp; memcpy( new_image, *image, owidth * bpp ); - memcpy( ptr, *image, size - owidth * bpp ); + memcpy( ptr, *image, owidth * ( oheight - 1 ) * bpp ); *image = new_image; // Set the normalised field order diff -Nru mlt-0.6.2/src/modules/core/filter_watermark.c mlt-0.7.2/src/modules/core/filter_watermark.c --- mlt-0.6.2/src/modules/core/filter_watermark.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/core/filter_watermark.c 2011-05-02 05:59:12.000000000 +0000 @@ -42,6 +42,8 @@ // Get the properties of the filter mlt_properties properties = MLT_FILTER_PROPERTIES( this ); + mlt_service_lock( MLT_FILTER_SERVICE( this ) ); + // Get the producer from the filter mlt_producer producer = mlt_properties_get_data( properties, "producer", NULL ); @@ -115,6 +117,8 @@ mlt_properties_pass( producer_properties, properties, "producer." ); } + mlt_service_unlock( MLT_FILTER_SERVICE( this ) ); + // Only continue if we have both producer and composite if ( composite != NULL && producer != NULL ) { @@ -124,11 +128,8 @@ // We will get the 'b frame' from the producer mlt_frame b_frame = NULL; - // Get the unique id of the filter (used to reacquire the producer position) - char *name = mlt_properties_get( properties, "_unique_id" ); - // Get the original producer position - mlt_position position = mlt_properties_get_position( MLT_FRAME_PROPERTIES( frame ), name ); + mlt_position position = mlt_filter_get_position( this, frame ); // Make sure the producer is in the correct position mlt_producer_seek( producer, position ); @@ -193,8 +194,8 @@ mlt_service_apply_filters( MLT_FILTER_SERVICE( this ), b_frame, 0 ); error = mlt_frame_get_image( b_frame, image, format, width, height, 1 ); alpha = mlt_frame_get_alpha_mask( b_frame ); - mlt_properties_set_data( a_props, "image", *image, *width * *height * 2, NULL, NULL ); - mlt_properties_set_data( a_props, "alpha", alpha, *width * *height, NULL, NULL ); + mlt_frame_set_image( frame, *image, *width * *height * 2, NULL ); + mlt_frame_set_alpha( frame, alpha, *width * *height, NULL ); mlt_properties_set_int( a_props, "width", *width ); mlt_properties_set_int( a_props, "height", *height ); mlt_properties_set_int( a_props, "progressive", 1 ); @@ -226,15 +227,9 @@ // Get the properties of the frame mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); - // Get a unique name to store the frame position - char *name = mlt_properties_get( MLT_FILTER_PROPERTIES( this ), "_unique_id" ); - // Assign the frame out point to the filter (just in case we need it later) mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "_out", mlt_properties_get_int( properties, "out" ) ); - // Assign the current position to the name - mlt_properties_set_position( properties, name, mlt_frame_get_position( frame ) - mlt_filter_get_in( this ) ); - // Push the filter on to the stack mlt_frame_push_service( frame, this ); diff -Nru mlt-0.6.2/src/modules/core/Makefile mlt-0.7.2/src/modules/core/Makefile --- mlt-0.6.2/src/modules/core/Makefile 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/core/Makefile 2011-05-02 05:59:12.000000000 +0000 @@ -43,6 +43,12 @@ SRCS := $(OBJS:.o=.c) +ifeq ($(targetos), MinGW) +CFLAGS += -I../../win32 +OBJS += ../../win32/fnmatch.o +SRCS += ../../win32/fnmatch.c +endif + all: $(TARGET) $(TARGET): $(OBJS) $(ASM_OBJS) diff -Nru mlt-0.6.2/src/modules/core/producer_colour.c mlt-0.7.2/src/modules/core/producer_colour.c --- mlt-0.6.2/src/modules/core/producer_colour.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/core/producer_colour.c 2011-05-02 05:59:12.000000000 +0000 @@ -50,7 +50,7 @@ // Set the default properties mlt_properties_set( properties, "resource", colour == NULL ? "0x000000ff" : colour ); mlt_properties_set( properties, "_resource", "" ); - mlt_properties_set_double( properties, "aspect_ratio", 0 ); + mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile ) ); return producer; } @@ -99,6 +99,8 @@ // Obtain the producer for this frame mlt_producer producer = mlt_properties_get_data( properties, "producer_colour", NULL ); + mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) ); + // Obtain properties of producer mlt_properties producer_props = MLT_PRODUCER_PROPERTIES( producer ); @@ -116,8 +118,10 @@ // Parse the colour if ( now && strchr( now, '/' ) ) { - now = strrchr( now, '/' ) + 1; + now = strdup( strrchr( now, '/' ) + 1 ); mlt_properties_set( producer_props, "resource", now ); + free( now ); + now = mlt_properties_get( producer_props, "resource" ); } rgba_color color = parse_color( now, mlt_properties_get_int( producer_props, "resource" ) ); @@ -128,23 +132,8 @@ int i = *width * *height + 1; int bpp; - switch ( *format ) - { - case mlt_image_rgb24: - bpp = 3; - break; - case mlt_image_rgb24a: - case mlt_image_opengl: - bpp = 4; - break; - default: - bpp = 2; - *format = mlt_image_yuv422; - break; - } - // Allocate the image - size = *width * *height * bpp; + size = mlt_image_format_size( *format, *width, *height, &bpp ); uint8_t *p = image = mlt_pool_alloc( size ); // Update the producer @@ -154,6 +143,8 @@ mlt_properties_set_int( producer_props, "_format", *format ); mlt_properties_set( producer_props, "_resource", now ); + mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) ); + switch ( *format ) { case mlt_image_yuv422: @@ -204,6 +195,10 @@ break; } } + else + { + mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) ); + } // Create the alpha channel int alpha_size = *width * *height; @@ -218,8 +213,8 @@ memcpy( *buffer, image, size ); // Now update properties so we free the copy after - mlt_properties_set_data( properties, "image", *buffer, size, mlt_pool_release, NULL ); - mlt_properties_set_data( properties, "alpha", alpha, alpha_size, mlt_pool_release, NULL ); + mlt_frame_set_image( frame, *buffer, size, mlt_pool_release ); + mlt_frame_set_alpha( frame, alpha, alpha_size, mlt_pool_release ); mlt_properties_set_double( properties, "aspect_ratio", mlt_properties_get_double( producer_props, "aspect_ratio" ) ); mlt_properties_set_int( properties, "real_width", *width ); mlt_properties_set_int( properties, "real_height", *height ); diff -Nru mlt-0.6.2/src/modules/core/producer_consumer.c mlt-0.7.2/src/modules/core/producer_consumer.c --- mlt-0.6.2/src/modules/core/producer_consumer.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/core/producer_consumer.c 2011-05-02 05:59:12.000000000 +0000 @@ -52,10 +52,19 @@ // Update the frame mlt_properties properties = mlt_frame_properties( frame ); - mlt_properties_set_data( properties, "image", new_image, size, mlt_pool_release, NULL ); + mlt_frame_set_image( frame, new_image, size, mlt_pool_release ); memcpy( new_image, *image, size ); mlt_properties_set( properties, "progressive", mlt_properties_get( MLT_FRAME_PROPERTIES(nested_frame), "progressive" ) ); *image = new_image; + + // Copy the alpha channel + uint8_t *alpha = mlt_properties_get_data( MLT_FRAME_PROPERTIES( nested_frame ), "alpha", &size ); + if ( alpha && size > 0 ) + { + new_image = mlt_pool_alloc( size ); + memcpy( new_image, alpha, size ); + mlt_frame_set_alpha( frame, new_image, size, mlt_pool_release ); + } return result; } @@ -64,22 +73,10 @@ { mlt_frame nested_frame = mlt_frame_pop_audio( frame ); int result = mlt_frame_get_audio( nested_frame, buffer, format, frequency, channels, samples ); - int size = *channels * *samples; - - switch ( *format ) - { - case mlt_audio_s16: - size *= sizeof( int16_t ); - break; - case mlt_audio_s32: - size *= sizeof( int32_t ); - case mlt_audio_float: - size *= sizeof( float ); - default: - mlt_log_error( NULL, "[producer consumer] Invalid audio format\n" ); - } + int size = mlt_audio_format_size( *format, *samples, *channels ); int16_t *new_buffer = mlt_pool_alloc( size ); - mlt_properties_set_data( MLT_FRAME_PROPERTIES( frame ), "audio", new_buffer, size, mlt_pool_release, NULL ); + + mlt_frame_set_audio( frame, new_buffer, *format, size, mlt_pool_release ); memcpy( new_buffer, *buffer, size ); *buffer = new_buffer; @@ -209,7 +206,7 @@ mlt_producer producer_consumer_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { - mlt_producer this = mlt_producer_new( ); + mlt_producer this = mlt_producer_new( profile ); // Encapsulate the real producer mlt_profile temp_profile = mlt_profile_init( NULL ); diff -Nru mlt-0.6.2/src/modules/core/producer_hold.c mlt-0.7.2/src/modules/core/producer_hold.c --- mlt-0.6.2/src/modules/core/producer_hold.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/core/producer_hold.c 2011-05-02 05:59:12.000000000 +0000 @@ -37,7 +37,7 @@ mlt_producer producer_hold_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { // Construct a new holding producer - mlt_producer this = mlt_producer_new( ); + mlt_producer this = mlt_producer_new( profile ); // Construct the requested producer via loader mlt_producer producer = mlt_factory_producer( profile, NULL, arg ); @@ -119,12 +119,12 @@ uint8_t *image = mlt_pool_alloc( size ); memcpy( image, *buffer, size ); *buffer = image; - mlt_properties_set_data( properties, "image", *buffer, size, mlt_pool_release, NULL ); + mlt_frame_set_image( frame, *buffer, size, mlt_pool_release ); } else { // Pass the current image as is - mlt_properties_set_data( properties, "image", *buffer, size, NULL, NULL ); + mlt_frame_set_image( frame, *buffer, size, NULL ); } // Make sure that no further scaling is done @@ -170,8 +170,8 @@ else { // Temporary fix - ensure that we aren't seen as a test frame - int8_t *image = mlt_properties_get_data( MLT_FRAME_PROPERTIES( real_frame ), "image", NULL ); - mlt_properties_set_data( MLT_FRAME_PROPERTIES( *frame ), "image", image, 0, NULL, NULL ); + uint8_t *image = mlt_properties_get_data( MLT_FRAME_PROPERTIES( real_frame ), "image", NULL ); + mlt_frame_set_image( *frame, image, 0, NULL ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( *frame ), "test_image", 0 ); } diff -Nru mlt-0.6.2/src/modules/core/producer_loader.c mlt-0.7.2/src/modules/core/producer_loader.c --- mlt-0.6.2/src/modules/core/producer_loader.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/core/producer_loader.c 2011-05-02 05:59:12.000000000 +0000 @@ -53,7 +53,8 @@ mlt_producer result = NULL; // 1st Line - check for service:resource handling - if ( strchr( file, ':' ) ) + // And ignore drive letters on Win32 - no single char services supported. + if ( strchr( file, ':' ) > file + 1 ) { char *temp = strdup( file ); char *service = temp; diff -Nru mlt-0.6.2/src/modules/core/producer_noise.c mlt-0.7.2/src/modules/core/producer_noise.c --- mlt-0.6.2/src/modules/core/producer_noise.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/core/producer_noise.c 2011-05-02 05:59:12.000000000 +0000 @@ -50,7 +50,7 @@ mlt_producer producer_noise_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { // Create a new producer object - mlt_producer this = mlt_producer_new( ); + mlt_producer this = mlt_producer_new( profile ); // Initialise the producer if ( this != NULL ) @@ -65,9 +65,6 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) { - // Obtain properties of frame - mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); - // Calculate the size of the image int size = *width * *height * 2; @@ -78,9 +75,7 @@ *buffer = mlt_pool_alloc( size ); // Update the frame - mlt_properties_set_data( properties, "image", *buffer, size, mlt_pool_release, NULL ); - mlt_properties_set_int( properties, "width", *width ); - mlt_properties_set_int( properties, "height", *height ); + mlt_frame_set_image( frame, *buffer, size, mlt_pool_release ); // Before we write to the image, make sure we have one if ( *buffer != NULL ) @@ -105,9 +100,6 @@ static int producer_get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) { - // Get the frame properties - mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); - int size = 0; // Correct the returns if necessary @@ -130,7 +122,7 @@ } // Set the buffer for destruction - mlt_properties_set_data( properties, "audio", *buffer, size, ( mlt_destructor )mlt_pool_release, NULL ); + mlt_frame_set_audio( frame, *buffer, *format, size, mlt_pool_release ); return 0; } @@ -147,7 +139,7 @@ mlt_properties properties = MLT_FRAME_PROPERTIES( *frame ); // Aspect ratio is whatever it needs to be - mlt_properties_set_double( properties, "aspect_ratio", 0 ); + mlt_properties_set_double( properties, "aspect_ratio", mlt_properties_get_double( MLT_PRODUCER_PROPERTIES( this ), "aspect_ratio" ) ); // Set producer-specific frame properties mlt_properties_set_int( properties, "progressive", 1 ); diff -Nru mlt-0.6.2/src/modules/core/producer_ppm.c mlt-0.7.2/src/modules/core/producer_ppm.c --- mlt-0.6.2/src/modules/core/producer_ppm.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/core/producer_ppm.c 2011-05-02 05:59:12.000000000 +0000 @@ -163,12 +163,12 @@ // Read it if ( pipe != NULL ) - fread( *buffer, size, 1, pipe ); + size = fread( *buffer, size, 1, pipe ); else memset( *buffer, 0, size ); // Pass the data on the frame properties - mlt_properties_set_data( properties, "audio", *buffer, size, free, NULL ); + mlt_frame_set_audio( this, *buffer, *format, size, free ); return 0; } @@ -178,10 +178,10 @@ int count = 0; { char temp[ 132 ]; - fgets( temp, 132, video ); - fgets( temp, 132, video ); + char *ignore = fgets( temp, 132, video ); + ignore = fgets( temp, 132, video ); count += sscanf( temp, "%d %d", width, height ); - fgets( temp, 132, video ); + ignore = fgets( temp, 132, video ); } return count; } @@ -211,10 +211,11 @@ uint8_t *image = mlt_pool_alloc( width * ( height + 1 ) * 3 ); // Read it - fread( image, width * height * 3, 1, video ); + size_t ignore; + ignore = fread( image, width * height * 3, 1, video ); // Pass the data on the frame properties - mlt_properties_set_data( properties, "image", image, width * ( height + 1 ) * 3, ( mlt_destructor )mlt_pool_release, NULL ); + mlt_frame_set_image( *frame, image, width * ( height + 1 ) * 3, mlt_pool_release ); mlt_properties_set_int( properties, "width", width ); mlt_properties_set_int( properties, "height", height ); mlt_properties_set_int( properties, "has_image", 1 ); diff -Nru mlt-0.6.2/src/modules/core/transition_composite.c mlt-0.7.2/src/modules/core/transition_composite.c --- mlt-0.6.2/src/modules/core/transition_composite.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/core/transition_composite.c 2011-05-02 05:59:12.000000000 +0000 @@ -98,10 +98,8 @@ // Create an empty geometries object mlt_geometry geometry = mlt_geometry_init( ); - // Get the in and out position - mlt_position in = mlt_transition_get_in( this ); - mlt_position out = mlt_transition_get_out( this ); - int length = out - in + 1; + // Get the duration + mlt_position length = mlt_transition_get_length( this ); double cycle = mlt_properties_get_double( properties, "cycle" ); // Get the new style geometry string @@ -187,20 +185,6 @@ /** Calculate the field delta for this frame - position between two frames. */ -static inline double delta_calculate( mlt_transition this, mlt_frame frame, mlt_position position ) -{ - // Get the in and out position - mlt_position in = mlt_transition_get_in( this ); - mlt_position out = mlt_transition_get_out( this ); - double length = out - in + 1; - - // Now do the calcs - double x = ( double )( position - in ) / length; - double y = ( double )( position + 1 - in ) / length; - - return length * ( y - x ) / 2.0; -} - static int get_value( mlt_properties properties, const char *preferred, const char *fallback ) { int value = mlt_properties_get_int( properties, preferred ); @@ -853,6 +837,7 @@ // Adjust to consumer scale *width = rint( geometry->sw * *width / geometry->nw ); + *width -= *width % 2; // coerce to even width for yuv422 *height = rint( geometry->sh * *height / geometry->nh ); // fprintf(stderr, "%s: scaled %dx%d norm %dx%d resize %dx%d\n", __FILE__, // geometry->sw, geometry->sh, geometry->nw, geometry->nh, *width, *height); @@ -881,9 +866,7 @@ if ( !crop ) { crop = mlt_geometry_init(); - mlt_position in = mlt_transition_get_in( this ); - mlt_position out = mlt_transition_get_out( this ); - int length = out - in + 1; + mlt_position length = mlt_transition_get_length( this ); double cycle = mlt_properties_get_double( properties, "cycle" ); // Allow a geometry repeat cycle @@ -951,7 +934,7 @@ } else { - int length = mlt_transition_get_out( this ) - mlt_transition_get_in( this ) + 1; + mlt_position length = mlt_transition_get_length( this ); double cycle = mlt_properties_get_double( properties, "cycle" ); if ( cycle > 1 ) length = cycle; @@ -999,10 +982,14 @@ uint8_t *dest = NULL; // Get the image and dimensions - uint8_t *image = mlt_properties_get_data( a_props, "image", NULL ); + uint8_t *image = NULL; int width = mlt_properties_get_int( a_props, "width" ); int height = mlt_properties_get_int( a_props, "height" ); - int format = mlt_properties_get_int( a_props, "format" ); + mlt_image_format format = mlt_image_yuv422; + + mlt_frame_get_image( a_frame, &image, &format, &width, &height, 0 ); + if ( !image ) + return b_frame; // Pointers for copy operation uint8_t *p; @@ -1047,7 +1034,7 @@ dest = mlt_pool_alloc( w * h * 2 ); // Assign to the new frame - mlt_properties_set_data( b_props, "image", dest, w * h * 2, mlt_pool_release, NULL ); + mlt_frame_set_image( b_frame, dest, w * h * 2, mlt_pool_release ); mlt_properties_set_int( b_props, "width", w ); mlt_properties_set_int( b_props, "height", h ); mlt_properties_set_int( b_props, "format", format ); @@ -1133,12 +1120,12 @@ struct geometry_s result; // Calculate the position - double delta = delta_calculate( this, a_frame, position ); + double delta = mlt_transition_get_progress_delta( this, a_frame ); // Get the image from the b frame uint8_t *image_b = NULL; - int width_b = *width; - int height_b = *height; + int width_b = *width > 0 ? *width : mlt_properties_get_int( a_props, "normalised_width" ); + int height_b = *height > 0 ? *height : mlt_properties_get_int( a_props, "normalised_height" ); // Vars for alphas uint8_t *alpha_a = NULL; @@ -1223,7 +1210,9 @@ int field; double luma_softness = mlt_properties_get_double( properties, "softness" ); + mlt_service_lock( MLT_TRANSITION_SERVICE( this ) ); uint16_t *luma_bitmap = get_luma( this, properties, width_b, height_b ); + mlt_service_unlock( MLT_TRANSITION_SERVICE( this ) ); char *operator = mlt_properties_get( properties, "operator" ); alpha_b = alpha_b == NULL ? mlt_frame_get_alpha_mask( b_frame ) : alpha_b; diff -Nru mlt-0.6.2/src/modules/core/transition_luma.c mlt-0.7.2/src/modules/core/transition_luma.c --- mlt-0.6.2/src/modules/core/transition_luma.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/core/transition_luma.c 2011-05-02 05:59:12.000000000 +0000 @@ -29,42 +29,6 @@ #include #include -/** Calculate the position for this frame. -*/ - -static float position_calculate( mlt_transition this, mlt_frame frame ) -{ - // Get the in and out position - mlt_position in = mlt_transition_get_in( this ); - mlt_position out = mlt_transition_get_out( this ); - - // Get the position of the frame - char *name = mlt_properties_get( MLT_TRANSITION_PROPERTIES( this ), "_unique_id" ); - mlt_position position = mlt_properties_get_position( MLT_FRAME_PROPERTIES( frame ), name ); - - // Now do the calcs - return ( float )( position - in ) / ( float )( out - in + 1 ); -} - -/** Calculate the field delta for this frame - position between two frames. -*/ - -static float delta_calculate( mlt_transition this, mlt_frame frame ) -{ - // Get the in and out position - mlt_position in = mlt_transition_get_in( this ); - mlt_position out = mlt_transition_get_out( this ); - - // Get the position of the frame - mlt_position position = mlt_frame_get_position( frame ); - - // Now do the calcs - float x = ( float )( position - in ) / ( float )( out - in + 1 ); - float y = ( float )( position + 1 - in ) / ( float )( out - in + 1 ); - - return ( y - x ) / 2.0; -} - static inline int dissolve_yuv( mlt_frame this, mlt_frame that, float weight, int width, int height ) { int ret = 0; @@ -368,6 +332,8 @@ // This compositer is yuv422 only *format = mlt_image_yuv422; + mlt_service_lock( MLT_TRANSITION_SERVICE( transition ) ); + // The cached luma map information int luma_width = mlt_properties_get_int( properties, "width" ); int luma_height = mlt_properties_get_int( properties, "height" ); @@ -380,14 +346,15 @@ // Correct width/height if not specified if ( luma_width == 0 || luma_height == 0 ) { - luma_width = mlt_properties_get_int( a_props, "width" ); - luma_height = mlt_properties_get_int( a_props, "height" ); + luma_width = *width; + luma_height = *height; } - if ( resource != current_resource ) + if ( resource && ( !current_resource || strcmp( resource, current_resource ) ) ) { char temp[ 512 ]; char *extension = strrchr( resource, '.' ); + char *orig_resource = resource; if ( strchr( resource, '%' ) ) { @@ -416,7 +383,7 @@ // Set the transition properties mlt_properties_set_int( properties, "width", luma_width ); mlt_properties_set_int( properties, "height", luma_height ); - mlt_properties_set( properties, "_resource", resource ); + mlt_properties_set( properties, "_resource", orig_resource ); mlt_properties_set_data( properties, "bitmap", luma_bitmap, luma_width * luma_height * 2, mlt_pool_release, NULL ); } } @@ -467,7 +434,7 @@ // Set the transition properties mlt_properties_set_int( properties, "width", luma_width ); mlt_properties_set_int( properties, "height", luma_height ); - mlt_properties_set( properties, "_resource", resource); + mlt_properties_set( properties, "_resource", orig_resource); mlt_properties_set_data( properties, "bitmap", luma_bitmap, luma_width * luma_height * 2, mlt_pool_release, NULL ); // Cleanup the luma frame @@ -481,9 +448,8 @@ } // Arbitrary composite defaults - float mix = position_calculate( transition, a_frame ); - float frame_delta = delta_calculate( transition, a_frame ); - + float mix = mlt_transition_get_progress( transition, a_frame ); + float frame_delta = mlt_transition_get_progress_delta( transition, a_frame ); float luma_softness = mlt_properties_get_double( properties, "softness" ); int progressive = mlt_properties_get_int( a_props, "consumer_deinterlace" ) || @@ -508,23 +474,34 @@ if ( mix >= 1.0 ) mix -= floor( mix ); - mix = reverse || invert ? 1 - mix : mix; - frame_delta *= reverse || invert ? -1.0 : 1.0; - // Ensure we get scaling on the b_frame if ( mlt_properties_get( b_props, "rescale.interp" ) == NULL || !strcmp( mlt_properties_get( b_props, "rescale.interp" ), "none" ) ) mlt_properties_set( b_props, "rescale.interp", mlt_properties_get( a_props, "rescale.interp" ) ); + + if ( invert ) + mlt_properties_set_int( b_props, "consumer_deinterlace", mlt_properties_get_int( a_props, "consumer_deinterlace") ); if ( mlt_properties_get( properties, "fixed" ) ) mix = mlt_properties_get_double( properties, "fixed" ); if ( luma_width > 0 && luma_height > 0 && luma_bitmap != NULL ) + { + reverse = invert ? !reverse : reverse; + mix = reverse ? 1 - mix : mix; + frame_delta *= reverse ? -1.0 : 1.0; // Composite the frames using a luma map luma_composite( !invert ? a_frame : b_frame, !invert ? b_frame : a_frame, luma_width, luma_height, luma_bitmap, mix, frame_delta, luma_softness, progressive ? -1 : top_field_first, width, height ); + } else + { + mix = ( reverse || invert ) ? 1 - mix : mix; + invert = 0; // Dissolve the frames using the time offset for mix value dissolve_yuv( a_frame, b_frame, mix, *width, *height ); + } + + mlt_service_unlock( MLT_TRANSITION_SERVICE( transition ) ); // Extract the a_frame image info *width = mlt_properties_get_int( !invert ? a_props : b_props, "width" ); @@ -540,12 +517,6 @@ static mlt_frame transition_process( mlt_transition transition, mlt_frame a_frame, mlt_frame b_frame ) { - // Get a unique name to store the frame position - char *name = mlt_properties_get( MLT_TRANSITION_PROPERTIES( transition ), "_unique_id" ); - - // Assign the current position to the name - mlt_properties_set_position( MLT_FRAME_PROPERTIES( a_frame ), name, mlt_frame_get_position( a_frame ) ); - // Push the transition on to the frame mlt_frame_push_service( a_frame, transition ); diff -Nru mlt-0.6.2/src/modules/core/transition_mix.c mlt-0.7.2/src/modules/core/transition_mix.c --- mlt-0.6.2/src/modules/core/transition_mix.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/core/transition_mix.c 2011-05-02 05:59:12.000000000 +0000 @@ -214,12 +214,13 @@ { // Determine the time position of this frame in the transition duration mlt_properties props = mlt_properties_get_data( MLT_FRAME_PROPERTIES( b_frame ), "_producer", NULL ); - int always_active = mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( this ), "always_active" ); - mlt_position in = !always_active ? mlt_transition_get_in( this ) : mlt_properties_get_int( props, "in" ); - mlt_position out = !always_active ? mlt_transition_get_out( this ) : mlt_properties_get_int( props, "out" ); + mlt_position in = mlt_properties_get_int( props, "in" ); + mlt_position out = mlt_properties_get_int( props, "out" ); int length = mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( this ), "length" ); - mlt_position time = !always_active ? mlt_frame_get_position( b_frame ) : mlt_properties_get_int( props, "_frame" ); - double mix = ( double )( time - in ) / ( double )( out - in + 1 ); + mlt_position time = mlt_properties_get_int( props, "_frame" ); + double mix = mlt_transition_get_progress( this, b_frame ); + if ( mlt_properties_get_int( properties, "always_active" ) ) + mix = ( double ) ( time - in ) / ( double ) ( out - in + 1 ); // TODO: Check the logic here - shouldn't we be computing current and next mixing levels in all cases? if ( length == 0 ) diff -Nru mlt-0.6.2/src/modules/core/transition_region.c mlt-0.7.2/src/modules/core/transition_region.c --- mlt-0.6.2/src/modules/core/transition_region.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/core/transition_region.c 2011-05-02 05:59:12.000000000 +0000 @@ -123,11 +123,11 @@ *p ++ = ( int )( ( ( *image ++ - 16 ) * 299 ) / 255 ); image ++; } - mlt_properties_set_data( MLT_FRAME_PROPERTIES( this ), "alpha", alpha, region_width * region_height, mlt_pool_release, NULL ); + mlt_frame_set_alpha( this, alpha, region_width * region_height, mlt_pool_release ); } else { - mlt_properties_set_data( MLT_FRAME_PROPERTIES( this ), "alpha", alpha, region_width * region_height, NULL, NULL ); + mlt_frame_set_alpha( this, alpha, region_width * region_height, NULL ); } this->get_alpha_mask = NULL; @@ -152,17 +152,16 @@ // Get the properties of the transition mlt_properties properties = MLT_TRANSITION_PROPERTIES( this ); + mlt_service_lock( MLT_TRANSITION_SERVICE( this ) ); + // Get the composite from the transition mlt_transition composite = mlt_properties_get_data( properties, "composite", NULL ); // Look for the first filter mlt_filter filter = mlt_properties_get_data( properties, "_filter_0", NULL ); - // Get the unique id of the filter (used to reacquire the producer position) - char *name = mlt_properties_get( properties, "_unique_id" ); - - // Get the original producer position - mlt_position position = mlt_properties_get_position( MLT_FRAME_PROPERTIES( frame ), name ); + // Get the position + mlt_position position = mlt_transition_get_position( this, frame ); // Create a composite if we don't have one if ( composite == NULL ) @@ -265,8 +264,8 @@ } } - // Get the image - error = mlt_frame_get_image( frame, image, format, width, height, 1 ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "width", *width ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "height", *height ); // Only continue if we have both filter and composite if ( composite != NULL ) @@ -290,12 +289,10 @@ b_frame = composite_copy_region( composite, frame, position ); // Ensure a destructor + char *name = mlt_properties_get( properties, "_unique_id" ); mlt_properties_set_data( MLT_FRAME_PROPERTIES( frame ), name, b_frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); } - // Set the position of the b_frame - mlt_frame_set_position( b_frame, position ); - // Make sure the filter is in the correct position while ( filter != NULL ) { @@ -386,6 +383,8 @@ error = mlt_frame_get_image( frame, image, format, width, height, 0 ); } + mlt_service_unlock( MLT_TRANSITION_SERVICE( this ) ); + return error; } @@ -394,15 +393,6 @@ static mlt_frame transition_process( mlt_transition this, mlt_frame a_frame, mlt_frame b_frame ) { - // Get the properties of the frame - mlt_properties properties = MLT_FRAME_PROPERTIES( a_frame ); - - // Get a unique name to store the frame position - char *name = mlt_properties_get( MLT_TRANSITION_PROPERTIES( this ), "_unique_id" ); - - // Assign the current position to the name - mlt_properties_set_position( properties, name, mlt_frame_get_position( a_frame ) ); - // Push the transition on to the frame mlt_frame_push_service( a_frame, this ); diff -Nru mlt-0.6.2/src/modules/decklink/configure mlt-0.7.2/src/modules/decklink/configure --- mlt-0.6.2/src/modules/decklink/configure 1970-01-01 00:00:00.000000000 +0000 +++ mlt-0.7.2/src/modules/decklink/configure 2011-05-02 05:59:12.000000000 +0000 @@ -0,0 +1,14 @@ +#!/bin/sh + +if [ "$help" != "1" ] +then + if [ "$targetos" = "Darwin" ] || [ "$targetos" = "MinGW" ] + then + echo "- does not build on OS X or Windows: disabling" + touch ../disable-decklink + exit 0 + fi + + exit 0 +fi + diff -Nru mlt-0.6.2/src/modules/decklink/consumer_decklink.cpp mlt-0.7.2/src/modules/decklink/consumer_decklink.cpp --- mlt-0.6.2/src/modules/decklink/consumer_decklink.cpp 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/decklink/consumer_decklink.cpp 2011-05-02 05:59:12.000000000 +0000 @@ -23,9 +23,10 @@ #include #include #include +#include #include "DeckLinkAPI.h" -const unsigned PREROLL_MINIMUM = 3; +static const unsigned PREROLL_MINIMUM = 3; typedef struct { @@ -81,7 +82,6 @@ mlt_consumer_s m_consumer; IDeckLink* m_deckLink; IDeckLinkOutput* m_deckLinkOutput; - IDeckLinkMutableVideoFrame* m_videoFrame; IDeckLinkDisplayMode* m_displayMode; pthread_mutex_t m_mutex; pthread_cond_t m_condition; @@ -98,10 +98,15 @@ int m_channels; uint32_t m_maxAudioBuffer; mlt_deque m_videoFrameQ; - + mlt_frame m_frame; + unsigned m_dropped; + bool m_isAudio; + bool m_isKeyer; + IDeckLinkKeyer* m_deckLinkKeyer; + IDeckLinkDisplayMode* getDisplayMode() { - mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( &m_consumer ) ); + mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( getConsumer() ) ); IDeckLinkDisplayModeIterator* iter; IDeckLinkDisplayMode* mode; IDeckLinkDisplayMode* result = 0; @@ -115,7 +120,7 @@ mode->GetFrameRate( &m_duration, &m_timescale ); m_fps = (double) m_timescale / m_duration; int p = mode->GetFieldDominance() == bmdProgressiveFrame; - mlt_log_verbose( &m_consumer, "BMD mode %dx%d %.3f fps prog %d\n", m_width, m_height, m_fps, p ); + mlt_log_verbose( getConsumer(), "BMD mode %dx%d %.3f fps prog %d\n", m_width, m_height, m_fps, p ); if ( m_width == profile->width && m_height == profile->height && p == profile->progressive && m_fps == mlt_profile_fps( profile ) ) @@ -134,12 +139,18 @@ ~DeckLinkConsumer() { + if ( m_deckLinkKeyer ) + m_deckLinkKeyer->Release(); if ( m_deckLinkOutput ) m_deckLinkOutput->Release(); if ( m_deckLink ) m_deckLink->Release(); if ( m_videoFrameQ ) + { mlt_deque_close( m_videoFrameQ ); + pthread_mutex_destroy( &m_mutex ); + pthread_cond_destroy( &m_condition ); + } } bool open( unsigned card = 0 ) @@ -149,7 +160,7 @@ if ( !deckLinkIterator ) { - mlt_log_verbose( NULL, "The DeckLink drivers not installed.\n" ); + mlt_log_error( getConsumer(), "The DeckLink drivers not installed.\n" ); return false; } @@ -157,22 +168,43 @@ do { if ( deckLinkIterator->Next( &m_deckLink ) != S_OK ) { - mlt_log_verbose( NULL, "DeckLink card not found\n" ); + mlt_log_error( getConsumer(), "DeckLink card not found\n" ); deckLinkIterator->Release(); return false; } } while ( ++i <= card ); + deckLinkIterator->Release(); // Obtain the audio/video output interface (IDeckLinkOutput) if ( m_deckLink->QueryInterface( IID_IDeckLinkOutput, (void**)&m_deckLinkOutput ) != S_OK ) { - mlt_log_verbose( NULL, "No DeckLink cards support output\n" ); + mlt_log_error( getConsumer(), "No DeckLink cards support output\n" ); m_deckLink->Release(); m_deckLink = 0; - deckLinkIterator->Release(); return false; } + // Get the keyer interface + IDeckLinkAttributes *deckLinkAttributes = 0; + m_deckLinkKeyer = 0; + if ( m_deckLink->QueryInterface( IID_IDeckLinkAttributes, (void**) &deckLinkAttributes ) == S_OK ) + { + bool flag = false; + if ( deckLinkAttributes->GetFlag( BMDDeckLinkSupportsInternalKeying, &flag ) == S_OK && flag ) + { + if ( m_deckLink->QueryInterface( IID_IDeckLinkKeyer, (void**) &m_deckLinkKeyer ) != S_OK ) + { + mlt_log_error( getConsumer(), "Failed to get keyer\n" ); + m_deckLinkOutput->Release(); + m_deckLinkOutput = 0; + m_deckLink->Release(); + m_deckLink = 0; + return false; + } + } + deckLinkAttributes->Release(); + } + // Provide this class as a delegate to the audio and video output interfaces m_deckLinkOutput->SetScheduledFrameCompletionCallback( this ); m_deckLinkOutput->SetAudioCallback( this ); @@ -187,36 +219,63 @@ bool start( unsigned preroll ) { + mlt_properties properties = MLT_CONSUMER_PROPERTIES( getConsumer() ); + + // Initialize members + m_count = 0; + m_frame = 0; + m_dropped = 0; + m_isPrerolling = true; + m_prerollCounter = 0; + m_preroll = preroll < PREROLL_MINIMUM ? PREROLL_MINIMUM : preroll; + m_channels = mlt_properties_get_int( properties, "channels" ); + m_isAudio = !mlt_properties_get_int( properties, "audio_off" ); + m_displayMode = getDisplayMode(); if ( !m_displayMode ) { - mlt_log_error( &m_consumer, "Profile is not compatible with decklink.\n" ); + mlt_log_error( getConsumer(), "Profile is not compatible with decklink.\n" ); return false; } + // Set the keyer + if ( m_deckLinkKeyer && ( m_isKeyer = mlt_properties_get_int( properties, "keyer" ) ) ) + { + bool external = false; + double level = mlt_properties_get_double( properties, "keyer_level" ); + + if ( m_deckLinkKeyer->Enable( external ) != S_OK ) + mlt_log_error( getConsumer(), "Failed to enable keyer\n" ); + m_deckLinkKeyer->SetLevel( level <= 1 ? ( level > 0 ? 255 * level : 255 ) : 255 ); + m_preroll = 0; + m_isAudio = false; + } + else if ( m_deckLinkKeyer ) + { + m_deckLinkKeyer->Disable(); + } + // Set the video output mode if ( S_OK != m_deckLinkOutput->EnableVideoOutput( m_displayMode->GetDisplayMode(), bmdVideoOutputFlagDefault) ) { - mlt_log_error( &m_consumer, "Failed to enable video output\n" ); + mlt_log_error( getConsumer(), "Failed to enable video output\n" ); return false; } - + // Set the audio output mode - m_channels = 2; + if ( !m_isAudio ) + { + m_deckLinkOutput->DisableAudioOutput(); + return true; + } if ( S_OK != m_deckLinkOutput->EnableAudioOutput( bmdAudioSampleRate48kHz, bmdAudioSampleType16bitInteger, m_channels, bmdAudioOutputStreamContinuous ) ) { - mlt_log_error( &m_consumer, "Failed to enable audio output\n" ); + mlt_log_error( getConsumer(), "Failed to enable audio output\n" ); stop(); return false; } m_fifo = sample_fifo_init(); - - // Preroll - m_isPrerolling = true; - m_prerollCounter = 0; - m_preroll = preroll < PREROLL_MINIMUM ? PREROLL_MINIMUM : preroll; - m_count = 0; m_deckLinkOutput->BeginAudioPreroll(); return true; @@ -253,129 +312,195 @@ } while ( mlt_deque_count( m_videoFrameQ ) ) { - m_videoFrame = (IDeckLinkMutableVideoFrame*) mlt_deque_pop_back( m_videoFrameQ ); - m_videoFrame->Release(); + IDeckLinkMutableVideoFrame* frame = (IDeckLinkMutableVideoFrame*) mlt_deque_pop_back( m_videoFrameQ ); + frame->Release(); } - m_videoFrame = 0; if ( m_fifo ) sample_fifo_close( m_fifo ); + mlt_frame_close( m_frame ); } - - void createFrame() + + void renderAudio( mlt_frame frame ) + { + mlt_audio_format format = mlt_audio_s16; + int frequency = bmdAudioSampleRate48kHz; + int samples = mlt_sample_calculator( m_fps, frequency, m_count ); + int16_t *pcm = 0; + + if ( !mlt_frame_get_audio( frame, (void**) &pcm, &format, &frequency, &m_channels, &samples ) ) + { + int count = samples; + + if ( !m_isPrerolling ) + { + uint32_t audioCount = 0; + uint32_t videoCount = 0; + + // Check for resync + m_deckLinkOutput->GetBufferedAudioSampleFrameCount( &audioCount ); + m_deckLinkOutput->GetBufferedVideoFrameCount( &videoCount ); + + // Underflow typically occurs during non-normal speed playback. + if ( audioCount < 1 || videoCount < 1 ) + { + // Upon switching to normal playback, buffer some frames faster than realtime. + mlt_log_info( getConsumer(), "buffer underrun: audio buf %u video buf %u frames\n", audioCount, videoCount ); + m_prerollCounter = 0; + } + + // While rebuffering + if ( isBuffering() ) + { + // Only append audio to reach the ideal level and not overbuffer. + int ideal = ( m_preroll - 1 ) * bmdAudioSampleRate48kHz / m_fps; + int actual = m_fifo->used / m_channels + audioCount; + int diff = ideal / 2 - actual; + count = diff < 0 ? 0 : diff < count ? diff : count; + } + } + if ( count > 0 ) + sample_fifo_append( m_fifo, pcm, count * m_channels ); + } + } + + bool createFrame() { - m_videoFrame = 0; + BMDPixelFormat format = m_isKeyer? bmdFormat8BitARGB : bmdFormat8BitYUV; + IDeckLinkMutableVideoFrame* frame = 0; + uint8_t *buffer = 0; + int stride = m_width * ( m_isKeyer? 4 : 2 ); + // Generate a DeckLink video frame if ( S_OK != m_deckLinkOutput->CreateVideoFrame( m_width, m_height, - m_width * 2, bmdFormat8BitYUV, bmdFrameFlagDefault, &m_videoFrame ) ) + stride, format, bmdFrameFlagDefault, &frame ) ) { - mlt_log_verbose( &m_consumer, "Failed to create video frame\n" ); + mlt_log_verbose( getConsumer(), "Failed to create video frame\n" ); stop(); - return; + return false; } // Make the first line black for field order correction. - uint8_t *buffer = 0; - if ( S_OK == m_videoFrame->GetBytes( (void**) &buffer ) && buffer ) + if ( S_OK == frame->GetBytes( (void**) &buffer ) && buffer ) { - for ( int i = 0; i < m_width; i++ ) + if ( m_isKeyer ) + { + memset( buffer, 0, stride ); + } + else for ( int i = 0; i < m_width; i++ ) { *buffer++ = 128; *buffer++ = 16; } } - mlt_log_debug( &m_consumer, "created video frame\n" ); - mlt_deque_push_back( m_videoFrameQ, m_videoFrame ); + mlt_log_debug( getConsumer(), "created video frame\n" ); + mlt_deque_push_back( m_videoFrameQ, frame ); + + return true; } - HRESULT render( mlt_frame frame ) + void renderVideo() { - HRESULT result = S_OK; - // Get the audio - double speed = mlt_properties_get_double( MLT_FRAME_PROPERTIES(frame), "_speed" ); - if ( speed == 1.0 ) + mlt_image_format format = m_isKeyer? mlt_image_rgb24a : mlt_image_yuv422; + uint8_t* image = 0; + + if ( !mlt_frame_get_image( m_frame, &image, &format, &m_width, &m_height, 0 ) ) { - mlt_audio_format format = mlt_audio_s16; - int frequency = bmdAudioSampleRate48kHz; - int samples = mlt_sample_calculator( m_fps, frequency, m_count ); - int16_t *pcm = 0; - - if ( !mlt_frame_get_audio( frame, (void**) &pcm, &format, &frequency, &m_channels, &samples ) ) + IDeckLinkMutableVideoFrame* decklinkFrame = (IDeckLinkMutableVideoFrame*) mlt_deque_pop_back( m_videoFrameQ ); + uint8_t* buffer = 0; + int stride = m_width * ( m_isKeyer? 4 : 2 ); + + decklinkFrame->GetBytes( (void**) &buffer ); + if ( buffer ) { - int count = samples; - - if ( !m_isPrerolling ) + int progressive = mlt_properties_get_int( MLT_FRAME_PROPERTIES( m_frame ), "progressive" ); + + if ( !m_isKeyer ) { - uint32_t audioCount = 0; - uint32_t videoCount = 0; - - // Check for resync - m_deckLinkOutput->GetBufferedAudioSampleFrameCount( &audioCount ); - m_deckLinkOutput->GetBufferedVideoFrameCount( &videoCount ); - - // Underflow typically occurs during non-normal speed playback. - if ( audioCount < 1 || videoCount < 1 ) + // Normal non-keyer playout - needs byte swapping + if ( !progressive && m_displayMode->GetFieldDominance() == bmdUpperFieldFirst ) + // convert lower field first to top field first + swab( image, buffer + stride, stride * ( m_height - 1 ) ); + else + swab( image, buffer, stride * m_height ); + } + else if ( !mlt_properties_get_int( MLT_FRAME_PROPERTIES( m_frame ), "test_image" ) ) + { + // Normal keyer output + int y = m_height + 1; + uint32_t* s = (uint32_t*) image; + uint32_t* d = (uint32_t*) buffer; + + if ( !progressive && m_displayMode->GetFieldDominance() == bmdUpperFieldFirst ) { - // Upon switching to normal playback, buffer some frames faster than realtime. - mlt_log_info( &m_consumer, "buffer underrun: audio buf %u video buf %u frames\n", audioCount, videoCount ); - m_prerollCounter = 0; + // Correct field order + m_height--; + d += stride; } - - // While rebuffering - if ( isBuffering() ) + + // Need to relocate alpha channel RGBA => ARGB + while ( --y ) { - // Only append audio to reach the ideal level and not overbuffer. - int ideal = ( m_preroll - 1 ) * bmdAudioSampleRate48kHz / m_fps; - int actual = m_fifo->used / m_channels + audioCount; - int diff = ideal / 2 - actual; - count = diff < 0 ? 0 : diff < count ? diff : count; + int x = m_width + 1; + while ( --x ) + { + *d++ = ( *s << 8 ) | ( *s >> 24 ); + s++; + } } } - if ( count > 0 ) - sample_fifo_append( m_fifo, pcm, count * m_channels ); + else + { + // Keying blank frames - nullify alpha + memset( buffer, 0, stride * m_height ); + } + m_deckLinkOutput->ScheduleVideoFrame( decklinkFrame, m_count * m_duration, m_duration, m_timescale ); } + mlt_deque_push_front( m_videoFrameQ, decklinkFrame ); } + } + + HRESULT render( mlt_frame frame ) + { + HRESULT result = S_OK; + + // Get the audio + double speed = mlt_properties_get_double( MLT_FRAME_PROPERTIES(frame), "_speed" ); + if ( m_isAudio && speed == 1.0 ) + renderAudio( frame ); // Create video frames while pre-rolling if ( m_isPrerolling ) { - createFrame(); - if ( !m_videoFrame ) + if ( !createFrame() ) { - mlt_log_error( &m_consumer, "failed to create video frame\n" ); + mlt_log_error( getConsumer(), "failed to create video frame\n" ); return S_FALSE; } } - // Get the video if ( mlt_properties_get_int( MLT_FRAME_PROPERTIES( frame ), "rendered") ) { - mlt_image_format format = mlt_image_yuv422; - uint8_t* image = 0; - uint8_t* buffer = 0; - - if ( !mlt_frame_get_image( frame, &image, &format, &m_width, &m_height, 0 ) ) - { - m_videoFrame = (IDeckLinkMutableVideoFrame*) mlt_deque_pop_back( m_videoFrameQ ); - m_videoFrame->GetBytes( (void**) &buffer ); - if ( m_displayMode->GetFieldDominance() == bmdUpperFieldFirst ) - // convert lower field first to top field first - swab( image, buffer + m_width * 2, m_width * ( m_height - 1 ) * 2 ); - else - swab( image, buffer, m_width * m_height * 2 ); - m_deckLinkOutput->ScheduleVideoFrame( m_videoFrame, m_count * m_duration, m_duration, m_timescale ); - mlt_deque_push_front( m_videoFrameQ, m_videoFrame ); - } + // Close the previous frame and use the new one + mlt_frame_close( m_frame ); + m_frame = frame; } else { - mlt_log_verbose( &m_consumer, "dropped video frame\n" ); + if ( !m_frame ) + m_frame = frame; + // Reuse the last frame + mlt_log_verbose( getConsumer(), "dropped video frame %u\n", ++m_dropped ); } + + // Get the video + renderVideo(); ++m_count; // Check for end of pre-roll if ( ++m_prerollCounter > m_preroll && m_isPrerolling ) { // Start audio and video output - m_deckLinkOutput->EndAudioPreroll(); + if ( m_isAudio ) + m_deckLinkOutput->EndAudioPreroll(); m_deckLinkOutput->StartScheduledPlayback( 0, m_timescale, 1.0 ); m_isPrerolling = false; } @@ -405,7 +530,7 @@ virtual HRESULT STDMETHODCALLTYPE ScheduledPlaybackHasStopped() { - return mlt_consumer_is_stopped( &m_consumer ) ? S_FALSE : S_OK; + return mlt_consumer_is_stopped( getConsumer() ) ? S_FALSE : S_OK; } virtual HRESULT STDMETHODCALLTYPE RenderAudioSamples( bool preroll ) @@ -457,22 +582,16 @@ while ( !terminated && mlt_properties_get_int( properties, "running" ) ) { // Get the frame - frame = mlt_consumer_rt_frame( consumer ); - - // Check for termination - if ( terminate_on_pause && frame ) - terminated = mlt_properties_get_double( MLT_FRAME_PROPERTIES( frame ), "_speed" ) == 0.0; - - // Check that we have a frame to work with - if ( frame ) + if ( ( frame = mlt_consumer_rt_frame( consumer ) ) ) { + // Check for termination + if ( terminate_on_pause ) + terminated = mlt_properties_get_double( MLT_FRAME_PROPERTIES( frame ), "_speed" ) == 0.0; + decklink->render( frame ); if ( !decklink->isBuffering() ) decklink->wait(); - - // Close the frame mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); - mlt_frame_close( frame ); } } @@ -598,10 +717,33 @@ return consumer; } +extern mlt_producer producer_decklink_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); + +static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) +{ + char file[ PATH_MAX ]; + const char *service_type = NULL; + switch ( type ) + { + case consumer_type: + service_type = "consumer"; + break; + case producer_type: + service_type = "producer"; + break; + default: + return NULL; + } + snprintf( file, PATH_MAX, "%s/decklink/%s_%s.yml", mlt_environment( "MLT_DATA" ), service_type, id ); + return mlt_properties_parse_yaml( file ); +} MLT_REPOSITORY { MLT_REGISTER( consumer_type, "decklink", consumer_decklink_init ); + MLT_REGISTER( producer_type, "decklink", producer_decklink_init ); + MLT_REGISTER_METADATA( consumer_type, "decklink", metadata, NULL ); + MLT_REGISTER_METADATA( producer_type, "decklink", metadata, NULL ); } } // extern C diff -Nru mlt-0.6.2/src/modules/decklink/consumer_decklink.yml mlt-0.7.2/src/modules/decklink/consumer_decklink.yml --- mlt-0.6.2/src/modules/decklink/consumer_decklink.yml 1970-01-01 00:00:00.000000000 +0000 +++ mlt-0.7.2/src/modules/decklink/consumer_decklink.yml 2011-05-02 05:59:12.000000000 +0000 @@ -0,0 +1,81 @@ +schema_version: 0.1 +type: consumer +identifier: decklink +title: Blackmagic Design DeckLink Output +version: 2 +copyright: Copyright (C) 2011 Daniel R. Dennedy +license: LGPL +language: en +creator: Dan Dennedy +tags: + - Audio + - Video +description: > + Output audio and video using Blackmagic Design DeckLink SDI or Intensity + HDMI cards. +notes: > + Please ensure that you use a MLT profile that is compatible with a broadcast + standard which the card you are using supports. +bugs: + - Only internal keying is supported at this time. + - Only 8-bit Y'CbCr or RGBA (key) is supported at this time. +parameters: + - identifier: argument + title: Card + type: integer + readonly: no + required: no + mutable: no + default: 0 + minimum: 0 + widget: spinner + + - identifier: preroll + title: Pre-roll Count + type: integer + description: > + This controls the amount of buffering in the DeckLink driver/library. + Increase this if you get video tearing or choppy audio. However, as + you increase the amount, you increase the risk of audio and video + becoming out of synchronization. + readonly: no + required: no + mutable: no + default: 3 + minimum: 2 + unit: frames + widget: spinner + + - identifier: keyer + title: Enable Keyer + type: integer + description: > + Keying is the process of compositing MLT output over a live SDI input. + The alpha channel of the MLT video controls the transparent areas, and + the keyer supports alpha-blending. You can not control the compositing + rectangle. Rather, the entire MLT output overlays the entire video + input. Therefore, you must use MLT's compositing services to control + the size and position. + readonly: no + required: no + mutable: no + default: 0 + minimum: 0 + maximum: 1 + widget: checkbox + + - identifier: keyer_level + title: Key Opacity + type: float + description: > + This controls the level of blending between the key and the input video. + 1 is fully opaque and something near 0 is transparent. However, absolute + 0 is considered as "not supplied" and also fully opaque. 0.5 is an + evenly balanced blending of the key and input video. + readonly: no + required: no + mutable: no + minimum: 0 + maximum: 1 + default: 1 + widget: slider diff -Nru mlt-0.6.2/src/modules/decklink/Makefile mlt-0.7.2/src/modules/decklink/Makefile --- mlt-0.6.2/src/modules/decklink/Makefile 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/decklink/Makefile 2011-05-02 05:59:12.000000000 +0000 @@ -7,6 +7,7 @@ TARGET = ../libmltdecklink$(LIBSUF) OBJS = consumer_decklink.o \ + producer_decklink.o \ DeckLinkAPIDispatch.o SRCS := $(OBJS:.o=.cpp) @@ -31,6 +32,12 @@ install: all install -m 755 $(TARGET) "$(DESTDIR)$(libdir)/mlt" + install -d "$(DESTDIR)$(datadir)/mlt/decklink" + install -m 644 producer_decklink.yml "$(DESTDIR)$(datadir)/mlt/decklink" + +uninstall: + rm "$(DESTDIR)$(libdir)/mlt/libmltdecklink$(LIBSUF)" 2> /dev/null || true + rm -rf "$(DESTDIR)$(datadir)/mlt/decklink" ifneq ($(wildcard .depend),) include .depend diff -Nru mlt-0.6.2/src/modules/decklink/producer_decklink.cpp mlt-0.7.2/src/modules/decklink/producer_decklink.cpp --- mlt-0.6.2/src/modules/decklink/producer_decklink.cpp 1970-01-01 00:00:00.000000000 +0000 +++ mlt-0.7.2/src/modules/decklink/producer_decklink.cpp 2011-05-02 05:59:12.000000000 +0000 @@ -0,0 +1,398 @@ +/* + * producer_decklink.c -- input from Blackmagic Design DeckLink + * Copyright (C) 2011 Dan Dennedy + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with consumer library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include "DeckLinkAPI.h" + +class DeckLinkProducer + : public IDeckLinkInputCallback +{ +private: + mlt_producer_s m_producer; + IDeckLink* m_decklink; + IDeckLinkInput* m_decklinkInput; + mlt_deque m_queue; + pthread_mutex_t m_mutex; + pthread_cond_t m_condition; + bool m_started; + + BMDDisplayMode getDisplayMode( mlt_profile profile ) + { + IDeckLinkDisplayModeIterator* iter; + IDeckLinkDisplayMode* mode; + BMDDisplayMode result = bmdDisplayModeNotSupported; + + if ( m_decklinkInput->GetDisplayModeIterator( &iter ) == S_OK ) + { + while ( !result && iter->Next( &mode ) == S_OK ) + { + int width = mode->GetWidth(); + int height = mode->GetHeight(); + BMDTimeValue duration; + BMDTimeScale timescale; + mode->GetFrameRate( &duration, ×cale ); + double fps = (double) timescale / duration; + int p = mode->GetFieldDominance() == bmdProgressiveFrame; + mlt_log_verbose( getProducer(), "BMD mode %dx%d %.3f fps prog %d\n", width, height, fps, p ); + + if ( width == profile->width && height == profile->height && p == profile->progressive + && fps == mlt_profile_fps( profile ) ) + result = mode->GetDisplayMode(); + } + } + + return result; + } + +public: + + mlt_producer getProducer() + { return &m_producer; } + + ~DeckLinkProducer() + { + if ( m_decklinkInput ) + m_decklinkInput->Release(); + if ( m_decklink ) + m_decklink->Release(); + if ( m_queue ) + { + stop(); + mlt_deque_close( m_queue ); + pthread_mutex_destroy( &m_mutex ); + pthread_cond_destroy( &m_condition ); + } + } + + bool open( mlt_profile profile, unsigned card = 0 ) + { + IDeckLinkIterator* decklinkIterator = CreateDeckLinkIteratorInstance(); + try + { + if ( !decklinkIterator ) + throw "The DeckLink drivers are not installed."; + + // Connect to the Nth DeckLink instance + unsigned i = 0; + do { + if ( decklinkIterator->Next( &m_decklink ) != S_OK ) + throw "DeckLink card not found."; + } while ( ++i <= card ); + decklinkIterator->Release(); + + // Get the input interface + if ( m_decklink->QueryInterface( IID_IDeckLinkInput, (void**) &m_decklinkInput ) != S_OK ) + throw "No DeckLink cards support input."; + + // Provide this class as a delegate to the input callback + m_decklinkInput->SetCallback( this ); + + // Initialize other members + pthread_mutex_init( &m_mutex, NULL ); + pthread_cond_init( &m_condition, NULL ); + m_queue = mlt_deque_init(); + m_started = false; + } + catch ( const char *error ) + { + if ( decklinkIterator ) + decklinkIterator->Release(); + mlt_log_error( getProducer(), "%s\n", error ); + return false; + } + return true; + } + + bool start( mlt_profile profile = 0 ) + { + if ( m_started ) + return false; + try + { + if ( !profile ) + profile = mlt_service_profile( MLT_PRODUCER_SERVICE( getProducer() ) ); + + // Get the display mode + BMDDisplayMode displayMode = getDisplayMode( profile ); + if ( displayMode == bmdDisplayModeNotSupported ) + throw "Profile is not compatible with decklink."; + + // Enable video capture + BMDPixelFormat pixelFormat = bmdFormat8BitYUV; + BMDVideoInputFlags flags = bmdVideoInputFlagDefault; + if ( S_OK != m_decklinkInput->EnableVideoInput( displayMode, pixelFormat, flags ) ) + throw "Failed to enable video capture."; + + // Enable audio capture + BMDAudioSampleRate sampleRate = bmdAudioSampleRate48kHz; + BMDAudioSampleType sampleType = bmdAudioSampleType16bitInteger; + int channels = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" ); + if ( S_OK != m_decklinkInput->EnableAudioInput( sampleRate, sampleType, channels ) ) + throw "Failed to enable audio capture."; + + // Start capture + m_started = m_decklinkInput->StartStreams() == S_OK; + if ( !m_started ) + throw "Failed to start capture."; + } + catch ( const char *error ) + { + m_decklinkInput->DisableVideoInput(); + mlt_log_error( getProducer(), "%s\n", error ); + return false; + } + return true; + } + + void stop() + { + if ( m_started ) + return; + + // Release the wait in getFrame + pthread_mutex_lock( &m_mutex ); + pthread_cond_broadcast( &m_condition ); + pthread_mutex_unlock( &m_mutex ); + + m_decklinkInput->StopStreams(); + + // Cleanup queue + pthread_mutex_lock( &m_mutex ); + while ( mlt_frame frame = (mlt_frame) mlt_deque_pop_back( m_queue ) ) + mlt_frame_close( frame ); + pthread_mutex_unlock( &m_mutex ); + + m_started = false; + } + + mlt_frame getFrame() + { + mlt_frame frame = NULL; + + // Wait if queue is empty + pthread_mutex_lock( &m_mutex ); + while ( mlt_deque_count( m_queue ) < 1 ) + pthread_cond_wait( &m_condition, &m_mutex ); + + // Get the first frame from the queue + frame = ( mlt_frame ) mlt_deque_pop_front( m_queue ); + pthread_mutex_unlock( &m_mutex ); + + // Set frame timestamp and properties + mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( getProducer() ) ); + mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); + mlt_properties_set_int( properties, "progressive", profile->progressive ); + mlt_properties_set_double( properties, "aspect_ratio", mlt_profile_sar( profile ) ); + mlt_properties_set_int( properties, "width", profile->width ); + mlt_properties_set_int( properties, "real_width", profile->width ); + mlt_properties_set_int( properties, "height", profile->height ); + mlt_properties_set_int( properties, "real_height", profile->height ); + mlt_properties_set_int( properties, "format", mlt_image_yuv422 ); + mlt_properties_set_int( properties, "audio_frequency", 48000 ); + mlt_properties_set_int( properties, "audio_channels", + mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" ) ); + + return frame; + } + + // *** DeckLink API implementation of IDeckLinkInputCallback *** // + + // IUnknown needs only a dummy implementation + virtual HRESULT STDMETHODCALLTYPE QueryInterface( REFIID iid, LPVOID *ppv ) + { return E_NOINTERFACE; } + virtual ULONG STDMETHODCALLTYPE AddRef() + { return 1; } + virtual ULONG STDMETHODCALLTYPE Release() + { return 1; } + + /************************* DeckLink API Delegate Methods *****************************/ + + virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived( + IDeckLinkVideoInputFrame* video, + IDeckLinkAudioInputPacket* audio ) + { + // Create mlt_frame + mlt_frame frame = mlt_frame_init( MLT_PRODUCER_SERVICE( getProducer() ) ); + + // Copy video + if ( video ) + { + if ( !( video->GetFlags() & bmdFrameHasNoInputSource ) ) + { + int size = video->GetRowBytes() * video->GetHeight(); + void* image = mlt_pool_alloc( size ); + void* buffer = 0; + + video->GetBytes( &buffer ); + if ( image && buffer ) + { + swab( buffer, image, size ); + mlt_frame_set_image( frame, (uint8_t*) image, size, mlt_pool_release ); + } + else if ( image ) + { + mlt_log_verbose( getProducer(), "no video\n" ); + mlt_pool_release( image ); + } + } + else + { + mlt_log_verbose( getProducer(), "no signal\n" ); + mlt_frame_close( frame ); + frame = 0; + } + } + else + { + mlt_log_verbose( getProducer(), "no video\n" ); + mlt_frame_close( frame ); + frame = 0; + } + + // Copy audio + if ( frame && audio ) + { + int channels = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" ); + int size = audio->GetSampleFrameCount() * channels * sizeof(int16_t); + mlt_audio_format format = mlt_audio_s16; + void* pcm = mlt_pool_alloc( size ); + void* buffer = 0; + + audio->GetBytes( &buffer ); + if ( buffer ) + { + memcpy( pcm, buffer, size ); + mlt_frame_set_audio( frame, pcm, format, size, mlt_pool_release ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES(frame), "audio_samples", audio->GetSampleFrameCount() ); + } + else + { + mlt_log_verbose( getProducer(), "no audio\n" ); + mlt_pool_release( pcm ); + } + } + else + { + mlt_log_verbose( getProducer(), "no audio\n" ); + } + + // Put frame in queue + if ( frame ) + { + int queueMax = mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "buffer" ); + pthread_mutex_lock( &m_mutex ); + if ( mlt_deque_count( m_queue ) < queueMax ) + { + mlt_deque_push_back( m_queue, frame ); + pthread_cond_broadcast( &m_condition ); + } + pthread_mutex_unlock( &m_mutex ); + } + + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged( + BMDVideoInputFormatChangedEvents events, + IDeckLinkDisplayMode* mode, + BMDDetectedVideoInputFormatFlags flags ) + { + return S_OK; + } +}; + +static int get_audio( mlt_frame frame, int16_t **buffer, mlt_audio_format *format, int *frequency, int *channels, int *samples ) +{ + return mlt_frame_get_audio( frame, (void**) buffer, format, frequency, channels, samples ); +} + +static int get_image( mlt_frame frame, uint8_t **buffer, mlt_image_format *format, int *width, int *height, int writable ) +{ + return mlt_frame_get_image( frame, buffer, format, width, height, writable ); +} + +static int get_frame( mlt_producer producer, mlt_frame_ptr frame, int index ) +{ + DeckLinkProducer* decklink = (DeckLinkProducer*) producer->child; + + // Get the next frame from the decklink object + *frame = decklink->getFrame(); + + // Calculate the next timecode + mlt_frame_set_position( *frame, mlt_producer_position( producer ) ); + mlt_producer_prepare_next( producer ); + + // Add audio and video getters + mlt_frame_push_audio( *frame, (void*) get_audio ); + mlt_frame_push_get_image( *frame, get_image ); + + return 0; +} + +static void producer_close( mlt_producer producer ) +{ + producer->close = NULL; + mlt_producer_close( producer ); + delete (DeckLinkProducer*) producer->child; +} + +extern "C" { + +/** Initialise the producer. + */ + +mlt_producer producer_decklink_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) +{ + // Allocate the producer + DeckLinkProducer* decklink = new DeckLinkProducer(); + mlt_producer producer = NULL; + + // If allocated and initializes + if ( decklink && !mlt_producer_init( decklink->getProducer(), decklink ) ) + { + if ( decklink->open( profile, arg? atoi( arg ) : 0 ) ) + { + producer = decklink->getProducer(); + + // Set callbacks + producer->close = (mlt_destructor) producer_close; + producer->get_frame = get_frame; + + // Set properties + mlt_properties_set( MLT_PRODUCER_PROPERTIES( producer ), "resource", arg ); + mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( producer ), "channels", 2 ); + mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( producer ), "buffer", 25 ); + + // Start immediately + if ( !decklink->start( profile ) ) + { + producer_close( producer ); + producer = NULL; + } + } + } + + return producer; +} + +} diff -Nru mlt-0.6.2/src/modules/decklink/producer_decklink.yml mlt-0.7.2/src/modules/decklink/producer_decklink.yml --- mlt-0.6.2/src/modules/decklink/producer_decklink.yml 1970-01-01 00:00:00.000000000 +0000 +++ mlt-0.7.2/src/modules/decklink/producer_decklink.yml 2011-05-02 05:59:12.000000000 +0000 @@ -0,0 +1,69 @@ +schema_version: 0.1 +type: producer +identifier: decklink +title: Blackmagic Design DeckLink Capture +version: 1 +copyright: Copytight (C) 2011 Daniel R. Dennedy +license: LGPL +language: en +creator: Dan Dennedy +tags: + - Audio + - Video +description: > + Capture video and audio using Blackmagic Design DeckLink SDI or Intensity + HDMI cards. +notes: > + Please ensure that you use a MLT profile that is compatible with a broadcast + standard which the card you are using supports. If you must use an interlaced + profile but wish to deinterlace or scale the input, then you must use the + consumer producer, e.g.: + melt -profile square_pal consumer:decklink: profile=dv_pal +bugs: + - It is incompatible with the yadif deinterlacer. + - Transport controls such as seeking has no affect. + - External deck control is not implemented. + - Only 8-bit Y'CbCr is supported at this time. +parameters: + - identifier: argument + title: Card + type: integer + readonly: no + required: no + mutable: no + default: 0 + minimum: 0 + widget: spinner + + - identifier: resource + title: Card + type: integer + readonly: yes + + - identifier: channels + title: Audio Channels + type: integer + readonly: no + required: no + mutable: no + default: 2 + minimum: 2 + maximum: 16 + widget: spinner + + - identifier: buffer + title: Maximum Buffer + description: > + There is a queue of frames between this plugin and its consumer. + If the consumer has a little, intermittent delay then it reduces the + risk of dropping a frame. However, this provides a maximum number of + frames that can be buffered to prevent consuming memory unbounded in + the case of frequent or sustained delays. + type: integer + readonly: no + required: no + mutable: no + default: 25 + minimum: 0 + unit: frames + widget: spinner diff -Nru mlt-0.6.2/src/modules/dgraft/filter_telecide.c mlt-0.7.2/src/modules/dgraft/filter_telecide.c --- mlt-0.6.2/src/modules/dgraft/filter_telecide.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/dgraft/filter_telecide.c 2011-05-02 05:59:12.000000000 +0000 @@ -782,7 +782,7 @@ { // Put the current image into the image cache, keyed on position size_t image_size = (*width * *height) << 1; - mlt_position pos = mlt_frame_get_position( frame ); + mlt_position pos = mlt_filter_get_position( filter, frame ); uint8_t *image_copy = mlt_pool_alloc( image_size ); memcpy( image_copy, *image, image_size ); char key[20]; @@ -1062,7 +1062,7 @@ // Do first and last lines. uint8_t *final = mlt_pool_alloc( image_size ); cx->finalp = final; - mlt_properties_set_data( frame_properties, "image", final, image_size, (mlt_destructor)mlt_pool_release, NULL ); + mlt_frame_set_image( frame, final, image_size, mlt_pool_release ); dstpn = cx->dstp + cx->dpitch; for ( cx->x = 0; cx->x < cx->w; cx->x++ ) { diff -Nru mlt-0.6.2/src/modules/dv/producer_libdv.c mlt-0.7.2/src/modules/dv/producer_libdv.c --- mlt-0.6.2/src/modules/dv/producer_libdv.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/dv/producer_libdv.c 2011-05-02 05:59:12.000000000 +0000 @@ -326,7 +326,7 @@ uint8_t *image = mlt_pool_alloc( *width * ( *height + 1 ) * 2 ); // Pass to properties for clean up - mlt_properties_set_data( properties, "image", image, *width * ( *height + 1 ) * 2, ( mlt_destructor )mlt_pool_release, NULL ); + mlt_frame_set_image( this, image, *width * ( *height + 1 ) * 2, mlt_pool_release ); // Decode the image pitches[ 0 ] = *width * 2; @@ -343,7 +343,7 @@ uint8_t *image = mlt_pool_alloc( *width * ( *height + 1 ) * 3 ); // Pass to properties for clean up - mlt_properties_set_data( properties, "image", image, *width * ( *height + 1 ) * 3, ( mlt_destructor )mlt_pool_release, NULL ); + mlt_frame_set_image( this, image, *width * ( *height + 1 ) * 3, mlt_pool_release ); // Decode the frame pitches[ 0 ] = 720 * 3; diff -Nru mlt-0.6.2/src/modules/effectv/filter_burn.c mlt-0.7.2/src/modules/effectv/filter_burn.c --- mlt-0.6.2/src/modules/effectv/filter_burn.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/effectv/filter_burn.c 2011-05-02 05:59:12.000000000 +0000 @@ -103,8 +103,9 @@ unsigned char v, w; RGB32 a, b; - diff = mlt_properties_get_data( MLT_FILTER_PROPERTIES( filter ), - "_diff", NULL ); + mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); + + diff = mlt_properties_get_data( MLT_FILTER_PROPERTIES( filter ), "_diff", NULL ); if (diff == NULL) { diff = mlt_pool_alloc(video_area*sizeof(unsigned char)); @@ -112,8 +113,7 @@ diff, video_area*sizeof(unsigned char), mlt_pool_release, NULL ); } - buffer = mlt_properties_get_data( MLT_FILTER_PROPERTIES( filter ), - "_buffer", NULL ); + buffer = mlt_properties_get_data( MLT_FILTER_PROPERTIES( filter ), "_buffer", NULL ); if (buffer == NULL) { buffer = mlt_pool_alloc(video_area*sizeof(unsigned char)); @@ -122,7 +122,6 @@ buffer, video_area*sizeof(unsigned char), mlt_pool_release, NULL ); } - if (burn_foreground == 1) { /* to burn the foreground, we need a background */ background = mlt_properties_get_data( MLT_FILTER_PROPERTIES( filter ), @@ -136,6 +135,8 @@ } } + mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); + if (burn_foreground == 1) { image_bgsubtract_y(diff, background, src, video_area, y_threshold); } else { diff -Nru mlt-0.6.2/src/modules/feeds/NTSC/data_fx.properties mlt-0.7.2/src/modules/feeds/NTSC/data_fx.properties --- mlt-0.6.2/src/modules/feeds/NTSC/data_fx.properties 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/feeds/NTSC/data_fx.properties 2011-05-02 05:59:12.000000000 +0000 @@ -26,7 +26,7 @@ .properties.length[1]=filter[1].composite.out .composite.geometry=5%,70%:90%x20% .filter[0]=watermark -.filter[0].resource=colour:0x000000 +.filter[0].resource=colour:0x000000ff .filter[0].composite.geometry=0%,0%:100%x100%:0;5=0%,0%:100%x100%:40 .filter[0].composite.titles=1 .filter[1]=watermark @@ -48,7 +48,7 @@ .properties.length[1]=filter[1].composite.out .composite.geometry=5%,5%:90%x20% .filter[0]=watermark -.filter[0].resource=colour:0x000000 +.filter[0].resource=colour:0x000000ff .filter[0].composite.geometry=0%,0%:100%x100%:0;5=0%,0%:100%x100%:40 .filter[0].composite.titles=1 .filter[1]=watermark @@ -69,7 +69,7 @@ .properties.length[0]=filter[1].composite.out .composite.geometry=0%,93%:100%x7% .filter[0]=watermark -.filter[0].resource=colour:0x000000 +.filter[0].resource=colour:0x000000ff .filter[0].composite.geometry=0%,0%:100%x100%:100 .filter[0].composite.titles=1 .filter[1]=watermark diff -Nru mlt-0.6.2/src/modules/feeds/PAL/data_fx.properties mlt-0.7.2/src/modules/feeds/PAL/data_fx.properties --- mlt-0.6.2/src/modules/feeds/PAL/data_fx.properties 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/feeds/PAL/data_fx.properties 2011-05-02 05:59:12.000000000 +0000 @@ -26,7 +26,7 @@ .properties.length[1]=filter[1].composite.out .composite.geometry=5%,70%:90%x20% .filter[0]=watermark -.filter[0].resource=colour:0x000000 +.filter[0].resource=colour:0x000000ff .filter[0].composite.geometry=0%,0%:100%x100%:0;5=0%,0%:100%x100%:40 .filter[1]=watermark .filter[1].resource=pango: @@ -47,7 +47,7 @@ .properties.length[1]=filter[1].composite.out .composite.geometry=5%,5%:90%x20% .filter[0]=watermark -.filter[0].resource=colour:0x000000 +.filter[0].resource=colour:0x000000ff .filter[0].composite.geometry=0%,0%:100%x100%:0;5=0%,0%:100%x100%:40 .filter[1]=watermark .filter[1].resource=pango: @@ -66,7 +66,7 @@ .properties.length[0]=filter[1].composite.out .composite.geometry=0%,93%:100%x7% .filter[0]=watermark -.filter[0].resource=colour:0x000000 +.filter[0].resource=colour:0x000000ff .filter[1]=watermark .filter[1].resource=pango: .filter[1].producer.markup=Shotcut diff -Nru mlt-0.6.2/src/modules/frei0r/blacklist.txt mlt-0.7.2/src/modules/frei0r/blacklist.txt --- mlt-0.6.2/src/modules/frei0r/blacklist.txt 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/frei0r/blacklist.txt 2011-05-02 05:59:12.000000000 +0000 @@ -1 +1 @@ -facedetect +perspective diff -Nru mlt-0.6.2/src/modules/frei0r/factory.c mlt-0.7.2/src/modules/frei0r/factory.c --- mlt-0.6.2/src/modules/frei0r/factory.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/frei0r/factory.c 2011-05-02 05:59:12.000000000 +0000 @@ -30,7 +30,15 @@ #include #include + +#ifdef WIN32 +#define LIBSUF ".dll" +#define FREI0R_PLUGIN_PATH "lib\\frei0r-1" +#else +#define LIBSUF ".so" #define FREI0R_PLUGIN_PATH "/usr/lib/frei0r-1:/usr/lib64/frei0r-1:/opt/local/lib/frei0r-1:/usr/local/lib/frei0r-1:$HOME/.frei0r-1/lib" +#endif + #define GET_FREI0R_PATH (getenv("FREI0R_PATH") ? getenv("FREI0R_PATH") : getenv("MLT_FREI0R_PLUGIN_PATH") ? getenv("MLT_FREI0R_PLUGIN_PATH") : FREI0R_PLUGIN_PATH) extern mlt_filter filter_frei0r_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); @@ -41,6 +49,24 @@ extern void transition_close( mlt_transition this ); extern mlt_frame transition_process( mlt_transition transition, mlt_frame a_frame, mlt_frame b_frame ); +static void check_thread_safe( mlt_properties properties, const char *name ) +{ + char dirname[PATH_MAX]; + snprintf( dirname, PATH_MAX, "%s/frei0r/not_thread_safe.txt", mlt_environment( "MLT_DATA" ) ); + mlt_properties not_thread_safe = mlt_properties_load( dirname ); + int i; + + for ( i = 0; i < mlt_properties_count( not_thread_safe ); i++ ) + { + if ( strcmp( name, mlt_properties_get_name( not_thread_safe, i ) ) == 0 ) + { + mlt_properties_set_int( properties, "_not_thread_safe", 1 ); + break; + } + } + mlt_properties_close( not_thread_safe ); +} + static mlt_properties fill_param_info ( mlt_service_type type, const char *service_name, char *name ) { char file[ PATH_MAX ]; @@ -150,7 +176,7 @@ return metadata; } -static void * load_lib( mlt_profile profile, mlt_service_type type , void* handle){ +static void * load_lib( mlt_profile profile, mlt_service_type type , void* handle, const char *name ){ int i=0; void (*f0r_get_plugin_info)(f0r_plugin_info_t*), @@ -163,7 +189,6 @@ const uint32_t* inframe2,const uint32_t* inframe3, uint32_t* outframe); if ( ( f0r_construct = dlsym(handle, "f0r_construct") ) && - (f0r_update = dlsym(handle,"f0r_update") ) && (f0r_destruct = dlsym(handle,"f0r_destruct") ) && (f0r_get_plugin_info = dlsym(handle,"f0r_get_plugin_info") ) && (f0r_get_param_info = dlsym(handle,"f0r_get_param_info") ) && @@ -173,6 +198,7 @@ (f0r_deinit= dlsym(handle,"f0r_deinit" ) ) ){ + f0r_update=dlsym(handle,"f0r_update"); f0r_update2=dlsym(handle,"f0r_update2"); f0r_plugin_info_t info; @@ -182,7 +208,7 @@ mlt_properties properties=NULL; if (type == producer_type && info.plugin_type == F0R_PLUGIN_TYPE_SOURCE ){ - mlt_producer this = mlt_producer_new( ); + mlt_producer this = mlt_producer_new( profile ); if ( this != NULL ) { this->get_frame = producer_get_frame; @@ -227,6 +253,7 @@ ret=transition; } } + check_thread_safe( properties, name ); mlt_properties_set_data(properties, "_dlclose_handle", handle , sizeof (void*) , NULL , NULL ); mlt_properties_set_data(properties, "_dlclose", dlclose , sizeof (void*) , NULL , NULL ); mlt_properties_set_data(properties, "f0r_construct", f0r_construct , sizeof(void*),NULL,NULL); @@ -259,27 +286,37 @@ void* ret=NULL; while (dircount--){ char soname[PATH_MAX]; + char *myid = strdup( id ); +#ifdef WIN32 + char *firstname = strtok( myid, "." ); +#else char *save_firstptr = NULL; - char *firstname=strtok_r(strdup(id),".",&save_firstptr); + char *firstname = strtok_r( myid, ".", &save_firstptr ); +#endif char* directory = mlt_tokeniser_get_string (tokeniser, dircount); - firstname=strtok_r(NULL,".",&save_firstptr); +#ifdef WIN32 + firstname = strtok( NULL, "." ); +#else + firstname = strtok_r( NULL, ".", &save_firstptr ); +#endif if (strncmp(directory, "$HOME", 5)) - snprintf(soname, PATH_MAX, "%s/%s.so", directory, firstname); + snprintf(soname, PATH_MAX, "%s/%s" LIBSUF, directory, firstname ); else - snprintf(soname, PATH_MAX, "%s%s/%s.so", getenv("HOME"), strchr(directory, '/'), firstname); + snprintf(soname, PATH_MAX, "%s%s/%s" LIBSUF, getenv("HOME"), strchr(directory, '/'), firstname ); if (firstname){ void* handle=dlopen(soname,RTLD_LAZY); if (handle ){ - ret=load_lib ( profile , type , handle ); + ret=load_lib ( profile , type , handle, firstname ); }else{ dlerror(); } } + free( myid ); } mlt_tokeniser_close ( tokeniser ); return ret; @@ -308,20 +345,24 @@ snprintf(dirname, PATH_MAX, "%s", directory); else snprintf(dirname, PATH_MAX, "%s%s", getenv("HOME"), strchr(directory, '/')); - mlt_properties_dir_list(direntries, dirname ,"*.so",1); + mlt_properties_dir_list(direntries, dirname ,"*" LIBSUF, 1); for (i=0; i + static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { @@ -32,12 +33,10 @@ if ( error == 0 && *image ) { - mlt_position length = mlt_filter_get_out( filter ) - mlt_filter_get_in( filter ) + 1; - mlt_position time = mlt_properties_get_position( properties, "_filter_position" ); - double position = ( double )( time ) / ( double )( length ); - - process_frei0r_item( filter_type, position, properties, this, image, width, height ); - + double position = mlt_filter_get_position( filter, this ); + mlt_profile profile = mlt_service_profile( MLT_FILTER_SERVICE( filter ) ); + double time = position / mlt_profile_fps( profile ); + process_frei0r_item( MLT_FILTER_SERVICE(filter), position, time, properties, this, image, width, height ); } return error; @@ -47,9 +46,6 @@ mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { mlt_frame_push_service( frame, this ); - // Determine the time position of this frame - mlt_properties_set_position( MLT_FILTER_PROPERTIES( this ), "_filter_position", mlt_frame_get_position( frame ) - mlt_filter_get_in( this ) ); - mlt_frame_push_get_image( frame, filter_get_image ); return frame; } diff -Nru mlt-0.6.2/src/modules/frei0r/frei0r_helper.c mlt-0.7.2/src/modules/frei0r/frei0r_helper.c --- mlt-0.6.2/src/modules/frei0r/frei0r_helper.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/frei0r/frei0r_helper.c 2011-05-02 05:59:12.000000000 +0000 @@ -45,7 +45,7 @@ } } -int process_frei0r_item( mlt_service_type type, double position, mlt_properties prop, mlt_frame this, uint8_t **image, int *width, int *height ) +int process_frei0r_item( mlt_service service, double position, double time, mlt_properties prop, mlt_frame this, uint8_t **image, int *width, int *height ) { int i=0; f0r_instance_t ( *f0r_construct ) ( unsigned int , unsigned int ) = mlt_properties_get_data( prop , "f0r_construct" ,NULL); @@ -57,8 +57,9 @@ void (*f0r_set_param_value)(f0r_instance_t instance, f0r_param_t param, int param_index)=mlt_properties_get_data( prop , "f0r_set_param_value" ,NULL); void (*f0r_update2) (f0r_instance_t instance, double time, const uint32_t* inframe1,const uint32_t* inframe2,const uint32_t* inframe3, - uint32_t* outframe)=mlt_properties_get_data( prop , "f0r_update2" ,NULL); - + uint32_t* outframe)=mlt_properties_get_data( prop , "f0r_update2" ,NULL); + mlt_service_type type = mlt_service_identify( service ); + int not_thread_safe = mlt_properties_get_int( prop, "_not_thread_safe" ); //use as name the width and height f0r_instance_t inst; @@ -66,6 +67,8 @@ char ctorname[1024]=""; sprintf(ctorname,"ctor-%dx%d",*width,*height); + mlt_service_lock( service ); + void* neu=mlt_properties_get_data( prop , ctorname ,NULL ); if (!f0r_construct){ //printf("no ctor\n"); @@ -77,6 +80,10 @@ }else{ inst=mlt_properties_get_data( prop , ctorname , NULL ); } + + if ( !not_thread_safe ) + mlt_service_unlock( service ); + if (f0r_get_plugin_info){ f0r_get_plugin_info(&info); for (i=0;i -int process_frei0r_item( mlt_service_type, double position, mlt_properties, +int process_frei0r_item( mlt_service, double position, double time, mlt_properties, mlt_frame, uint8_t **image, int *width, int *height ); void destruct (mlt_properties prop ); diff -Nru mlt-0.6.2/src/modules/frei0r/Makefile mlt-0.7.2/src/modules/frei0r/Makefile --- mlt-0.6.2/src/modules/frei0r/Makefile 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/frei0r/Makefile 2011-05-02 05:59:12.000000000 +0000 @@ -37,6 +37,7 @@ install -m 755 $(TARGET) "$(DESTDIR)$(libdir)/mlt" install -d "$(DESTDIR)$(prefix)/share/mlt/frei0r" install -m 644 blacklist.txt "$(DESTDIR)$(datadir)/mlt/frei0r" + install -m 644 not_thread_safe.txt "$(DESTDIR)$(datadir)/mlt/frei0r" ifneq ($(wildcard .depend),) include .depend diff -Nru mlt-0.6.2/src/modules/frei0r/not_thread_safe.txt mlt-0.7.2/src/modules/frei0r/not_thread_safe.txt --- mlt-0.6.2/src/modules/frei0r/not_thread_safe.txt 1970-01-01 00:00:00.000000000 +0000 +++ mlt-0.7.2/src/modules/frei0r/not_thread_safe.txt 2011-05-02 05:59:12.000000000 +0000 @@ -0,0 +1,23 @@ +facebl0r +facedetect +cluster +squareblur +primaries +rgbparade +scale0tilt +sobel +hqdn3d +sharpness +baltan +cartoon +edgeglow +equaliz0r +lightgraffiti +mask0mate +tehRoxx0r +vectorscope +vertigo +delay0r +threelay0r +twolay0r +select0r diff -Nru mlt-0.6.2/src/modules/frei0r/producer_frei0r.c mlt-0.7.2/src/modules/frei0r/producer_frei0r.c --- mlt-0.6.2/src/modules/frei0r/producer_frei0r.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/frei0r/producer_frei0r.c 2011-05-02 05:59:12.000000000 +0000 @@ -43,18 +43,15 @@ *buffer = mlt_pool_alloc( size ); // Update the frame - mlt_properties_set_data( properties, "image", *buffer, size, mlt_pool_release, NULL ); - mlt_properties_set_int( properties, "width", *width ); - mlt_properties_set_int( properties, "height", *height ); + mlt_frame_set_image( frame, *buffer, size, mlt_pool_release ); *format = mlt_image_rgb24a; if ( *buffer != NULL ) { - mlt_position in = mlt_producer_get_in( producer ); - mlt_position out = mlt_producer_get_out( producer ); - mlt_position time = mlt_frame_get_position( frame ); - double position = ( double )( time - in ) / ( double )( out - in + 1 ); - process_frei0r_item( producer_type, position, producer_props, frame, buffer, width, height ); + double position = mlt_frame_get_position( frame ); + mlt_profile profile = mlt_service_profile( MLT_PRODUCER_SERVICE( producer ) ); + double time = position / mlt_profile_fps( profile ); + process_frei0r_item( MLT_PRODUCER_SERVICE(producer), position, time, producer_props, frame, buffer, width, height ); } return 0; diff -Nru mlt-0.6.2/src/modules/frei0r/transition_frei0r.c mlt-0.7.2/src/modules/frei0r/transition_frei0r.c --- mlt-0.6.2/src/modules/frei0r/transition_frei0r.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/frei0r/transition_frei0r.c 2011-05-02 05:59:12.000000000 +0000 @@ -50,16 +50,10 @@ mlt_frame_get_image( a_frame, &images[0], format, width, height, 0 ); mlt_frame_get_image( b_frame, &images[1], format, width, height, 0 ); - mlt_position in = mlt_transition_get_in( transition ); - mlt_position out = mlt_transition_get_out( transition ); - - // Get the position of the frame - char *name = mlt_properties_get( MLT_TRANSITION_PROPERTIES( transition ), "_unique_id" ); - mlt_position position = mlt_properties_get_position( MLT_FRAME_PROPERTIES( a_frame ), name ); - - float pos=( float )( position - in ) / ( float )( out - in + 1 ); - - process_frei0r_item( transition_type, pos, properties, !invert ? a_frame : b_frame, images, width, height ); + double position = mlt_transition_get_position( transition, a_frame ); + mlt_profile profile = mlt_service_profile( MLT_TRANSITION_SERVICE( transition ) ); + double time = position / mlt_profile_fps( profile ); + process_frei0r_item( MLT_TRANSITION_SERVICE(transition), position, time, properties, !invert ? a_frame : b_frame, images, width, height ); *width = mlt_properties_get_int( !invert ? a_props : b_props, "width" ); *height = mlt_properties_get_int( !invert ? a_props : b_props, "height" ); @@ -69,8 +63,6 @@ mlt_frame transition_process( mlt_transition transition, mlt_frame a_frame, mlt_frame b_frame ) { - char *name = mlt_properties_get( MLT_TRANSITION_PROPERTIES( transition ), "_unique_id" ); - mlt_properties_set_position( MLT_FRAME_PROPERTIES( a_frame ), name, mlt_frame_get_position( a_frame ) ); mlt_frame_push_service( a_frame, transition ); mlt_frame_push_frame( a_frame, b_frame ); mlt_frame_push_get_image( a_frame, transition_get_image ); diff -Nru mlt-0.6.2/src/modules/gtk2/consumer_gtk2.c mlt-0.7.2/src/modules/gtk2/consumer_gtk2.c --- mlt-0.6.2/src/modules/gtk2/consumer_gtk2.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/gtk2/consumer_gtk2.c 2011-05-02 05:59:12.000000000 +0000 @@ -22,7 +22,11 @@ #include #include #include +#ifdef WIN32 +#include +#else #include +#endif #include mlt_consumer consumer_gtk2_preview_init( mlt_profile profile, GtkWidget *widget ) @@ -33,9 +37,13 @@ // This is a nasty little hack which is required by SDL if ( widget != NULL ) { - Window xwin = GDK_WINDOW_XWINDOW( widget->window ); +#ifdef WIN32 + HWND xwin = GDK_WINDOW_HWND( widget->window ); +#else + Window xwin = GDK_WINDOW_XWINDOW( widget->window ); +#endif char windowhack[ 32 ]; - sprintf( windowhack, "%ld", xwin ); + sprintf( windowhack, "%ld", (long) xwin ); setenv( "SDL_WINDOWID", windowhack, 1 ); } diff -Nru mlt-0.6.2/src/modules/gtk2/filter_rescale.c mlt-0.7.2/src/modules/gtk2/filter_rescale.c --- mlt-0.6.2/src/modules/gtk2/filter_rescale.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/gtk2/filter_rescale.c 2011-05-02 05:59:12.000000000 +0000 @@ -44,16 +44,19 @@ interp = PIXOPS_INTERP_NEAREST; else if ( strcmp( interps, "tiles" ) == 0 ) interp = PIXOPS_INTERP_TILES; - else if ( strcmp( interps, "hyper" ) == 0 ) + else if ( strcmp( interps, "hyper" ) == 0 || strcmp( interps, "bicubic" ) == 0 ) interp = PIXOPS_INTERP_HYPER; + int bpp; + int size = mlt_image_format_size( *format, owidth, oheight, &bpp ); + // Carry out the rescaling switch ( *format ) { case mlt_image_yuv422: { // Create the output image - uint8_t *output = mlt_pool_alloc( owidth * ( oheight + 1 ) * 2 ); + uint8_t *output = mlt_pool_alloc( size ); // Calculate strides int istride = iwidth * 2; @@ -62,9 +65,7 @@ yuv422_scale_simple( output, owidth, oheight, ostride, *image, iwidth, iheight, istride, interp ); // Now update the frame - mlt_properties_set_data( properties, "image", output, owidth * ( oheight + 1 ) * 2, ( mlt_destructor )mlt_pool_release, NULL ); - mlt_properties_set_int( properties, "width", owidth ); - mlt_properties_set_int( properties, "height", oheight ); + mlt_frame_set_image( this, output, size, mlt_pool_release ); // Return the output *image = output; @@ -74,10 +75,8 @@ case mlt_image_rgb24a: case mlt_image_opengl: { - int bpp = ( *format == mlt_image_rgb24 ? 3 : 4 ); - // Create the output image - uint8_t *output = mlt_pool_alloc( owidth * ( oheight + 1 ) * bpp ); + uint8_t *output = mlt_pool_alloc( size ); if ( strcmp( interps, "none" ) && ( iwidth != owidth || iheight != oheight ) ) { @@ -109,9 +108,7 @@ g_object_unref( scaled ); // Now update the frame - mlt_properties_set_data( properties, "image", output, owidth * ( oheight + 1 ) * bpp, ( mlt_destructor )mlt_pool_release, NULL ); - mlt_properties_set_int( properties, "width", owidth ); - mlt_properties_set_int( properties, "height", oheight ); + mlt_frame_set_image( this, output, size, mlt_pool_release ); // Return the output *image = output; diff -Nru mlt-0.6.2/src/modules/gtk2/Makefile mlt-0.7.2/src/modules/gtk2/Makefile --- mlt-0.6.2/src/modules/gtk2/Makefile 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/gtk2/Makefile 2011-05-02 05:59:12.000000000 +0000 @@ -36,13 +36,24 @@ OBJS += producer_pango.o CFLAGS += `pkg-config pangoft2 --cflags` LDFLAGS += `pkg-config pangoft2 --libs` +ifeq ($(targetos),Darwin) +LDFLAGS += -liconv +endif ifeq ($(targetos),FreeBSD) LDFLAGS += -liconv endif +ifeq ($(targetos), MinGW) +LDFLAGS += -liconv +endif endif SRCS := $(OBJS:.o=.c) +ifeq ($(targetos), MinGW) +OBJS += ../../win32/win32.o +SRCS += ../../win32/win32.c +endif + all: $(TARGET) $(TARGET): $(OBJS) $(ASM_OBJS) diff -Nru mlt-0.6.2/src/modules/gtk2/producer_pango.c mlt-0.7.2/src/modules/gtk2/producer_pango.c --- mlt-0.6.2/src/modules/gtk2/producer_pango.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/gtk2/producer_pango.c 2011-05-02 05:59:12.000000000 +0000 @@ -207,7 +207,10 @@ } else { - mlt_properties_set( properties, "markup", "" ); + producer->close = NULL; + mlt_producer_close( producer ); + producer = NULL; + free( this ); } } @@ -435,7 +438,7 @@ interp = GDK_INTERP_NEAREST; else if ( strcmp( interps, "tiles" ) == 0 ) interp = GDK_INTERP_TILES; - else if ( strcmp( interps, "hyper" ) == 0 ) + else if ( strcmp( interps, "hyper" ) == 0 || strcmp( interps, "bicubic" ) == 0 ) interp = GDK_INTERP_HYPER; // fprintf(stderr,"%s: scaling from %dx%d to %dx%d\n", __FILE__, this->width, this->height, width, height); @@ -466,6 +469,8 @@ *width = mlt_properties_get_int( properties, "rescale_width" ); *height = mlt_properties_get_int( properties, "rescale_height" ); + mlt_service_lock( MLT_PRODUCER_SERVICE( &this->parent ) ); + // Refresh the image pthread_mutex_lock( &pango_mutex ); refresh_image( frame, *width, *height ); @@ -483,7 +488,7 @@ memcpy( *buffer, gdk_pixbuf_get_pixels( this->pixbuf ), image_size ); // Now update properties so we free the copy after - mlt_properties_set_data( properties, "image", *buffer, image_size, mlt_pool_release, NULL ); + mlt_frame_set_image( frame, *buffer, image_size, mlt_pool_release ); *format = mlt_image_rgb24a; } else @@ -492,6 +497,7 @@ } pthread_mutex_unlock( &pango_mutex ); + mlt_service_unlock( MLT_PRODUCER_SERVICE( &this->parent ) ); return error; } diff -Nru mlt-0.6.2/src/modules/gtk2/producer_pixbuf.c mlt-0.7.2/src/modules/gtk2/producer_pixbuf.c --- mlt-0.6.2/src/modules/gtk2/producer_pixbuf.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/gtk2/producer_pixbuf.c 2011-05-02 05:59:12.000000000 +0000 @@ -124,7 +124,7 @@ { // Generate a temporary file for the svg char fullname[ 1024 ] = "/tmp/mlt.XXXXXX"; - int fd = mkstemp( fullname ); + int fd = g_mkstemp( fullname ); if ( fd > -1 ) { @@ -303,6 +303,9 @@ /* Free the EXIF data */ exif_data_unref(d); } + + // Remember EXIF value, might be useful for someone + mlt_properties_set_int( producer_props, "_exif_orientation" , exif_orientation ); if ( exif_orientation > 1 ) { @@ -372,7 +375,7 @@ interp = GDK_INTERP_NEAREST; else if ( strcmp( interps, "tiles" ) == 0 ) interp = GDK_INTERP_TILES; - else if ( strcmp( interps, "hyper" ) == 0 ) + else if ( strcmp( interps, "hyper" ) == 0 || strcmp( interps, "bicubic" ) == 0 ) interp = GDK_INTERP_HYPER; // Note - the original pixbuf is already safe and ready for destruction @@ -440,7 +443,7 @@ mlt_properties_set_int( cached_props, "height", this->height ); mlt_properties_set_int( cached_props, "real_width", mlt_properties_get_int( producer_props, "_real_width" ) ); mlt_properties_set_int( cached_props, "real_height", mlt_properties_get_int( producer_props, "_real_height" ) ); - mlt_properties_set_data( cached_props, "image", this->image, this->width * ( this->alpha ? 4 : 3 ) * this->height, mlt_pool_release, NULL ); + mlt_frame_set_image( cached, this->image, this->width * ( this->alpha ? 4 : 3 ) * this->height, mlt_pool_release ); mlt_properties_set_int( cached_props, "alpha", this->alpha ); mlt_properties_set_data( cache, image_key, cached, 0, ( mlt_destructor )mlt_frame_close, NULL ); } @@ -461,6 +464,8 @@ *width = mlt_properties_get_int( properties, "rescale_width" ); *height = mlt_properties_get_int( properties, "rescale_height" ); + mlt_service_lock( MLT_PRODUCER_SERVICE( &this->parent ) ); + // Refresh the image refresh_image( this, frame, *width, *height ); @@ -477,7 +482,7 @@ uint8_t *image_copy = mlt_pool_alloc( image_size ); memcpy( image_copy, this->image, image_size ); // Now update properties so we free the copy after - mlt_properties_set_data( properties, "image", image_copy, image_size, mlt_pool_release, NULL ); + mlt_frame_set_image( frame, image_copy, image_size, mlt_pool_release ); // We're going to pass the copy on *buffer = image_copy; *format = this->alpha ? mlt_image_rgb24a : mlt_image_rgb24; @@ -492,6 +497,7 @@ // Release references and locks pthread_mutex_unlock( &this->mutex ); mlt_cache_item_close( this->image_cache ); + mlt_service_unlock( MLT_PRODUCER_SERVICE( &this->parent ) ); return error; } diff -Nru mlt-0.6.2/src/modules/jackrack/configure mlt-0.7.2/src/modules/jackrack/configure --- mlt-0.6.2/src/modules/jackrack/configure 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/jackrack/configure 2011-05-02 05:59:12.000000000 +0000 @@ -9,13 +9,15 @@ pkg-config libxml-2.0 > /dev/null 2>&1 disable_xml2=$? - disable_ladspa=1 ladspa_prefix=`which listplugins 2> /dev/null` if [ "$ladspa_prefix" != "" ] then ladspa_prefix=`dirname "$ladspa_prefix"` - disable_ladspa=`[ -f "$ladspa_prefix/include/ladspa.h" ] && echo 1 || echo 0` + ladspa_prefix=`dirname "$ladspa_prefix"` + else + ladspa_prefix=`pkg-config --variable=prefix jack` fi + disable_ladspa=`[ -f "$ladspa_prefix/include/ladspa.h" ] && echo 0 || echo 1` if [ "$disable_jack" = "1" -o "$disable_xml2" = "1" -o "$disable_ladspa" = "1" ] then diff -Nru mlt-0.6.2/src/modules/jackrack/filter_jackrack.c mlt-0.7.2/src/modules/jackrack/filter_jackrack.c --- mlt-0.6.2/src/modules/jackrack/filter_jackrack.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/jackrack/filter_jackrack.c 2011-05-02 05:59:12.000000000 +0000 @@ -27,9 +27,9 @@ #include #include +#include #include #include -#include #include #include "jack_rack.h" @@ -194,7 +194,7 @@ // Do not start returning audio until we have sent first mlt frame if ( sync && i == 0 && frame_size > 0 ) total_size += ring_size; - mlt_log_debug( MLT_FILTER_SERVICE(filter), "sync %d frame_size %d ring_size %zd jack_size %zd\n", sync, frame_size, ring_size, jack_size ); + mlt_log_debug( MLT_FILTER_SERVICE(filter), "sync %d frame_size %d ring_size %zu jack_size %zu\n", sync, frame_size, ring_size, jack_size ); if ( ! sync || ( frame_size > 0 && total_size >= frame_size ) ) { diff -Nru mlt-0.6.2/src/modules/jackrack/jack_rack.c mlt-0.7.2/src/modules/jackrack/jack_rack.c --- mlt-0.6.2/src/modules/jackrack/jack_rack.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/jackrack/jack_rack.c 2011-05-02 05:59:12.000000000 +0000 @@ -164,6 +164,10 @@ xmlChar *content; unsigned long num; unsigned long control = 0; +#ifdef WIN32 + xmlFreeFunc xmlFree = NULL; + xmlMemGet( &xmlFree, NULL, NULL, NULL); +#endif for (node = plugin->children; node; node = node->next) { @@ -257,6 +261,10 @@ xmlNodePtr node; xmlChar *content; saved_plugin_t * saved_plugin; +#ifdef WIN32 + xmlFreeFunc xmlFree = NULL; + xmlMemGet( &xmlFree, NULL, NULL, NULL); +#endif for (node = jackrack->children; node; node = node->next) { diff -Nru mlt-0.6.2/src/modules/jackrack/plugin.h mlt-0.7.2/src/modules/jackrack/plugin.h --- mlt-0.6.2/src/modules/jackrack/plugin.h 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/jackrack/plugin.h 2011-05-02 05:59:12.000000000 +0000 @@ -28,6 +28,7 @@ #include #include +#include #include #include "process.h" diff -Nru mlt-0.6.2/src/modules/jackrack/plugin_mgr.c mlt-0.7.2/src/modules/jackrack/plugin_mgr.c --- mlt-0.6.2/src/modules/jackrack/plugin_mgr.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/jackrack/plugin_mgr.c 2011-05-02 05:59:12.000000000 +0000 @@ -211,7 +211,11 @@ ladspa_path = g_strdup (getenv ("LADSPA_PATH")); if (!ladspa_path) +#ifdef WIN32 + ladspa_path = g_strdup ("lib\\ladspa"); +#else ladspa_path = g_strdup ("/usr/local/lib/ladspa:/usr/lib/ladspa:/usr/lib64/ladspa"); +#endif dir = strtok (ladspa_path, ":"); do diff -Nru mlt-0.6.2/src/modules/jackrack/process.c mlt-0.7.2/src/modules/jackrack/process.c --- mlt-0.6.2/src/modules/jackrack/process.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/jackrack/process.c 2011-05-02 05:59:12.000000000 +0000 @@ -23,6 +23,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include #include #include diff -Nru mlt-0.6.2/src/modules/kdenlive/filter_boxblur.c mlt-0.7.2/src/modules/kdenlive/filter_boxblur.c --- mlt-0.6.2/src/modules/kdenlive/filter_boxblur.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/kdenlive/filter_boxblur.c 2011-05-02 05:59:12.000000000 +0000 @@ -122,12 +122,8 @@ if ( mlt_properties_get( MLT_FILTER_PROPERTIES( this ), "end" ) != NULL ) { // Determine the time position of this frame in the transition duration - mlt_position in = mlt_filter_get_in( this ); - mlt_position out = mlt_filter_get_out( this ); - mlt_position time = mlt_frame_get_position( frame ); - double position = (double) ( time - in ) / ( out - in + 1.0 ); double end = (double) mlt_properties_get_int( MLT_FILTER_PROPERTIES( this ), "end" ); - blur += ( end - blur ) * position; + blur += ( end - blur ) * mlt_filter_get_progress( this, frame ); } // Push the frame filter diff -Nru mlt-0.6.2/src/modules/kdenlive/filter_freeze.c mlt-0.7.2/src/modules/kdenlive/filter_freeze.c --- mlt-0.6.2/src/modules/kdenlive/filter_freeze.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/kdenlive/filter_freeze.c 2011-05-02 05:59:12.000000000 +0000 @@ -38,7 +38,7 @@ int freeze_before = mlt_properties_get_int( properties, "freeze_before" ); int freeze_after = mlt_properties_get_int( properties, "freeze_after" ); mlt_position pos = mlt_properties_get_position( properties, "frame" ); - mlt_position currentpos = mlt_properties_get_position( properties, "_seek_frame" ); + mlt_position currentpos = mlt_filter_get_position( filter, this ); int do_freeze = 0; if (freeze_before == 0 && freeze_after == 0) { @@ -50,6 +50,7 @@ } if (do_freeze == 1) { + mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); freeze_frame = mlt_properties_get_data( properties, "freeze_frame", NULL ); if ( freeze_frame == NULL || mlt_properties_get_position( properties, "_frame" ) != pos ) { @@ -70,35 +71,19 @@ mlt_properties_set_data( properties, "freeze_frame", freeze_frame, 0, ( mlt_destructor )mlt_frame_close, NULL ); mlt_properties_set_position( properties, "_frame", pos ); } + mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); // Get frozen image uint8_t *buffer = NULL; int error = mlt_frame_get_image( freeze_frame, &buffer, format, width, height, 1 ); - int size = 0; - switch ( *format ) - { - case mlt_image_yuv420p: - size = *width * 3 * ( *height + 1 ) / 2; - break; - case mlt_image_rgb24: - size = *width * ( *height + 1 ) * 3; - break; - case mlt_image_rgb24a: - case mlt_image_opengl: - size = *width * ( *height + 1 ) * 4; - break; - default: - *format = mlt_image_yuv422; - size = *width * ( *height + 1 ) * 2; - break; - } - // Copy it to current frame - uint8_t *image_copy = mlt_pool_alloc( size ); + int size = mlt_image_format_size( *format, *width, *height, NULL ); + uint8_t *image_copy = mlt_pool_alloc( size ); memcpy( image_copy, buffer, size ); *image = image_copy; - mlt_properties_set_data( props, "image", *image, size, ( mlt_destructor ) mlt_pool_release, NULL ); + mlt_frame_set_image( this, *image, size, mlt_pool_release ); + return error; } @@ -115,9 +100,6 @@ // Push the filter on to the stack mlt_frame_push_service( frame, this ); - // Determine the time position of this frame - mlt_properties_set_position( MLT_FILTER_PROPERTIES( this ), "_seek_frame", mlt_frame_get_position( frame ) - mlt_filter_get_in( this ) ); - // Push the frame filter mlt_frame_push_get_image( frame, filter_get_image ); diff -Nru mlt-0.6.2/src/modules/kdenlive/filter_wave.c mlt-0.7.2/src/modules/kdenlive/filter_wave.c --- mlt-0.6.2/src/modules/kdenlive/filter_wave.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/kdenlive/filter_wave.c 2011-05-02 05:59:12.000000000 +0000 @@ -60,25 +60,28 @@ } } -static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) +static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { + mlt_properties unique = mlt_frame_pop_service( frame ); + mlt_position position = mlt_frame_get_position( frame ); + // Get the image *format = mlt_image_yuv422; - int error = mlt_frame_get_image( this, image, format, width, height, 0 ); - mlt_position position = mlt_frame_get_position( this ); + int error = mlt_frame_get_image( frame, image, format, width, height, 0 ); // Only process if we have no error and a valid colour space if ( error == 0 ) { - double factor = mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "wave" ); - int speed = mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "speed" ); - int deformX = mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "deformX" ); - int deformY = mlt_properties_get_int( MLT_FRAME_PROPERTIES( this ), "deformY" ); + double factor = mlt_properties_get_int( unique, "wave" ); + int speed = mlt_properties_get_int( unique, "speed" ); + int deformX = mlt_properties_get_int( unique, "deformX" ); + int deformY = mlt_properties_get_int( unique, "deformY" ); if (factor != 0) { - int image_size = *width * (*height + 1) * 2; - *image = mlt_pool_alloc (image_size); - DoWave(*image, *width, (*height + 1), *image, position, speed, factor, deformX, deformY); - mlt_properties_set_data( MLT_FRAME_PROPERTIES( this ), "image", *image, image_size, mlt_pool_release, NULL ); + int image_size = *width * (*height) * 2; + uint8_t *dst = mlt_pool_alloc (image_size); + DoWave(*image, *width, (*height), dst, position, speed, factor, deformX, deformY); + *image = dst; + mlt_frame_set_image( frame, *image, image_size, mlt_pool_release ); } } @@ -88,31 +91,29 @@ /** Filter processing. */ -static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) +static mlt_frame filter_process( mlt_filter filter, mlt_frame frame ) { // Get the starting wave level - double wave = mlt_properties_get_double( MLT_FILTER_PROPERTIES( this ), "start" ); - int speed = mlt_properties_get_int( MLT_FILTER_PROPERTIES( this ), "speed" ); - int deformX = mlt_properties_get_int( MLT_FILTER_PROPERTIES( this ), "deformX" ); - int deformY = mlt_properties_get_int( MLT_FILTER_PROPERTIES( this ), "deformY" ); + double wave = mlt_properties_get_double( MLT_FILTER_PROPERTIES( filter ), "start" ); + int speed = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "speed" ); + int deformX = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "deformX" ); + int deformY = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "deformY" ); // If there is an end adjust gain to the range - if ( mlt_properties_get( MLT_FILTER_PROPERTIES( this ), "end" ) != NULL ) + if ( mlt_properties_get( MLT_FILTER_PROPERTIES( filter ), "end" ) != NULL ) { // Determine the time position of this frame in the transition duration - mlt_position in = mlt_filter_get_in( this ); - mlt_position out = mlt_filter_get_out( this ); - mlt_position time = mlt_frame_get_position( frame ); - double position = ( double )( time - in ) / ( double )( out - in + 1 ); - double end = fabs( mlt_properties_get_double( MLT_FILTER_PROPERTIES( this ), "end" ) ); - wave += ( end - wave ) * position; + double end = fabs( mlt_properties_get_double( MLT_FILTER_PROPERTIES( filter ), "end" ) ); + wave += ( end - wave ) * mlt_filter_get_progress( filter, frame ); } // Push the frame filter - mlt_properties_set_double( MLT_FRAME_PROPERTIES( frame ), "wave", wave ); - mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "speed", speed ); - mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "deformX", deformX ); - mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "deformY", deformY ); + mlt_properties unique = mlt_frame_unique_properties( frame, MLT_FILTER_SERVICE( filter ) ); + mlt_properties_set_double( unique, "wave", wave ); + mlt_properties_set_int( unique, "speed", speed ); + mlt_properties_set_int( unique, "deformX", deformX ); + mlt_properties_set_int( unique, "deformY", deformY ); + mlt_frame_push_service( frame, unique ); mlt_frame_push_get_image( frame, filter_get_image ); return frame; @@ -123,16 +124,16 @@ mlt_filter filter_wave_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { - mlt_filter this = mlt_filter_new( ); - if ( this != NULL ) + mlt_filter filter = mlt_filter_new( ); + if ( filter ) { - this->process = filter_process; - mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "start", arg == NULL ? "10" : arg); - mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "speed", arg == NULL ? "5" : arg); - mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "deformX", arg == NULL ? "1" : arg); - mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "deformY", arg == NULL ? "1" : arg); - } - return this; + filter->process = filter_process; + mlt_properties_set( MLT_FILTER_PROPERTIES( filter ), "start", arg == NULL ? "10" : arg); + mlt_properties_set( MLT_FILTER_PROPERTIES( filter ), "speed", arg == NULL ? "5" : arg); + mlt_properties_set( MLT_FILTER_PROPERTIES( filter ), "deformX", arg == NULL ? "1" : arg); + mlt_properties_set( MLT_FILTER_PROPERTIES( filter ), "deformY", arg == NULL ? "1" : arg); + } + return filter; } diff -Nru mlt-0.6.2/src/modules/kdenlive/producer_framebuffer.c mlt-0.7.2/src/modules/kdenlive/producer_framebuffer.c --- mlt-0.6.2/src/modules/kdenlive/producer_framebuffer.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/kdenlive/producer_framebuffer.c 2011-05-02 05:59:12.000000000 +0000 @@ -41,6 +41,8 @@ int index = ( int )mlt_frame_pop_service( this ); mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer ); + mlt_service_lock( MLT_PRODUCER_SERVICE( producer ) ); + // Frame properties objects mlt_properties frame_properties = MLT_FRAME_PROPERTIES( this ); mlt_frame first_frame = mlt_properties_get_data( properties, "first_frame", NULL ); @@ -83,26 +85,7 @@ // Determine output buffer size *width = mlt_properties_get_int( frame_properties, "width" ); *height = mlt_properties_get_int( frame_properties, "height" ); - - int size; - switch ( *format ) - { - case mlt_image_yuv420p: - size = *width * 3 * ( *height + 1 ) / 2; - break; - case mlt_image_rgb24: - size = *width * ( *height + 1 ) * 3; - break; - case mlt_image_rgb24a: - case mlt_image_opengl: - size = *width * ( *height + 1 ) * 4; - break; - default: - *format = mlt_image_yuv422; - size = *width * ( *height + 1 ) * 2; - break; - } - + int size = mlt_image_format_size( *format, *width, *height, NULL ); // Get output buffer int buffersize = 0; @@ -130,12 +113,13 @@ // Set the output image *image = image_copy; - mlt_properties_set_data( frame_properties, "image", image_copy, size, ( mlt_destructor )mlt_pool_release, NULL ); + mlt_frame_set_image( this, image_copy, size, mlt_pool_release ); *width = mlt_properties_get_int( properties, "_output_width" ); *height = mlt_properties_get_int( properties, "_output_height" ); *format = mlt_properties_get_int( properties, "_output_format" ); + mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) ); return 0; } @@ -167,7 +151,8 @@ int error = mlt_frame_get_image( first_frame, &first_image, format, width, height, writable ); if ( error != 0 ) { - fprintf(stderr, "first_image == NULL get image died\n"); + mlt_log_error( MLT_PRODUCER_SERVICE( producer ), "first_image == NULL get image died\n" ); + mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) ); return error; } output = mlt_pool_alloc( size ); @@ -179,6 +164,7 @@ mlt_properties_set_int( properties, "_output_format", *format ); } + mlt_service_unlock( MLT_PRODUCER_SERVICE( producer ) ); // Create a copy uint8_t *image_copy = mlt_pool_alloc( size ); @@ -186,7 +172,7 @@ // Set the output image *image = image_copy; - mlt_properties_set_data( frame_properties, "image", *image, size, ( mlt_destructor )mlt_pool_release, NULL ); + mlt_frame_set_image( this, *image, size, mlt_pool_release ); return 0; } diff -Nru mlt-0.6.2/src/modules/kino/configure mlt-0.7.2/src/modules/kino/configure --- mlt-0.6.2/src/modules/kino/configure 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/kino/configure 2011-05-02 05:59:12.000000000 +0000 @@ -3,9 +3,9 @@ if [ "$help" != "1" ] then - if [ "$targetos" = "Darwin" ] + if [ "$targetos" = "Darwin" ] || [ "$targetos" = "MinGW" ] then - echo "- does not build on Darwin: disabling" + echo "- does not build on OS X or Windows: disabling" touch ../disable-kino exit 0 fi diff -Nru mlt-0.6.2/src/modules/linsys/configure mlt-0.7.2/src/modules/linsys/configure --- mlt-0.6.2/src/modules/linsys/configure 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/linsys/configure 2011-05-02 05:59:12.000000000 +0000 @@ -5,24 +5,27 @@ cat << EOF Linsys options: - --enable-linsys - Enable the Linsys SDI module (disabled by default) --linsys-with-jpeg - Enable the option to export JPEGs (disabled by default) EOF else - export enable= + if [ "$targetos" = "Darwin" ] || [ "$targetos" = "MinGW" ] + then + echo "- does not build on OS X or Windows: disabling" + touch ../disable-linsys + exit 0 + fi + touch config.mak for i in "$@" do case $i in - --enable-linsys ) enable=1 ;; --linsys-with-jpeg ) echo "WITH_JPEG=1" > config.mak ;; esac done - [ "$enable" != "1" ] && touch ../disable-linsys exit 0 fi diff -Nru mlt-0.6.2/src/modules/linsys/sdi_generator.c mlt-0.7.2/src/modules/linsys/sdi_generator.c --- mlt-0.6.2/src/modules/linsys/sdi_generator.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/linsys/sdi_generator.c 2011-05-02 05:59:12.000000000 +0000 @@ -2352,7 +2352,7 @@ return strdup("0"); char * mystring = (char *) malloc(50); - sprintf(mystring, "%llui", i); + sprintf(mystring, "%"PRIu64, i); return mystring; } diff -Nru mlt-0.6.2/src/modules/melt/producer_melt.c mlt-0.7.2/src/modules/melt/producer_melt.c --- mlt-0.6.2/src/modules/melt/producer_melt.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/melt/producer_melt.c 2011-05-02 05:59:12.000000000 +0000 @@ -145,6 +145,23 @@ if ( argv ) for ( i = 0; argv[ i ] != NULL; i ++ ) { + if ( argv[ i + 1 ] == NULL && ( + !strcmp( argv[ i ], "-attach" ) || + !strcmp( argv[ i ], "-attach-cut" ) || + !strcmp( argv[ i ], "-attach-track" ) || + !strcmp( argv[ i ], "-attach-clip" ) || + !strcmp( argv[ i ], "-repeat" ) || + !strcmp( argv[ i ], "-split" ) || + !strcmp( argv[ i ], "-join" ) || + !strcmp( argv[ i ], "-mixer" ) || + !strcmp( argv[ i ], "-mix" ) || + !strcmp( argv[ i ], "-filter" ) || + !strcmp( argv[ i ], "-transition" ) || + !strcmp( argv[ i ], "-blank" ) ) ) + { + fprintf( stderr, "Argument missing for %s.\n", argv[ i ] ); + break; + } if ( !strcmp( argv[ i ], "-group" ) ) { if ( mlt_properties_count( group ) != 0 ) diff -Nru mlt-0.6.2/src/modules/motion_est/filter_autotrack_rectangle.c mlt-0.7.2/src/modules/motion_est/filter_autotrack_rectangle.c --- mlt-0.6.2/src/modules/motion_est/filter_autotrack_rectangle.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/motion_est/filter_autotrack_rectangle.c 2011-05-02 05:59:12.000000000 +0000 @@ -120,7 +120,7 @@ mlt_properties frame_properties = MLT_FRAME_PROPERTIES(frame); // Get the frame position - mlt_position position = mlt_frame_get_position( frame ); + mlt_position position = mlt_filter_get_position( filter, frame ); // Get the new image int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); @@ -128,6 +128,8 @@ if( error != 0 ) mlt_properties_debug( frame_properties, "error after mlt_frame_get_image() in autotrack_rectangle", stderr ); + mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); + // Get the geometry object mlt_geometry geometry = mlt_properties_get_data(filter_properties, "filter_geometry", NULL); @@ -171,7 +173,9 @@ mlt_geometry_insert(geometry, &boundry); } - if( mlt_properties_get_int( filter_properties, "debug" ) == 1 ) + mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); + + if( mlt_properties_get_int( filter_properties, "debug" ) == 1 ) { init_arrows( format, *width, *height ); draw_rectangle_outline(*image, boundry.x, boundry.y, boundry.w, boundry.h, 100); @@ -211,8 +215,10 @@ mlt_properties frame_properties = MLT_FRAME_PROPERTIES(frame); // Get the frame position - mlt_position position = mlt_frame_get_position( frame ); + mlt_position position = mlt_filter_get_position( filter, frame ); + mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); + // Get the geometry object mlt_geometry geometry = mlt_properties_get_data(filter_properties, "filter_geometry", NULL); if (geometry == NULL) { @@ -232,6 +238,8 @@ geometry = mlt_properties_get_data(filter_properties, "filter_geometry", NULL); } + mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); + // Get the current geometry item mlt_geometry_item geometry_item = mlt_pool_alloc( sizeof( struct mlt_geometry_item_s ) ); mlt_geometry_fetch(geometry, geometry_item, position); diff -Nru mlt-0.6.2/src/modules/motion_est/filter_crop_detect.c mlt-0.7.2/src/modules/motion_est/filter_crop_detect.c --- mlt-0.6.2/src/modules/motion_est/filter_crop_detect.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/motion_est/filter_crop_detect.c 2011-05-02 05:59:12.000000000 +0000 @@ -63,6 +63,8 @@ // Producers may start with blank footage, by default we will skip, oh, 5 frames unless overridden int skip = mlt_properties_get_int( properties, "skip"); + mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); + // The result mlt_geometry_item bounds = mlt_properties_get_data( properties, "bounds", NULL ); @@ -75,7 +77,7 @@ } // For periodic detection (with offset of 'skip') - if( frequency == 0 || (int)(mlt_frame_get_position(this)+skip) % frequency != 0) + if( frequency == 0 || (int)(mlt_filter_get_position(filter, this)+skip) % frequency != 0) { // Inject in stream mlt_properties_set_data( MLT_FRAME_PROPERTIES(this), "bounds", bounds, sizeof( struct mlt_geometry_item_s ), NULL, NULL ); @@ -191,6 +193,8 @@ /* inject into frame */ mlt_properties_set_data( MLT_FRAME_PROPERTIES(this), "bounds", bounds, sizeof( struct mlt_geometry_item_s ), NULL, NULL ); + mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); + return error; } diff -Nru mlt-0.6.2/src/modules/motion_est/filter_motion_est.c mlt-0.7.2/src/modules/motion_est/filter_motion_est.c --- mlt-0.6.2/src/modules/motion_est/filter_motion_est.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/motion_est/filter_motion_est.c 2011-05-02 05:59:12.000000000 +0000 @@ -782,10 +782,11 @@ // Get the filter mlt_filter filter = mlt_frame_pop_service( frame ); + mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); + // Get the motion_est context object struct motion_est_context_s *c = mlt_properties_get_data( MLT_FILTER_PROPERTIES( filter ), "context", NULL); - // Get the new image and frame number *format = mlt_image_yuv422; int error = mlt_frame_get_image( frame, image, format, width, height, 1 ); @@ -1030,7 +1031,6 @@ // Remember which frame this is c->former_frame_position = c->current_frame_position; - mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "motion_est.macroblock_width", c->mb_w ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "motion_est.macroblock_height", c->mb_h ); mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "motion_est.left_mb", c->left_mb ); @@ -1043,6 +1043,7 @@ fprintf(stderr, " in frame %d:%d usec\n", c->current_frame_position, difference); #endif + mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); return error; } diff -Nru mlt-0.6.2/src/modules/motion_est/Makefile mlt-0.7.2/src/modules/motion_est/Makefile --- mlt-0.6.2/src/modules/motion_est/Makefile 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/motion_est/Makefile 2011-05-02 05:59:12.000000000 +0000 @@ -4,7 +4,7 @@ include ../../../config.mak -TARGET = ../libmltmotion_est.so +TARGET = ../libmltmotion_est$(LIBSUF) OBJS = factory.o \ filter_motion_est.o \ diff -Nru mlt-0.6.2/src/modules/motion_est/producer_slowmotion.c mlt-0.7.2/src/modules/motion_est/producer_slowmotion.c --- mlt-0.6.2/src/modules/motion_est/producer_slowmotion.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/motion_est/producer_slowmotion.c 2011-05-02 05:59:12.000000000 +0000 @@ -261,7 +261,7 @@ } *image = output; - mlt_properties_set_data( frame_properties, "image", output, size, NULL, NULL ); + mlt_frame_set_image( this, output, size, NULL ); // Make sure that no further scaling is done mlt_properties_set( frame_properties, "rescale.interps", "none" ); @@ -358,7 +358,7 @@ mlt_producer producer_slowmotion_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) { - mlt_producer this = mlt_producer_new( ); + mlt_producer this = mlt_producer_new( profile ); // Wrap the loader mlt_producer real_producer = mlt_factory_producer( profile, NULL, arg ); diff -Nru mlt-0.6.2/src/modules/normalize/filter_volume.c mlt-0.7.2/src/modules/normalize/filter_volume.c --- mlt-0.6.2/src/modules/normalize/filter_volume.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/normalize/filter_volume.c 2011-05-02 05:59:12.000000000 +0000 @@ -171,12 +171,8 @@ // Get the properties from the filter mlt_properties filter_props = MLT_FILTER_PROPERTIES( this ); - // Get the properties of the a frame - mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); - // Get the frame's filter instance properties - char *name = mlt_properties_get( filter_props, "_unique_id" ); - mlt_properties instance_props = mlt_properties_get_data( properties, name, NULL ); + mlt_properties instance_props = mlt_frame_unique_properties( frame, MLT_FILTER_SERVICE( this ) ); // Get the parameters double gain = mlt_properties_get_double( instance_props, "gain" ); @@ -201,6 +197,8 @@ int samplemax = (1 << (bytes_per_samp * 8 - 1)) - 1; int samplemin = -samplemax - 1; + mlt_service_lock( MLT_FILTER_SERVICE( this ) ); + if ( normalise ) { int window = mlt_properties_get_int( filter_props, "window" ); @@ -252,6 +250,8 @@ mlt_properties_set_double( filter_props, "_previous_gain", gain ); mlt_properties_set_position( filter_props, "_last_position", current_position ); + mlt_service_unlock( MLT_FILTER_SERVICE( this ) ); + // Ramp from the previous gain to the current gain = previous_gain; @@ -290,12 +290,8 @@ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { - mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); mlt_properties filter_props = MLT_FILTER_PROPERTIES( this ); - mlt_properties instance_props = mlt_properties_new(); - char *name = mlt_properties_get( filter_props, "_unique_id" ); - - mlt_properties_set_data( properties, name, instance_props, 0, (mlt_destructor) mlt_properties_close, NULL ); + mlt_properties instance_props = mlt_frame_unique_properties( frame, MLT_FILTER_SERVICE( this ) ); double gain = 1.0; // no adjustment @@ -323,12 +319,6 @@ // If there is an end adjust gain to the range if ( mlt_properties_get( filter_props, "end" ) != NULL ) { - // Determine the time position of this frame in the transition duration - mlt_position in = mlt_filter_get_in( this ); - mlt_position out = mlt_filter_get_out( this ); - mlt_position time = mlt_frame_get_position( frame ); - double position = ( double )( time - in ) / ( double )( out - in + 1 ); - double end = -1; char *p = mlt_properties_get( filter_props, "end" ); if ( strcmp( p, "" ) != 0 ) @@ -344,7 +334,7 @@ end = fabs( end ); if ( end != -1 ) - gain += ( end - gain ) * position; + gain += ( end - gain ) * mlt_filter_get_progress( this, frame ); } } } @@ -423,12 +413,7 @@ // If there is an end adjust gain to the range if ( mlt_properties_get( filter_props, "end" ) != NULL ) { - // Determine the time position of this frame in the transition duration - mlt_position in = mlt_filter_get_in( this ); - mlt_position out = mlt_filter_get_out( this ); - mlt_position time = mlt_frame_get_position( frame ); - double position = ( double )( time - in ) / ( double )( out - in + 1 ); - amplitude *= position; + amplitude *= mlt_filter_get_progress( this, frame ); } mlt_properties_set_int( instance_props, "normalise", 1 ); mlt_properties_set_double( instance_props, "amplitude", amplitude ); diff -Nru mlt-0.6.2/src/modules/oldfilm/filter_dust.c mlt-0.7.2/src/modules/oldfilm/filter_dust.c --- mlt-0.6.2/src/modules/oldfilm/filter_dust.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/oldfilm/filter_dust.c 2011-05-02 05:59:12.000000000 +0000 @@ -66,11 +66,6 @@ int maxdia = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "maxdiameter" ); int maxcount = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "maxcount" ); - mlt_position in = mlt_filter_get_in( filter ); - mlt_position out = mlt_filter_get_out( filter ); - mlt_position time = mlt_frame_get_position( this ); - double position = ( double )( time - in ) / ( double )( out - in + 1 ); - *format = mlt_image_yuv422; int error = mlt_frame_get_image( this, image, format, width, height, 1 ); // load svg @@ -84,8 +79,12 @@ if (!maxcount) return 0; + + double position = mlt_filter_get_progress( filter, this ); srand(position*10000); + mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); + int im=rand()%maxcount; int piccount=mlt_properties_count(direntries); while (im-- && piccount){ @@ -155,6 +154,9 @@ overlay_image ( *image , *width, *height , luma_image , dx , mlt_properties_get_int ( properties , cachedy ) , alpha , x1 , y1 , updown , mirror ); } } + + mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); + if (piccount>0 ) return 0; if ( error == 0 && *image ) diff -Nru mlt-0.6.2/src/modules/oldfilm/filter_grain.c mlt-0.7.2/src/modules/oldfilm/filter_grain.c --- mlt-0.6.2/src/modules/oldfilm/filter_grain.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/oldfilm/filter_grain.c 2011-05-02 05:59:12.000000000 +0000 @@ -38,10 +38,7 @@ int h = *height; int w = *width; - mlt_position in = mlt_filter_get_in( filter ); - mlt_position out = mlt_filter_get_out( filter ); - mlt_position time = mlt_frame_get_position( this ); - double position = ( double )( time - in ) / ( double )( out - in + 1 ); + double position = mlt_filter_get_progress( filter, this ); srand(position*10000); int noise = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "noise" ); diff -Nru mlt-0.6.2/src/modules/oldfilm/filter_lines.c mlt-0.7.2/src/modules/oldfilm/filter_lines.c --- mlt-0.6.2/src/modules/oldfilm/filter_lines.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/oldfilm/filter_lines.c 2011-05-02 05:59:12.000000000 +0000 @@ -44,14 +44,14 @@ char buf[256]; char typebuf[256]; - mlt_position in = mlt_filter_get_in( filter ); - mlt_position out = mlt_filter_get_out( filter ); - mlt_position time = mlt_frame_get_position( this ); - double position = ( double )( time - in ) / ( double )( out - in + 1 ); - srand(position*10000); if (!width_line) return 0; + + double position = mlt_filter_get_progress( filter, this ); + srand(position*10000); + mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); + while (num--){ int type=(rand()%3)+1; int x1=(double)w*rand()/RAND_MAX; @@ -105,6 +105,7 @@ mlt_properties_set_int(MLT_FILTER_PROPERTIES( filter ),buf,x1); } mlt_properties_set_double(MLT_FILTER_PROPERTIES( filter ),"last_oldfilm_line_pos",position); + mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); } return error; diff -Nru mlt-0.6.2/src/modules/oldfilm/filter_oldfilm.c mlt-0.7.2/src/modules/oldfilm/filter_oldfilm.c --- mlt-0.6.2/src/modules/oldfilm/filter_oldfilm.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/oldfilm/filter_oldfilm.c 2011-05-02 05:59:12.000000000 +0000 @@ -53,10 +53,7 @@ int x=0; int y=0; - mlt_position in = mlt_filter_get_in( filter ); - mlt_position out = mlt_filter_get_out( filter ); - mlt_position time = mlt_frame_get_position( this ); - double position = ( double )( time - in ) / ( double )( out - in + 1 ); + double position = mlt_filter_get_progress( filter, this ); srand(position*10000); int delta = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "delta" ); diff -Nru mlt-0.6.2/src/modules/oldfilm/filter_vignette.c mlt-0.7.2/src/modules/oldfilm/filter_vignette.c --- mlt-0.6.2/src/modules/oldfilm/filter_vignette.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/oldfilm/filter_vignette.c 2011-05-02 05:59:12.000000000 +0000 @@ -55,7 +55,7 @@ { float smooth, radius, cx, cy, opac; mlt_properties filter_props = MLT_FILTER_PROPERTIES( filter ) ; - mlt_position pos = mlt_properties_get_position( filter_props, "_pos" ); + mlt_position pos = mlt_filter_get_position( filter, this ); smooth = geometry_to_float ( mlt_properties_get( filter_props , "smooth" ) , pos ) * 100.0 ; radius = geometry_to_float ( mlt_properties_get( filter_props , "radius" ) , pos ) * *width; @@ -103,12 +103,7 @@ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { - mlt_frame_push_service( frame, this ); - - // Determine the time position of this frame - mlt_properties_set_position( MLT_FILTER_PROPERTIES( this ), "_pos", mlt_frame_get_position( frame ) - mlt_filter_get_in( this ) ); - mlt_frame_push_get_image( frame, filter_get_image ); return frame; } diff -Nru mlt-0.6.2/src/modules/plus/filter_affine.c mlt-0.7.2/src/modules/plus/filter_affine.c --- mlt-0.6.2/src/modules/plus/filter_affine.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/plus/filter_affine.c 2011-05-02 05:59:12.000000000 +0000 @@ -44,6 +44,7 @@ // Only process if we have no error and a valid colour space if ( error == 0 ) { + mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); mlt_producer producer = mlt_properties_get_data( properties, "producer", NULL ); mlt_transition transition = mlt_properties_get_data( properties, "transition", NULL ); mlt_frame a_frame = NULL; @@ -65,8 +66,7 @@ if ( producer != NULL && transition != NULL ) { - char *name = mlt_properties_get( properties, "_unique_id" ); - mlt_position position = mlt_properties_get_position( MLT_FRAME_PROPERTIES( this ), name ); + mlt_position position = mlt_filter_get_position( filter, this ); mlt_properties frame_properties = MLT_FRAME_PROPERTIES( this ); mlt_position in = mlt_filter_get_in( filter ); mlt_position out = mlt_filter_get_out( filter ); @@ -76,12 +76,12 @@ mlt_properties_set_position( MLT_PRODUCER_PROPERTIES( producer ), "length", out - in + 1 ); mlt_producer_set_in_and_out( producer, in, out ); } - mlt_producer_seek( producer, position - in ); + mlt_producer_seek( producer, in + position ); mlt_frame_set_position( this, position ); mlt_properties_pass( MLT_PRODUCER_PROPERTIES( producer ), properties, "producer." ); mlt_properties_pass( MLT_TRANSITION_PROPERTIES( transition ), properties, "transition." ); mlt_service_get_frame( MLT_PRODUCER_SERVICE( producer ), &a_frame, 0 ); - mlt_frame_set_position( a_frame, position ); + mlt_frame_set_position( a_frame, in + position ); // mlt_properties_set_int( MLT_FRAME_PROPERTIES( a_frame ), "distort", 1 ); // Special case - aspect_ratio = 0 @@ -92,6 +92,7 @@ mlt_properties_set_double( MLT_FRAME_PROPERTIES( a_frame ), "consumer_aspect_ratio", consumer_ar ); // Add the affine transition onto the frame stack + mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); mlt_transition_process( transition, a_frame, this ); if (mlt_properties_get_int( properties, "use_normalised" )) @@ -103,8 +104,12 @@ mlt_frame_get_image( a_frame, image, format, width, height, writable ); mlt_properties_set_data( frame_properties, "affine_frame", a_frame, 0, (mlt_destructor)mlt_frame_close, NULL ); - mlt_properties_set_data( frame_properties, "image", *image, *width * *height * 4, NULL, NULL ); - mlt_properties_set_data( frame_properties, "alpha", mlt_frame_get_alpha_mask( a_frame ), *width * *height, NULL, NULL ); + mlt_frame_set_image( this, *image, *width * *height * 4, NULL ); + mlt_frame_set_alpha( this, mlt_frame_get_alpha_mask( a_frame ), *width * *height, NULL ); + } + else + { + mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); } } @@ -116,15 +121,6 @@ static mlt_frame filter_process( mlt_filter this, mlt_frame frame ) { - // Get the properties of the frame - mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); - - // Get a unique name to store the frame position - char *name = mlt_properties_get( MLT_FILTER_PROPERTIES( this ), "_unique_id" ); - - // Assign the current position to the name - mlt_properties_set_position( properties, name, mlt_frame_get_position( frame ) ); - // Push the frame filter mlt_frame_push_service( frame, this ); mlt_frame_push_get_image( frame, filter_get_image ); @@ -141,7 +137,7 @@ if ( this != NULL ) { this->process = filter_process; - mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "background", "colour:black" ); + mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "background", arg ? arg : "colour:black" ); } return this; } diff -Nru mlt-0.6.2/src/modules/plus/filter_charcoal.c mlt-0.7.2/src/modules/plus/filter_charcoal.c --- mlt-0.6.2/src/modules/plus/filter_charcoal.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/plus/filter_charcoal.c 2011-05-02 05:59:12.000000000 +0000 @@ -138,7 +138,7 @@ *image = temp; // Store new and destroy old - mlt_properties_set_data( MLT_FRAME_PROPERTIES( this ), "image", *image, *width * *height * 2, mlt_pool_release, NULL ); + mlt_frame_set_image( this, *image, *width * *height * 2, mlt_pool_release ); } return error; diff -Nru mlt-0.6.2/src/modules/plus/transition_affine.c mlt-0.7.2/src/modules/plus/transition_affine.c --- mlt-0.6.2/src/modules/plus/transition_affine.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/plus/transition_affine.c 2011-05-02 05:59:12.000000000 +0000 @@ -63,13 +63,8 @@ // Try to fetch it first mlt_geometry geometry = mlt_properties_get_data( properties, store, NULL ); - // Get the in and out position - int always_active = mlt_properties_get_int( properties, "always_active" ); - mlt_position in = mlt_transition_get_in( this ); - mlt_position out = !always_active ? mlt_transition_get_out( this ) : -1; - // Determine length and obtain cycle - int length = out - in + 1; + mlt_position length = mlt_transition_get_length( this ); double cycle = mlt_properties_get_double( properties, "cycle" ); // Allow a geometry repeat cycle @@ -347,11 +342,14 @@ float shear_x = composite_calculate_key( this, "shear_x", "shear_x_info", 360, position ); float shear_y = composite_calculate_key( this, "shear_y", "shear_y_info", 360, position ); float shear_z = composite_calculate_key( this, "shear_z", "shear_z_info", 360, position ); - + float o_x = composite_calculate_key( this, "ox", "ox_info", 0, position ); + float o_y = composite_calculate_key( this, "oy", "oy_info", 0, position ); + affine_rotate_x( affine->matrix, rotate_x ); affine_rotate_y( affine->matrix, rotate_y ); affine_rotate_z( affine->matrix, rotate_z ); affine_shear( affine->matrix, shear_x, shear_y, shear_z ); + affine_offset( affine->matrix, o_x, o_y ); } } @@ -381,19 +379,18 @@ int b_width; int b_height; - // Get the unique name to retrieve the frame position - char *name = mlt_properties_get( properties, "_unique_id" ); + // Assign the current position + mlt_position position = mlt_transition_get_position( this, a_frame ); - // Assign the current position to the name - mlt_position position = mlt_properties_get_position( a_props, name ); - - mlt_properties props = mlt_properties_get_data( b_props, "_producer", NULL ); - int always_active = mlt_properties_get_int( properties, "always_active" ); - - mlt_position in = !always_active ? mlt_properties_get_position( properties, "in" ) : mlt_properties_get_int( props, "in" ); - mlt_position out = !always_active ? mlt_properties_get_position( properties, "out" ) : mlt_properties_get_int( props, "out" ); int mirror = mlt_properties_get_position( properties, "mirror" ); - int length = out - in + 1; + int length = mlt_transition_get_length( this ); + if ( mlt_properties_get_int( properties, "always_active" ) ) + { + mlt_properties props = mlt_properties_get_data( b_props, "_producer", NULL ); + mlt_position in = mlt_properties_get_int( props, "in" ); + mlt_position out = mlt_properties_get_int( props, "out" ); + length = out - in + 1; + } // Obtain the normalised width and height from the a_frame int normalised_width = mlt_properties_get_int( a_props, "normalised_width" ); @@ -412,7 +409,9 @@ mlt_frame_get_image( a_frame, image, format, width, height, 1 ); // Calculate the region now + mlt_service_lock( MLT_TRANSITION_SERVICE( this ) ); composite_calculate( this, &result, normalised_width, normalised_height, ( float )position ); + mlt_service_unlock( MLT_TRANSITION_SERVICE( this ) ); // Fetch the b frame image result.w = ( result.w * *width / normalised_width ); @@ -550,13 +549,6 @@ static mlt_frame transition_process( mlt_transition transition, mlt_frame a_frame, mlt_frame b_frame ) { - // Get a unique name to store the frame position - char *name = mlt_properties_get( MLT_TRANSITION_PROPERTIES( transition ), "_unique_id" ); - - // Assign the current position to the name - mlt_properties a_props = MLT_FRAME_PROPERTIES( a_frame ); - mlt_properties_set_position( a_props, name, mlt_frame_get_position( a_frame ) - mlt_transition_get_in( transition ) ); - // Push the transition on to the frame mlt_frame_push_service( a_frame, transition ); diff -Nru mlt-0.6.2/src/modules/qimage/configure mlt-0.7.2/src/modules/qimage/configure --- mlt-0.6.2/src/modules/qimage/configure 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/qimage/configure 2011-05-02 05:59:12.000000000 +0000 @@ -109,7 +109,7 @@ then # test if we have a Qt3 or Qt4 - if [ -f "$qimage_libdir/libQtCore.so" ] || [ -d "$qimage_libdir/QtGui.framework" ] && [ "$force_qt3" = "" ] + if [ -f "$qimage_libdir/libQtCore.so" ] || [ -d "$qimage_libdir/QtGui.framework" ] || [ -f "$qimage_libdir/libQtCore4.a" ] && [ "$force_qt3" = "" ] then echo "Qt version 4.x detected, will compile Qt4 qimage producer" qt4_found=true @@ -127,9 +127,13 @@ then echo QTCXXFLAGS=$(pkg-config --cflags QtCore QtGui QtXml QtSvg ) >> config.mak echo QTLIBS=$(pkg-config --libs QtCore QtGui QtXml QtSvg) >> config.mak + elif [ -f "$qimage_libdir/libQtCore4.a" ] + then + echo QTCXXFLAGS=-I$qimage_includedir >> config.mak + echo QTLIBS=-enable-auto-import -L$qimage_libdir -lQtCore4 -lQtGui4 -lQtXml4 -lQtSvg4 >> config.mak else echo QTCXXFLAGS=-I$qimage_includedir >> config.mak - echo QTLIBS=-L$qimage_libdir -lQtCore -lQtGui -lQtXml -lQtSvg >> config.mak + echo QTLIBS=-L$qimage_libdir -lQtCore -lQtGui -lQtXml -lQtSvg >> config.mak fi else if [ -d "$kde_includedir" ] diff -Nru mlt-0.6.2/src/modules/qimage/Makefile mlt-0.7.2/src/modules/qimage/Makefile --- mlt-0.6.2/src/modules/qimage/Makefile 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/qimage/Makefile 2011-05-02 05:59:12.000000000 +0000 @@ -13,7 +13,6 @@ CXXFLAGS += $(CFLAGS) $(QTCXXFLAGS) $(EXIFCXXFLAGS) -Wno-deprecated LDFLAGS += $(QTLIBS) $(EXIFLIBS) -LDFLAGS += -lstdc++ ifdef USE_KDE LDFLAGS += -lkio @@ -27,7 +26,7 @@ $(CXX) $(SHFLAGS) -o $@ $(OBJS) $(CPPOBJS) $(LDFLAGS) depend: $(SRCS) - $(CC) -MM $(CFLAGS) $(QTCXXFLAGS) $^ 1>.depend + $(CXX) -MM $(CXXFLAGS) $^ 1>.depend distclean: clean rm -f .depend config.h config.mak diff -Nru mlt-0.6.2/src/modules/qimage/producer_kdenlivetitle.c mlt-0.7.2/src/modules/qimage/producer_kdenlivetitle.c --- mlt-0.6.2/src/modules/qimage/producer_kdenlivetitle.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/qimage/producer_kdenlivetitle.c 2011-05-02 05:59:12.000000000 +0000 @@ -60,8 +60,7 @@ *width = mlt_properties_get_int( properties, "rescale_width" ); *height = mlt_properties_get_int( properties, "rescale_height" ); - /* Allocate the image */ - int size = *width * ( *height ) * 4; + mlt_service_lock( MLT_PRODUCER_SERVICE( &this->parent ) ); /* Allocate the image */ *format = mlt_image_rgb24a; @@ -84,16 +83,15 @@ uint8_t *image_copy = mlt_pool_alloc( image_size ); memcpy( image_copy, this->current_image, image_size ); // Now update properties so we free the copy after - mlt_properties_set_data( properties, "image", image_copy, image_size, mlt_pool_release, NULL ); + mlt_frame_set_image( frame, image_copy, image_size, mlt_pool_release ); // We're going to pass the copy on *buffer = image_copy; - - /* Update the frame */ - mlt_properties_set_data( properties, "image", *buffer, size, mlt_pool_release, NULL ); mlt_log_debug( MLT_PRODUCER_SERVICE( &this->parent ), "width:%d height:%d %s\n", *width, *height, mlt_image_format_name( *format ) ); } + mlt_service_unlock( MLT_PRODUCER_SERVICE( &this->parent ) ); + return 0; } diff -Nru mlt-0.6.2/src/modules/qimage/producer_qimage.c mlt-0.7.2/src/modules/qimage/producer_qimage.c --- mlt-0.6.2/src/modules/qimage/producer_qimage.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/qimage/producer_qimage.c 2011-05-02 05:59:12.000000000 +0000 @@ -69,7 +69,6 @@ if ( frame ) { mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame ); - pthread_mutex_init( &this->mutex, NULL ); mlt_properties_set_data( frame_properties, "producer_qimage", this, 0, NULL, NULL ); mlt_frame_set_position( frame, mlt_producer_position( producer ) ); mlt_properties_set_position( frame_properties, "qimage_position", mlt_producer_position( producer ) ); @@ -82,6 +81,8 @@ producer_close( producer ); producer = NULL; } + if ( producer ) + pthread_mutex_init( &this->mutex, NULL ); return producer; } free( this ); @@ -96,30 +97,7 @@ // Read xml string if ( strstr( filename, " -1 ) - { - // Write the svg into the temp file - ssize_t remaining_bytes; - char *xml = filename; - - // Strip leading crap - while ( xml[0] != '<' ) - xml++; - - remaining_bytes = strlen( xml ); - while ( remaining_bytes > 0 ) - remaining_bytes -= write( fd, xml + strlen( xml ) - remaining_bytes, remaining_bytes ); - close( fd ); - - mlt_properties_set( this->filenames, "0", fullname ); - - // Teehe - when the producer closes, delete the temp file and the space allo - mlt_properties_set_data( producer_properties, "__temporary_file__", fullname, 0, ( mlt_destructor )unlink, NULL ); - } + make_tempfile( this, filename ); } // Obtain filenames else if ( strchr( filename, '%' ) != NULL ) @@ -183,6 +161,8 @@ *width = mlt_properties_get_int( properties, "rescale_width" ); *height = mlt_properties_get_int( properties, "rescale_height" ); + mlt_service_lock( MLT_PRODUCER_SERVICE( &this->parent ) ); + // Refresh the image refresh_qimage( this, frame, *width, *height ); @@ -199,7 +179,7 @@ uint8_t *image_copy = mlt_pool_alloc( image_size ); memcpy( image_copy, this->current_image, image_size ); // Now update properties so we free the copy after - mlt_properties_set_data( properties, "image", image_copy, image_size, mlt_pool_release, NULL ); + mlt_frame_set_image( frame, image_copy, image_size, mlt_pool_release ); // We're going to pass the copy on *buffer = image_copy; *format = this->has_alpha ? mlt_image_rgb24a : mlt_image_rgb24; @@ -214,6 +194,7 @@ // Release references and locks pthread_mutex_unlock( &this->mutex ); mlt_cache_item_close( this->image_cache ); + mlt_service_unlock( MLT_PRODUCER_SERVICE( &this->parent ) ); return error; } diff -Nru mlt-0.6.2/src/modules/qimage/qimage_wrapper.cpp mlt-0.7.2/src/modules/qimage/qimage_wrapper.cpp --- mlt-0.6.2/src/modules/qimage/qimage_wrapper.cpp 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/qimage/qimage_wrapper.cpp 2011-05-02 05:59:12.000000000 +0000 @@ -40,6 +40,7 @@ #include #include #include +#include #endif #ifdef USE_EXIF @@ -186,6 +187,9 @@ exif_data_unref(d); } + // Remember EXIF value, might be useful for someone + mlt_properties_set_int( producer_props, "_exif_orientation" , exif_orientation ); + if ( exif_orientation > 1 ) { // Rotate image according to exif data @@ -260,9 +264,14 @@ #ifdef USE_QT4 // Note - the original qimage is already safe and ready for destruction + if ( qimage->depth() == 1 ) + { + QImage temp = qimage->convertToFormat( QImage::Format_RGB32 ); + delete qimage; + qimage = new QImage( temp ); + } QImage scaled = interp == 0 ? qimage->scaled( QSize( width, height ) ) : qimage->scaled( QSize(width, height), Qt::IgnoreAspectRatio, Qt::SmoothTransformation ); - QImage temp; self->has_alpha = scaled.hasAlphaChannel(); #endif @@ -341,4 +350,31 @@ g_mutex.unlock(); } +extern void make_tempfile( producer_qimage self, const char *xml ) +{ + // Generate a temporary file for the svg + QTemporaryFile tempFile( "mlt.XXXXXX" ); + + tempFile.setAutoRemove( false ); + if ( tempFile.open() ) + { + // Write the svg into the temp file + char *fullname = tempFile.fileName().toUtf8().data(); + + // Strip leading crap + while ( xml[0] != '<' ) + xml++; + + qint64 remaining_bytes = strlen( xml ); + while ( remaining_bytes > 0 ) + remaining_bytes -= tempFile.write( xml + strlen( xml ) - remaining_bytes, remaining_bytes ); + tempFile.close(); + + mlt_properties_set( self->filenames, "0", fullname ); + + mlt_properties_set_data( MLT_PRODUCER_PROPERTIES( &self->parent ), "__temporary_file__", + fullname, 0, ( mlt_destructor )unlink, NULL ); + } +} + } // extern "C" diff -Nru mlt-0.6.2/src/modules/qimage/qimage_wrapper.h mlt-0.7.2/src/modules/qimage/qimage_wrapper.h --- mlt-0.6.2/src/modules/qimage/qimage_wrapper.h 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/qimage/qimage_wrapper.h 2011-05-02 05:59:12.000000000 +0000 @@ -51,6 +51,8 @@ typedef struct producer_qimage_s *producer_qimage; extern void refresh_qimage( producer_qimage, mlt_frame, int width, int height ); +extern void make_tempfile( producer_qimage, const char *xml ); + #ifdef USE_KDE extern void init_qimage(); #endif diff -Nru mlt-0.6.2/src/modules/resample/filter_resample.c mlt-0.7.2/src/modules/resample/filter_resample.c --- mlt-0.6.2/src/modules/resample/filter_resample.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/resample/filter_resample.c 2011-05-02 05:59:12.000000000 +0000 @@ -27,7 +27,9 @@ #include #include -#define BUFFER_LEN 20480 +// BUFFER_LEN is based on a maximum of 96KHz, 5 fps, 8 channels +// TODO: dynamically allocate larger buffer size +#define BUFFER_LEN ((96000/5) * 8 * sizeof(float)) #define RESAMPLE_TYPE SRC_SINC_FASTEST /** Get the audio. @@ -45,24 +47,75 @@ int output_rate = mlt_properties_get_int( filter_properties, "frequency" ); int error = 0; + // Used to return number of channels in the source + int channels_avail = *channels; + // If no resample frequency is specified, default to requested value if ( output_rate == 0 ) output_rate = *frequency; // Get the producer's audio - if ( *format != mlt_audio_s16 ) - *format = mlt_audio_float; - mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); + mlt_frame_get_audio( frame, buffer, format, frequency, &channels_avail, samples ); + + if ( channels_avail < *channels ) + { + int size = mlt_audio_format_size( *format, *samples, *channels ); + int16_t *new_buffer = mlt_pool_alloc( size ); + int sample_size_factor = mlt_audio_format_size( *format, 1, 1 ) / sizeof( *new_buffer ); + int i, j, k; + + // Duplicate the existing channels + for ( i = 0; i < *samples; i++ ) + { + for ( j = 0; j < *channels; j++ ) + { + new_buffer[ ( ( i * *channels ) + j ) * sample_size_factor ] + = ((int16_t*)(*buffer))[ ( ( i * channels_avail ) + k ) * sample_size_factor ]; + k = ( k + 1 ) % channels_avail; + } + } + + // Update the audio buffer now - destroys the old + mlt_frame_set_audio( frame, new_buffer, *format, size, mlt_pool_release ); + + *buffer = new_buffer; + } + else if ( channels_avail > *channels ) + { + int size = mlt_audio_format_size( *format, *samples, *channels ); + int16_t *new_buffer = mlt_pool_alloc( size ); + int sample_size_factor = mlt_audio_format_size( *format, 1, 1 ) / sizeof( *new_buffer ); + int i, j; + + // Drop all but the first *channels + for ( i = 0; i < *samples; i++ ) + { + for ( j = 0; j < *channels; j++ ) + new_buffer[ ( ( i * *channels ) + j ) * sample_size_factor ] + = ((int16_t*)(*buffer))[ ( ( i * channels_avail ) + j ) * sample_size_factor ]; + } + + // Update the audio buffer now - destroys the old + mlt_frame_set_audio( frame, new_buffer, *format, size, mlt_pool_release ); + + *buffer = new_buffer; + } // Return now if no work to do if ( output_rate != *frequency ) { + mlt_log_verbose( MLT_FILTER_SERVICE(filter), "channels %d samples %d frequency %d -> %d\n", + *channels, *samples, *frequency, output_rate ); + // Do not convert to float unless we need to change the rate if ( *format != mlt_audio_float ) { *format = mlt_audio_float; mlt_frame_get_audio( frame, buffer, format, frequency, channels, samples ); } + + mlt_service_lock( MLT_FILTER_SERVICE(filter) ); + float *input_buffer = mlt_properties_get_data( filter_properties, "input_buffer", NULL ); float *output_buffer = mlt_properties_get_data( filter_properties, "output_buffer", NULL ); SRC_DATA data; @@ -119,9 +172,13 @@ // Update output variables *samples = data.output_frames_gen; *frequency = output_rate; + } else + { mlt_log_error( MLT_FILTER_SERVICE( filter ), "%s %d,%d,%d\n", src_strerror( error ), *frequency, *samples, output_rate ); + } + mlt_service_unlock( MLT_FILTER_SERVICE(filter) ); } return error; diff -Nru mlt-0.6.2/src/modules/rotoscoping/cJSON.c mlt-0.7.2/src/modules/rotoscoping/cJSON.c --- mlt-0.6.2/src/modules/rotoscoping/cJSON.c 1970-01-01 00:00:00.000000000 +0000 +++ mlt-0.7.2/src/modules/rotoscoping/cJSON.c 2011-05-02 05:59:12.000000000 +0000 @@ -0,0 +1,497 @@ +/* + Copyright (c) 2009 Dave Gamble + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +// cJSON +// JSON parser in C. + +#include +#include +#include +#include +#include +#include +#include +#include "cJSON.h" + +static int cJSON_strcasecmp(const char *s1,const char *s2) +{ + if (!s1) return (s1==s2)?0:1;if (!s2) return 1; + for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0; + return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2); +} + +static void *(*cJSON_malloc)(size_t sz) = malloc; +static void (*cJSON_free)(void *ptr) = free; + +static char* cJSON_strdup(const char* str) +{ + size_t len; + char* copy; + + len = strlen(str) + 1; + if (!(copy = (char*)cJSON_malloc(len))) return 0; + memcpy(copy,str,len); + return copy; +} + +void cJSON_InitHooks(cJSON_Hooks* hooks) +{ + if (!hooks) { /* Reset hooks */ + cJSON_malloc = malloc; + cJSON_free = free; + return; + } + + cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc; + cJSON_free = (hooks->free_fn)?hooks->free_fn:free; +} + +// Internal constructor. +static cJSON *cJSON_New_Item() +{ + cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); + if (node) memset(node,0,sizeof(cJSON)); + return node; +} + +// Delete a cJSON structure. +void cJSON_Delete(cJSON *c) +{ + cJSON *next; + while (c) + { + next=c->next; + if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child); + if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring); + if (c->string) cJSON_free(c->string); + cJSON_free(c); + c=next; + } +} + +// Parse the input text to generate a number, and populate the result into item. +static const char *parse_number(cJSON *item,const char *num) +{ + double n=0,sign=1,scale=0;int subscale=0,signsubscale=1; + + // Could use sscanf for this? + if (*num=='-') sign=-1,num++; // Has sign? + if (*num=='0') num++; // is zero + if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); // Number? + if (*num=='.') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} // Fractional part? + if (*num=='e' || *num=='E') // Exponent? + { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; // With sign? + while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); // Number? + } + + n=sign*n*pow(10.0,(scale+subscale*signsubscale)); // number = +/- number.fraction * 10^+/- exponent + + item->valuedouble=n; + item->valueint=(int)n; + item->type=cJSON_Number; + return num; +} + +// Render the number nicely from the given item into a string. +static char *print_number(cJSON *item) +{ + char *str; + double d=item->valuedouble; + if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN) + { + str=(char*)cJSON_malloc(21); // 2^64+1 can be represented in 21 chars. + if (str) sprintf(str,"%d",item->valueint); + } + else + { + str=(char*)cJSON_malloc(64); // This is a nice tradeoff. + if (str) + { + if (fabs(floor(d)-d)<=DBL_EPSILON) sprintf(str,"%.0f",d); + else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); + else sprintf(str,"%f",d); + } + } + return str; +} + +// Parse the input text into an unescaped cstring, and populate item. +static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; +static const char *parse_string(cJSON *item,const char *str) +{ + const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc; + if (*str!='\"') return 0; // not a string! + + while (*ptr!='\"' && (unsigned char)*ptr>31 && ++len) if (*ptr++ == '\\') ptr++; // Skip escaped quotes. + + out=(char*)cJSON_malloc(len+1); // This is how long we need for the string, roughly. + if (!out) return 0; + + ptr=str+1;ptr2=out; + while (*ptr!='\"' && (unsigned char)*ptr>31) + { + if (*ptr!='\\') *ptr2++=*ptr++; + else + { + ptr++; + switch (*ptr) + { + case 'b': *ptr2++='\b'; break; + case 'f': *ptr2++='\f'; break; + case 'n': *ptr2++='\n'; break; + case 'r': *ptr2++='\r'; break; + case 't': *ptr2++='\t'; break; + case 'u': // transcode utf16 to utf8. DOES NOT SUPPORT SURROGATE PAIRS CORRECTLY. + sscanf(ptr+1,"%4x",&uc); // get the unicode char. + len=3;if (uc<0x80) len=1;else if (uc<0x800) len=2;ptr2+=len; + + switch (len) { + case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; + case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; + case 1: *--ptr2 =(uc | firstByteMark[len]); + } + ptr2+=len;ptr+=4; + break; + default: *ptr2++=*ptr; break; + } + ptr++; + } + } + *ptr2=0; + if (*ptr=='\"') ptr++; + item->valuestring=out; + item->type=cJSON_String; + return ptr; +} + +// Render the cstring provided to an escaped version that can be printed. +static char *print_string_ptr(const char *str) +{ + const char *ptr;char *ptr2,*out;int len=0; + + if (!str) return cJSON_strdup(""); + ptr=str;while (*ptr && ++len) {if ((unsigned char)*ptr<32 || *ptr=='\"' || *ptr=='\\') len++;ptr++;} + + out=(char*)cJSON_malloc(len+3); + if (!out) return 0; + + ptr2=out;ptr=str; + *ptr2++='\"'; + while (*ptr) + { + if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++; + else + { + *ptr2++='\\'; + switch (*ptr++) + { + case '\\': *ptr2++='\\'; break; + case '\"': *ptr2++='\"'; break; + case '\b': *ptr2++='b'; break; + case '\f': *ptr2++='f'; break; + case '\n': *ptr2++='n'; break; + case '\r': *ptr2++='r'; break; + case '\t': *ptr2++='t'; break; + default: ptr2--; break; // eviscerate with prejudice. + } + } + } + *ptr2++='\"';*ptr2++=0; + return out; +} +// Invote print_string_ptr (which is useful) on an item. +static char *print_string(cJSON *item) {return print_string_ptr(item->valuestring);} + +// Predeclare these prototypes. +static const char *parse_value(cJSON *item,const char *value); +static char *print_value(cJSON *item,int depth,int fmt); +static const char *parse_array(cJSON *item,const char *value); +static char *print_array(cJSON *item,int depth,int fmt); +static const char *parse_object(cJSON *item,const char *value); +static char *print_object(cJSON *item,int depth,int fmt); + +// Utility to jump whitespace and cr/lf +static const char *skip(const char *in) {while (in && (unsigned char)*in<=32) in++; return in;} + +// Parse an object - create a new root, and populate. +cJSON *cJSON_Parse(const char *value) +{ + cJSON *c=cJSON_New_Item(); + if (!c) return 0; /* memory fail */ + + if (!parse_value(c,skip(value))) {cJSON_Delete(c);return 0;} + return c; +} + +// Render a cJSON item/entity/structure to text. +char *cJSON_Print(cJSON *item) {return print_value(item,0,1);} +char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0);} + +// Parser core - when encountering text, process appropriately. +static const char *parse_value(cJSON *item,const char *value) +{ + if (!value) return 0; // Fail on null. + if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; } + if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; } + if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; } + if (*value=='\"') { return parse_string(item,value); } + if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); } + if (*value=='[') { return parse_array(item,value); } + if (*value=='{') { return parse_object(item,value); } + + return 0; // failure. +} + +// Render a value to text. +static char *print_value(cJSON *item,int depth,int fmt) +{ + char *out=0; + if (!item) return 0; + switch ((item->type)&255) + { + case cJSON_NULL: out=cJSON_strdup("null"); break; + case cJSON_False: out=cJSON_strdup("false");break; + case cJSON_True: out=cJSON_strdup("true"); break; + case cJSON_Number: out=print_number(item);break; + case cJSON_String: out=print_string(item);break; + case cJSON_Array: out=print_array(item,depth,fmt);break; + case cJSON_Object: out=print_object(item,depth,fmt);break; + } + return out; +} + +// Build an array from input text. +static const char *parse_array(cJSON *item,const char *value) +{ + cJSON *child; + if (*value!='[') return 0; // not an array! + + item->type=cJSON_Array; + value=skip(value+1); + if (*value==']') return value+1; // empty array. + + item->child=child=cJSON_New_Item(); + if (!item->child) return 0; // memory fail + value=skip(parse_value(child,skip(value))); // skip any spacing, get the value. + if (!value) return 0; + + while (*value==',') + { + cJSON *new_item; + if (!(new_item=cJSON_New_Item())) return 0; // memory fail + child->next=new_item;new_item->prev=child;child=new_item; + value=skip(parse_value(child,skip(value+1))); + if (!value) return 0; // memory fail + } + + if (*value==']') return value+1; // end of array + return 0; // malformed. +} + +// Render an array to text +static char *print_array(cJSON *item,int depth,int fmt) +{ + char **entries; + char *out=0,*ptr,*ret;int len=5; + cJSON *child=item->child; + int numentries=0,i=0,fail=0; + + // How many entries in the array? + while (child) numentries++,child=child->next; + // Allocate an array to hold the values for each + entries=(char**)cJSON_malloc(numentries*sizeof(char*)); + if (!entries) return 0; + memset(entries,0,numentries*sizeof(char*)); + // Retrieve all the results: + child=item->child; + while (child && !fail) + { + ret=print_value(child,depth+1,fmt); + entries[i++]=ret; + if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1; + child=child->next; + } + + // If we didn't fail, try to malloc the output string + if (!fail) out=cJSON_malloc(len); + // If that fails, we fail. + if (!out) fail=1; + + // Handle failure. + if (fail) + { + for (i=0;itype=cJSON_Object; + value=skip(value+1); + if (*value=='}') return value+1; // empty array. + + item->child=child=cJSON_New_Item(); + if (!item->child) return 0; + value=skip(parse_string(child,skip(value))); + if (!value) return 0; + child->string=child->valuestring;child->valuestring=0; + if (*value!=':') return 0; // fail! + value=skip(parse_value(child,skip(value+1))); // skip any spacing, get the value. + if (!value) return 0; + + while (*value==',') + { + cJSON *new_item; + if (!(new_item=cJSON_New_Item())) return 0; // memory fail + child->next=new_item;new_item->prev=child;child=new_item; + value=skip(parse_string(child,skip(value+1))); + if (!value) return 0; + child->string=child->valuestring;child->valuestring=0; + if (*value!=':') return 0; // fail! + value=skip(parse_value(child,skip(value+1))); // skip any spacing, get the value. + if (!value) return 0; + } + + if (*value=='}') return value+1; // end of array + return 0; // malformed. +} + +// Render an object to text. +static char *print_object(cJSON *item,int depth,int fmt) +{ + char **entries=0,**names=0; + char *out=0,*ptr,*ret,*str;int len=7,i=0,j; + cJSON *child=item->child; + int numentries=0,fail=0; + // Count the number of entries. + while (child) numentries++,child=child->next; + // Allocate space for the names and the objects + entries=(char**)cJSON_malloc(numentries*sizeof(char*)); + if (!entries) return 0; + names=(char**)cJSON_malloc(numentries*sizeof(char*)); + if (!names) {cJSON_free(entries);return 0;} + memset(entries,0,sizeof(char*)*numentries); + memset(names,0,sizeof(char*)*numentries); + + // Collect all the results into our arrays: + child=item->child;depth++;if (fmt) len+=depth; + while (child) + { + names[i]=str=print_string_ptr(child->string); + entries[i++]=ret=print_value(child,depth,fmt); + if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1; + child=child->next; + } + + // Try to allocate the output string + if (!fail) out=(char*)cJSON_malloc(len); + if (!out) fail=1; + + // Handle failure + if (fail) + { + for (i=0;ichild;int i=0;while(c)i++,c=c->next;return i;} +cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;} +cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;} + +// Utility for array list handling. +static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} +// Utility for handling references. +static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;} + +// Add item to array/object. +void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} +void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);} +void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));} +void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));} + +cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0; + if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;} +void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));} +cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;} +void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} + +// Replace array/object items with new ones. +void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; + newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem; + if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);} +void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}} + +// Create basic types: +cJSON *cJSON_CreateNull() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} +cJSON *cJSON_CreateTrue() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} +cJSON *cJSON_CreateFalse() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} +cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;} +cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;} +cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;} +cJSON *cJSON_CreateArray() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} +cJSON *cJSON_CreateObject() {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} + +// Create Arrays: +cJSON *cJSON_CreateIntArray(int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateFloatArray(float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateDoubleArray(double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} +cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} diff -Nru mlt-0.6.2/src/modules/rotoscoping/cJSON.h mlt-0.7.2/src/modules/rotoscoping/cJSON.h --- mlt-0.6.2/src/modules/rotoscoping/cJSON.h 1970-01-01 00:00:00.000000000 +0000 +++ mlt-0.7.2/src/modules/rotoscoping/cJSON.h 2011-05-02 05:59:12.000000000 +0000 @@ -0,0 +1,124 @@ +/* + Copyright (c) 2009 Dave Gamble + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef cJSON__h +#define cJSON__h + +#ifdef __cplusplus +extern "C" +{ +#endif + +// cJSON Types: +#define cJSON_False 0 +#define cJSON_True 1 +#define cJSON_NULL 2 +#define cJSON_Number 3 +#define cJSON_String 4 +#define cJSON_Array 5 +#define cJSON_Object 6 + +#define cJSON_IsReference 256 + +// The cJSON structure: +typedef struct cJSON { + struct cJSON *next,*prev; // next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem + struct cJSON *child; // An array or object item will have a child pointer pointing to a chain of the items in the array/object. + + int type; // The type of the item, as above. + + char *valuestring; // The item's string, if type==cJSON_String + int valueint; // The item's number, if type==cJSON_Number + double valuedouble; // The item's number, if type==cJSON_Number + + char *string; // The item's name string, if this item is the child of, or is in the list of subitems of an object. +} cJSON; + +typedef struct cJSON_Hooks { + void *(*malloc_fn)(size_t sz); + void (*free_fn)(void *ptr); +} cJSON_Hooks; + +// Supply malloc, realloc and free functions to cJSON +extern void cJSON_InitHooks(cJSON_Hooks* hooks); + + +// Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. +extern cJSON *cJSON_Parse(const char *value); +// Render a cJSON entity to text for transfer/storage. Free the char* when finished. +extern char *cJSON_Print(cJSON *item); +// Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. +extern char *cJSON_PrintUnformatted(cJSON *item); +// Delete a cJSON entity and all subentities. +extern void cJSON_Delete(cJSON *c); + +// Returns the number of items in an array (or object). +extern int cJSON_GetArraySize(cJSON *array); +// Retrieve item number "item" from array "array". Returns NULL if unsuccessful. +extern cJSON *cJSON_GetArrayItem(cJSON *array,int item); +// Get item "string" from object. Case insensitive. +extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string); + +// These calls create a cJSON item of the appropriate type. +extern cJSON *cJSON_CreateNull(); +extern cJSON *cJSON_CreateTrue(); +extern cJSON *cJSON_CreateFalse(); +extern cJSON *cJSON_CreateBool(int b); +extern cJSON *cJSON_CreateNumber(double num); +extern cJSON *cJSON_CreateString(const char *string); +extern cJSON *cJSON_CreateArray(); +extern cJSON *cJSON_CreateObject(); + +// These utilities create an Array of count items. +extern cJSON *cJSON_CreateIntArray(int *numbers,int count); +extern cJSON *cJSON_CreateFloatArray(float *numbers,int count); +extern cJSON *cJSON_CreateDoubleArray(double *numbers,int count); +extern cJSON *cJSON_CreateStringArray(const char **strings,int count); + +// Append item to the specified array/object. +extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); +extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); +// Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. +extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); +extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item); + +// Remove/Detatch items from Arrays/Objects. +extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which); +extern void cJSON_DeleteItemFromArray(cJSON *array,int which); +extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string); +extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string); + +// Update array items. +extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); +extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); + +#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) +#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) +#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) +#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) +#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) + +#ifdef __cplusplus +} +#endif + +#endif diff -Nru mlt-0.6.2/src/modules/rotoscoping/factory.c mlt-0.7.2/src/modules/rotoscoping/factory.c --- mlt-0.6.2/src/modules/rotoscoping/factory.c 1970-01-01 00:00:00.000000000 +0000 +++ mlt-0.7.2/src/modules/rotoscoping/factory.c 2011-05-02 05:59:12.000000000 +0000 @@ -0,0 +1,39 @@ +/* + * factory.c -- the factory method interfaces + * Copyright (C) 2003-2004 Ushodaya Enterprises Limited + * Author: Charles Yates + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include + +extern mlt_filter filter_rotoscoping_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); + +static mlt_properties rotoscoping_metadata( mlt_service_type type, const char *id, void *data ) +{ + char file[ PATH_MAX ]; + snprintf( file, PATH_MAX, "%s/rotoscoping/filter_%s.yml", mlt_environment( "MLT_DATA" ), id ); + return mlt_properties_parse_yaml( file ); +} + +MLT_REPOSITORY +{ + MLT_REGISTER( filter_type, "rotoscoping", filter_rotoscoping_init ); + + MLT_REGISTER_METADATA( filter_type, "rotoscoping", rotoscoping_metadata, NULL ); +} diff -Nru mlt-0.6.2/src/modules/rotoscoping/filter_rotoscoping.c mlt-0.7.2/src/modules/rotoscoping/filter_rotoscoping.c --- mlt-0.6.2/src/modules/rotoscoping/filter_rotoscoping.c 1970-01-01 00:00:00.000000000 +0000 +++ mlt-0.7.2/src/modules/rotoscoping/filter_rotoscoping.c 2011-05-02 05:59:12.000000000 +0000 @@ -0,0 +1,630 @@ +/* + * rotoscoping.c -- keyframable vector based rotoscoping + * Copyright (C) 2011 Till Theato + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include + +#include "cJSON.h" + +#include +#include +#include +#include + +#define MAX( x, y ) ( ( x ) > ( y ) ? ( x ) : ( y ) ) +#define MIN( x, y ) ( ( x ) < ( y ) ? ( x ) : ( y ) ) +#define SQR( x ) ( x ) * ( x ) + +/** x, y tuple with double precision */ +typedef struct PointF +{ + double x; + double y; +} PointF; + +typedef struct BPointF +{ + struct PointF h1; + struct PointF p; + struct PointF h2; +} BPointF; + +enum MODES { MODE_RGB, MODE_ALPHA, MODE_LUMA }; +const char *MODESTR[3] = { "rgb", "alpha", "luma" }; + +enum ALPHAOPERATIONS { ALPHA_CLEAR, ALPHA_MAX, ALPHA_MIN, ALPHA_ADD, ALPHA_SUB }; +const char *ALPHAOPERATIONSTR[5] = { "clear", "max", "min", "add", "sub" }; + + +/** Returns the index of \param string in \param stringList. + * Useful for assigning string parameters to enums. */ +int stringValue( const char *string, const char **stringList, int max ) +{ + int i; + for ( i = 0; i < max; i++ ) + if ( strcmp( stringList[i], string ) == 0 ) + return i; + return 0; +} + +/** Sets "spline_is_dirty" to 1 if property "spline" was changed. + * We then know when to parse the json stored in "spline" */ +static void rotoPropertyChanged( mlt_service owner, mlt_filter this, char *name ) +{ + if ( !strcmp( name, "spline" ) ) + mlt_properties_set_int( MLT_FILTER_PROPERTIES( this ), "_spline_is_dirty", 1 ); +} + +/** Linear interp */ +inline void lerp( const PointF *a, const PointF *b, PointF *result, double t ) +{ + result->x = a->x + ( b->x - a->x ) * t; + result->y = a->y + ( b->y - a->y ) * t; +} + +/** Linear interp. with t = 0.5 + * Speed gain? */ +inline void lerpHalf( const PointF *a, const PointF *b, PointF *result ) +{ + result->x = ( a->x + b->x ) * .5; + result->y = ( a->y + b->y ) * .5; +} + +/** Helper for using qsort with an array of integers. */ +int ncompare( const void *a, const void *b ) +{ + return *(const int*)a - *(const int*)b; +} + +/** Turns a json array with two children into a point (x, y tuple). */ +void jsonGetPoint( cJSON *json, PointF *point ) +{ + if ( cJSON_GetArraySize( json ) == 2 ) + { + point->x = json->child->valuedouble; + point->y = json->child->next->valuedouble; + } +} + +/** + * Turns the array of json elements into an array of Bézier points. + * \param array cJSON array. values have to be Bézier points: handle 1, point , handl2 + * ( [ [ [h1x, h1y], [px, py], [h2x, h2y] ], ... ] ) + * \param points pointer to array of points. Will be allocated and filled with the points in \param array + * \return number of points + */ +int json2BCurves( cJSON *array, BPointF **points ) +{ + int count = cJSON_GetArraySize( array ); + cJSON *child = array->child; + *points = mlt_pool_alloc( count * sizeof( BPointF ) ); + + int i = 0; + do + { + if ( child && cJSON_GetArraySize( child ) == 3 ) + { + jsonGetPoint( child->child , &(*points)[i].h1 ); + jsonGetPoint( child->child->next, &(*points)[i].p ); + jsonGetPoint( child->child->next->next, &(*points)[i].h2 ); + i++; + } + } while ( child && ( child = child->next ) ); + + if ( i < count ) + *points = mlt_pool_realloc( *points, i * sizeof( BPointF ) ); + + return i; +} + +/** Blurs \param src horizontally. \See funtion blur. */ +void blurHorizontal( uint8_t *src, uint8_t *dst, int width, int height, int radius) +{ + int x, y, kx, yOff, total, amount, amountInit; + amountInit = radius * 2 + 1; + for (y = 0; y < height; ++y) + { + total = 0; + yOff = y * width; + // Process entire window for first pixel + int size = MIN(radius + 1, width); + for ( kx = 0; kx < size; ++kx ) + total += src[yOff + kx]; + dst[yOff] = total / ( radius + 1 ); + // Subsequent pixels just update window total + for ( x = 1; x < width; ++x ) + { + amount = amountInit; + // Subtract pixel leaving window + if ( x - radius - 1 >= 0 ) + total -= src[yOff + x - radius - 1]; + else + amount -= radius - x; + // Add pixel entering window + if ( x + radius < width ) + total += src[yOff + x + radius]; + else + amount -= radius - width + x; + dst[yOff + x] = total / amount; + } + } +} + +/** Blurs \param src vertically. \See funtion blur. */ +void blurVertical( uint8_t *src, uint8_t *dst, int width, int height, int radius) +{ + int x, y, ky, total, amount, amountInit; + amountInit = radius * 2 + 1; + for (x = 0; x < width; ++x) + { + total = 0; + int size = MIN(radius + 1, height); + for ( ky = 0; ky < size; ++ky ) + total += src[x + ky * width]; + dst[x] = total / ( radius + 1 ); + for ( y = 1; y < height; ++y ) + { + amount = amountInit; + if ( y - radius - 1 >= 0 ) + total -= src[( y - radius - 1 ) * width + x]; + else + amount -= radius - y; + if ( y + radius < height ) + total += src[( y + radius ) * width + x]; + else + amount -= radius - height + y; + dst[y * width + x] = total / amount; + } + } +} + +/** + * Blurs the \param map using a simple "average" blur. + * \param map Will be blured; 1bpp + * \param width x dimension of channel stored in \param map + * \param height y dimension of channel stored in \param map + * \param radius blur radius + * \param passes blur passes + */ +void blur( uint8_t *map, int width, int height, int radius, int passes ) +{ + uint8_t *src = mlt_pool_alloc( width * height ); + uint8_t *tmp = mlt_pool_alloc( width * height ); + + int i; + for ( i = 0; i < passes; ++i ) + { + memcpy( src, map, width * height ); + blurHorizontal( src, tmp, width, height, radius ); + blurVertical( tmp, map, width, height, radius ); + } + + mlt_pool_release(src); + mlt_pool_release(tmp); +} + +/** + * Determines which points are located in the polygon and sets their value in \param map to \param value + * \param vertices points defining the polygon + * \param count number of vertices + * \param with x range + * \param height y range + * \param value value identifying points in the polygon + * \param map array of integers of the dimension width * height. + * The map entries belonging to the points in the polygon will be set to \param set * 255 the others to !set * 255. + */ +void fillMap( PointF *vertices, int count, int width, int height, int invert, uint8_t *map ) +{ + int nodes, nodeX[1024], pixelY, i, j, value; + + value = !invert * 255; + memset( map, invert * 255, width * height ); + + // Loop through the rows of the image + for ( pixelY = 0; pixelY < height; pixelY++ ) + { + /* + * Build a list of nodes. + * nodes are located at the borders of the polygon + * and therefore indicate a move from in to out or vice versa + */ + nodes = 0; + for ( i = 0, j = count - 1; i < count; j = i++ ) + if ( (vertices[i].y > (double)pixelY) != (vertices[j].y > (double)pixelY) ) + nodeX[nodes++] = (int)(vertices[i].x + (pixelY - vertices[i].y) / (vertices[j].y - vertices[i].y) * (vertices[j].x - vertices[i].x) ); + + qsort( nodeX, nodes, sizeof( int ), ncompare ); + + // Set map values for points between the node pairs to 1 + for ( i = 0; i < nodes; i += 2 ) + { + if ( nodeX[i] >= width ) + break; + + if ( nodeX[i+1] > 0 ) + { + nodeX[i] = MAX( 0, nodeX[i] ); + nodeX[i+1] = MIN( nodeX[i+1], width ); + memset( map + width * pixelY + nodeX[i], value, nodeX[i+1] - nodeX[i] ); + } + } + } +} + +/** Determines the point in the middle of the Bézier curve (t = 0.5) defined by \param p1 and \param p2 + * using De Casteljau's algorithm. + */ +void deCasteljau( BPointF *p1, BPointF *p2, BPointF *mid ) +{ + struct PointF ab, bc, cd; + + lerpHalf( &(p1->p), &(p1->h2), &ab ); + lerpHalf( &(p1->h2), &(p2->h1), &bc ); + lerpHalf( &(p2->h1), &(p2->p), &cd ); + lerpHalf( &ab, &bc, &(mid->h1) ); // mid->h1 = abbc + lerpHalf( &bc, &cd, &(mid->h2) ); // mid->h2 = bccd + lerpHalf( &(mid->h1), &(mid->h2), &(mid->p) ); + + p1->h2 = ab; + p2->h1 = cd; +} + +/** + * Calculates points for the cubic Bézier curve defined by \param p1 and \param p2. + * Points are calculated until the squared distanced between neighbour points is smaller than 2. + * \param points Pointer to list of points. Will be allocted and filled with calculated points. + * \param count Number of calculated points in \param points + * \param size Allocated size of \param points (in elements not in bytes) + */ +void curvePoints( BPointF p1, BPointF p2, PointF **points, int *count, int *size ) +{ + double errorSqr = SQR( p1.p.x - p2.p.x ) + SQR( p1.p.y - p2.p.y ); + + if ( *size + 1 >= *count ) + { + *size += (int)sqrt( errorSqr / 2 ); + *points = mlt_pool_realloc( *points, *size * sizeof ( struct PointF ) ); + } + + (*points)[(*count)++] = p1.p; + + if ( errorSqr <= 2 ) + return; + + BPointF mid; + deCasteljau( &p1, &p2, &mid ); + + curvePoints( p1, mid, points, count, size ); + + curvePoints( mid, p2, points, count, size ); + + (*points)[*(count)++] = p2.p; +} + +/** Do it :-). +*/ +static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) +{ + mlt_properties unique = mlt_frame_pop_service( frame ); + + int mode = mlt_properties_get_int( unique, "mode" ); + + // Get the image + if ( mode == MODE_RGB ) + *format = mlt_image_rgb24; + int error = mlt_frame_get_image( frame, image, format, width, height, writable ); + + // Only process if we have no error and a valid colour space + if ( !error ) + { + BPointF *bpoints; + struct PointF *points; + int bcount, length, count, size, i, j; + bpoints = mlt_properties_get_data( unique, "points", &length ); + bcount = length / sizeof( BPointF ); + + for ( i = 0; i < bcount; i++ ) + { + // map to image dimensions + bpoints[i].h1.x *= *width; + bpoints[i].p.x *= *width; + bpoints[i].h2.x *= *width; + bpoints[i].h1.y *= *height; + bpoints[i].p.y *= *height; + bpoints[i].h2.y *= *height; + } + + count = 0; + size = 1; + points = mlt_pool_alloc( size * sizeof( struct PointF ) ); + for ( i = 0; i < bcount; i++ ) + { + j = (i + 1) % bcount; + curvePoints( bpoints[i], bpoints[j], &points, &count, &size ); + } + + if ( count ) + { + length = *width * *height; + uint8_t *map = mlt_pool_alloc( length ); + int invert = mlt_properties_get_int( unique, "invert" ); + fillMap( points, count, *width, *height, invert, map ); + + int feather = mlt_properties_get_int( unique, "feather" ); + if ( feather && mode != MODE_RGB ) + blur( map, *width, *height, feather, mlt_properties_get_int( unique, "feather_passes" ) ); + + int bpp; + size = mlt_image_format_size( *format, *width, *height, &bpp ); + uint8_t *p = *image; + uint8_t *q = *image + size; + + i = 0; + uint8_t *alpha; + + switch ( mode ) + { + case MODE_RGB: + // *format == mlt_image_rgb24 + while ( p != q ) + { + if ( !map[i++] ) + p[0] = p[1] = p[2] = 0; + p += 3; + } + break; + case MODE_LUMA: + switch ( *format ) + { + case mlt_image_rgb24: + case mlt_image_rgb24a: + case mlt_image_opengl: + while ( p != q ) + { + p[0] = p[1] = p[2] = map[i++]; + p += bpp; + } + break; + case mlt_image_yuv422: + while ( p != q ) + { + p[0] = map[i++]; + p[1] = 128; + p += 2; + } + break; + case mlt_image_yuv420p: + memcpy( p, map, length ); + memset( p + length, 128, length / 2 ); + break; + default: + break; + } + break; + case MODE_ALPHA: + switch ( *format ) + { + case mlt_image_rgb24a: + case mlt_image_opengl: + switch ( mlt_properties_get_int( unique, "alpha_operation" ) ) + { + case ALPHA_CLEAR: + while ( p != q ) + { + p[3] = map[i++]; + p += 4; + } + break; + case ALPHA_MAX: + while ( p != q ) + { + p[3] = MAX( p[3], map[i] ); + p += 4; + i++; + } + break; + case ALPHA_MIN: + while ( p != q ) + { + p[3] = MIN( p[3], map[i] ); + p += 4; + i++; + } + break; + case ALPHA_ADD: + while ( p != q ) + { + p[3] = MIN( p[3] + map[i], 255 ); + p += 4; + i++; + } + break; + case ALPHA_SUB: + while ( p != q ) + { + p[3] = MAX( p[3] - map[i], 0 ); + p += 4; + i++; + } + break; + } + break; + default: + alpha = mlt_frame_get_alpha_mask( frame ); + switch ( mlt_properties_get_int( unique, "alpha_operation" ) ) + { + case ALPHA_CLEAR: + memcpy( alpha, map, length ); + break; + case ALPHA_MAX: + for ( ; i < length; i++, alpha++ ) + *alpha = MAX( map[i], *alpha ); + break; + case ALPHA_MIN: + for ( ; i < length; i++, alpha++ ) + *alpha = MIN( map[i], *alpha ); + break; + case ALPHA_ADD: + for ( ; i < length; i++, alpha++ ) + *alpha = MIN( *alpha + map[i], 255 ); + break; + case ALPHA_SUB: + for ( ; i < length; i++, alpha++ ) + *alpha = MAX( *alpha - map[i], 0 ); + break; + } + break; + } + break; + } + + mlt_pool_release( map ); + } + + mlt_pool_release( points ); + } + + return error; +} + +/** Filter processing. +*/ +static mlt_frame filter_process( mlt_filter filter, mlt_frame frame ) +{ + mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); + int splineIsDirty = mlt_properties_get_int( properties, "_spline_is_dirty" ); + char *modeStr = mlt_properties_get( properties, "mode" ); + cJSON *root = mlt_properties_get_data( properties, "_spline_parsed", NULL ); + + if ( splineIsDirty || root == NULL ) + { + // we need to (re-)parse + char *spline = mlt_properties_get( properties, "spline" ); + root = cJSON_Parse( spline ); + mlt_properties_set_data( properties, "_spline_parsed", root, 0, (mlt_destructor)cJSON_Delete, NULL ); + mlt_properties_set_int( properties, "_spline_is_dirty", 0 ); + } + + if ( root == NULL ) + return frame; + + BPointF *points; + int count, i; + + if ( root->type == cJSON_Array ) + { + /* + * constant + */ + count = json2BCurves( root, &points ); + } + else if ( root->type == cJSON_Object ) + { + /* + * keyframes + */ + + mlt_position time, pos1, pos2; + time = mlt_frame_get_position( frame ); + + cJSON *keyframe = root->child; + cJSON *keyframeOld = keyframe; + + if ( !keyframe ) + return frame; + + while ( atoi( keyframe->string ) < time && keyframe->next ) + { + keyframeOld = keyframe; + keyframe = keyframe->next; + } + + pos1 = atoi( keyframeOld->string ); + pos2 = atoi( keyframe->string ); + + if ( pos1 >= pos2 || time >= pos2 ) + { + // keyframes in wrong order or before first / after last keyframe + count = json2BCurves( keyframe, &points ); + } + else + { + /* + * pos1 < time < pos2 + */ + + BPointF *p1, *p2; + int c1 = json2BCurves( keyframeOld, &p1 ); + int c2 = json2BCurves( keyframe, &p2 ); + + // range 0-1 + double position = ( time - pos1 ) / (double)( pos2 - pos1 + 1 ); + + count = MIN( c1, c2 ); // additional points are ignored + points = mlt_pool_alloc( count * sizeof( BPointF ) ); + for ( i = 0; i < count; i++ ) + { + lerp( &(p1[i].h1), &(p2[i].h1), &(points[i].h1), position ); + lerp( &(p1[i].p), &(p2[i].p), &(points[i].p), position ); + lerp( &(p1[i].h2), &(p2[i].h2), &(points[i].h2), position ); + } + + mlt_pool_release( p1 ); + mlt_pool_release( p2 ); + } + } + else + { + return frame; + } + + mlt_properties unique = mlt_frame_unique_properties( frame, MLT_FILTER_SERVICE( filter ) ); + mlt_properties_set_data( unique, "points", points, count * sizeof( BPointF ), (mlt_destructor)mlt_pool_release, NULL ); + mlt_properties_set_int( unique, "mode", stringValue( modeStr, MODESTR, 3 ) ); + mlt_properties_set_int( unique, "alpha_operation", stringValue( mlt_properties_get( properties, "alpha_operation" ), ALPHAOPERATIONSTR, 5 ) ); + mlt_properties_set_int( unique, "invert", mlt_properties_get_int( properties, "invert" ) ); + mlt_properties_set_int( unique, "feather", mlt_properties_get_int( properties, "feather" ) ); + mlt_properties_set_int( unique, "feather_passes", mlt_properties_get_int( properties, "feather_passes" ) ); + mlt_frame_push_service( frame, unique ); + mlt_frame_push_get_image( frame, filter_get_image ); + + return frame; +} + +/** Constructor for the filter. +*/ +mlt_filter filter_rotoscoping_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ) +{ + mlt_filter filter = mlt_filter_new( ); + if ( filter ) + { + filter->process = filter_process; + mlt_properties properties = MLT_FILTER_PROPERTIES( filter ); + mlt_properties_set( properties, "mode", "alpha" ); + mlt_properties_set( properties, "alpha_operation", "clear" ); + mlt_properties_set_int( properties, "invert", 0 ); + mlt_properties_set_int( properties, "feather", 0 ); + mlt_properties_set_int( properties, "feather_passes", 1 ); + if ( arg ) + mlt_properties_set( properties, "spline", arg ); + + mlt_events_listen( properties, filter, "property-changed", (mlt_listener)rotoPropertyChanged ); + } + return filter; +} diff -Nru mlt-0.6.2/src/modules/rotoscoping/filter_rotoscoping.yml mlt-0.7.2/src/modules/rotoscoping/filter_rotoscoping.yml --- mlt-0.6.2/src/modules/rotoscoping/filter_rotoscoping.yml 1970-01-01 00:00:00.000000000 +0000 +++ mlt-0.7.2/src/modules/rotoscoping/filter_rotoscoping.yml 2011-05-02 05:59:12.000000000 +0000 @@ -0,0 +1,97 @@ +schema_version: 0.1 +type: filter +identifier: rotoscoping +title: Rotoscoping +copyright: Copyright (C) 2011 Till Theato +version: 0.3 +license: GPL +language: en +url: none +creator: Till Theato +tags: + - Video +description: Keyframable vector based rotoscoping + +notes: ... +bugs: + - in some cases top most row in polygon is assigned to outside + +parameters: + - identifier: mode + title: Mode + type: string + description: How to visualize the area described by the spline + readonly: no + required: no + default: alpha + mutable: yes + widget: dropdown + values: | + alpha + luma + rgb + + - identifier: alpha_operation + title: Alpha Operation + type: string + description: How to proceed with the current alpha mask (only if mode = alpha) + readonly: no + required: no + default: clear + mutable: yes + widget: dropdown + values: | + clear (existing alpha mask is overwritten) + max (maximum: existing alpha mask; mask generated by this filter) + min (minimum: existing alpha mask; mask generated by this filter) + add (existing alpha mask + generated mask) + sub (existing alpha mask - generated mask) + + - identifier: invert + title: Invert + type: integer + description: use area inside of spline (0) or the outside (1) + readonly: no + required: no + minimum: 0 + maximum: 1 + default: 0 + mutable: yes + widget: checkbox + + - identifier: feather + title: Feather + type: integer + description: amount of feathering (radius of "average" blur applied on mask) + readonly: no + required: no + minimum: 0 + maximum: 1000 # no real limit + default: 0 + mutable: yes + widget: spinner + + - identifier: feather_passes + title: Feathering passes + type: integer + description: number of blur (feathering) passes + readonly: no + required: no + minimum: 1 + maximum: 1000 # no real limit + default: 1 + mutable: yes + widget: spinner + + - identifier: spline + title: Spline + type: string + description: | + The spline, a list of cubic Bézier curves, is described using JSON. + The most basic parts are the coordinate tuples: [x, y]; x,y will be mapped from the range 0-1 to the image dimensions. + Next layer are the Bézier points: [handle 1, point, handle 2] with handle 1, point, handle 2 being coordinate tuples + The spline is a list of Bézier points. + Optionally keyframes can be defined as a object of frame values, relative to the filter's in point, assigned to splines. + readonly: no + required: yes + mutable: yes diff -Nru mlt-0.6.2/src/modules/rotoscoping/Makefile mlt-0.7.2/src/modules/rotoscoping/Makefile --- mlt-0.6.2/src/modules/rotoscoping/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ mlt-0.7.2/src/modules/rotoscoping/Makefile 2011-05-02 05:59:12.000000000 +0000 @@ -0,0 +1,39 @@ +CFLAGS += -I../.. + +LDFLAGS += -L../../framework -lmlt -lm + +include ../../../config.mak + +TARGET = ../libmltrotoscoping$(LIBSUF) + +OBJS = factory.o \ + filter_rotoscoping.o \ + cJSON.o + + +LDFLAGS += -lm + +SRCS := $(OBJS:.o=.c) + +all: $(TARGET) + +$(TARGET): $(OBJS) + $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LDFLAGS) + +depend: $(SRCS) + $(CC) -MM $(CFLAGS) $^ 1>.depend + +distclean: clean + rm -f .depend + +clean: + rm -f $(OBJS) $(TARGET) + +install: all + install -m 755 $(TARGET) "$(DESTDIR)$(libdir)/mlt" + install -d $(DESTDIR)$(datadir)/mlt/rotoscoping + install -m 644 filter_rotoscoping.yml "$(DESTDIR)$(datadir)/mlt/rotoscoping" + +ifneq ($(wildcard .depend),) +include .depend +endif diff -Nru mlt-0.6.2/src/modules/sdl/consumer_sdl_audio.c mlt-0.7.2/src/modules/sdl/consumer_sdl_audio.c --- mlt-0.6.2/src/modules/sdl/consumer_sdl_audio.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/sdl/consumer_sdl_audio.c 2011-05-02 05:59:12.000000000 +0000 @@ -111,7 +111,7 @@ mlt_properties_set_int( this->properties, "buffer", 1 ); // Default audio buffer - mlt_properties_set_int( this->properties, "audio_buffer", 512 ); + mlt_properties_set_int( this->properties, "audio_buffer", 2048 ); // Ensure we don't join on a non-running object this->joined = 1; @@ -157,10 +157,6 @@ { consumer_stop( parent ); - this->running = 1; - this->joined = 0; - - pthread_mutex_lock( &mlt_sdl_mutex ); int ret = SDL_Init( SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE ); pthread_mutex_unlock( &mlt_sdl_mutex ); @@ -170,6 +166,8 @@ return -1; } + this->running = 1; + this->joined = 0; pthread_create( &this->thread, NULL, consumer_thread, this ); } @@ -181,7 +179,7 @@ // Get the actual object consumer_sdl this = parent->child; - if ( this->joined == 0 ) + if ( this->running && !this->joined ) { // Kill the thread and clean up this->joined = 1; @@ -193,15 +191,23 @@ pthread_mutex_unlock( &this->refresh_mutex ); // Cleanup the main thread +#ifndef WIN32 if ( this->thread ) +#endif pthread_join( this->thread, NULL ); + // Unlatch the video thread + pthread_mutex_lock( &this->video_mutex ); + pthread_cond_broadcast( &this->video_cond ); + pthread_mutex_unlock( &this->video_mutex ); + // Unlatch the audio callback pthread_mutex_lock( &this->audio_mutex ); pthread_cond_broadcast( &this->audio_cond ); pthread_mutex_unlock( &this->audio_mutex ); - SDL_QuitSubSystem( SDL_INIT_AUDIO ); + if ( this->playing ) + SDL_QuitSubSystem( SDL_INIT_AUDIO ); } return 0; @@ -465,7 +471,7 @@ int duration = 0; int64_t playtime = 0; struct timespec tm = { 0, 100000 }; - int last_position = -1; +// int last_position = -1; this->refresh_count = 0; // Loop until told not to @@ -534,19 +540,23 @@ pthread_mutex_unlock( &this->refresh_mutex ); } else + { mlt_frame_close( frame ); + frame = NULL; + } // Optimisation to reduce latency - if ( speed == 1.0 ) + if ( frame && speed == 1.0 ) { - if ( last_position != -1 && last_position + 1 != mlt_frame_get_position( frame ) ) - mlt_consumer_purge( consumer ); - last_position = mlt_frame_get_position( frame ); + // TODO: disabled due to misbehavior on parallel-consumer +// if ( last_position != -1 && last_position + 1 != mlt_frame_get_position( frame ) ) +// mlt_consumer_purge( consumer ); +// last_position = mlt_frame_get_position( frame ); } else { mlt_consumer_purge( consumer ); - last_position = -1; +// last_position = -1; } } } diff -Nru mlt-0.6.2/src/modules/sdl/consumer_sdl.c mlt-0.7.2/src/modules/sdl/consumer_sdl.c --- mlt-0.6.2/src/modules/sdl/consumer_sdl.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/sdl/consumer_sdl.c 2011-05-02 05:59:12.000000000 +0000 @@ -122,7 +122,7 @@ mlt_properties_set_int( this->properties, "buffer", 1 ); // Default audio buffer - mlt_properties_set_int( this->properties, "audio_buffer", 512 ); + mlt_properties_set_int( this->properties, "audio_buffer", 2048 ); // Ensure we don't join on a non-running object this->joined = 1; @@ -139,8 +139,10 @@ } // Set the sdl flags - this->sdl_flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL | SDL_RESIZABLE | SDL_DOUBLEBUF; - + this->sdl_flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL | SDL_DOUBLEBUF; +#if !defined(__DARWIN__) + this->sdl_flags |= SDL_RESIZABLE; +#endif // Allow thread to be started/stopped parent->start = consumer_start; parent->stop = consumer_stop; @@ -172,11 +174,12 @@ if ( !this->running ) { - int video_off = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( parent ), "video_off" ); - int preview_off = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( parent ), "preview_off" ); + mlt_properties properties = MLT_CONSUMER_PROPERTIES( parent ); + int video_off = mlt_properties_get_int( properties, "video_off" ); + int preview_off = mlt_properties_get_int( properties, "preview_off" ); int display_off = video_off | preview_off; - int audio_off = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( parent ), "audio_off" ); - int sdl_started = mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( parent ), "sdl_started" ); + int audio_off = mlt_properties_get_int( properties, "audio_off" ); + int sdl_started = mlt_properties_get_int( properties, "sdl_started" ); consumer_stop( parent ); @@ -226,7 +229,7 @@ else { double display_ratio = mlt_properties_get_double( this->properties, "display_ratio" ); - this->window_width = ( double )this->height * display_ratio; + this->window_width = ( double )this->height * display_ratio + 0.5; this->window_height = this->height; } @@ -264,7 +267,9 @@ // Kill the thread and clean up this->joined = 1; this->running = 0; +#ifndef WIN32 if ( this->thread ) +#endif pthread_join( this->thread, NULL ); // internal cleanup @@ -484,7 +489,6 @@ { // Get the image, width and height mlt_frame_get_image( frame, &image, &vfmt, &width, &height, 0 ); - mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "format", vfmt ); void *pool = mlt_cocoa_autorelease_init(); @@ -643,7 +647,6 @@ vfmt = preview_format == mlt_image_none ? mlt_image_rgb24a : preview_format; if ( !video_off ) mlt_frame_get_image( frame, &image, &vfmt, &width, &height, 0 ); - mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "format", vfmt ); mlt_events_fire( properties, "consumer-frame-show", frame, NULL ); } @@ -729,7 +732,8 @@ } else { - mlt_log_debug( MLT_CONSUMER_SERVICE(&this->parent), "dropped video frame\n" ); + static int dropped = 0; + mlt_log_info( MLT_CONSUMER_SERVICE(&this->parent), "dropped video frame %d\n", ++dropped ); } // This frame can now be closed @@ -767,27 +771,23 @@ int init_audio = 1; int init_video = 1; mlt_frame frame = NULL; - mlt_properties properties = NULL; int duration = 0; int64_t playtime = 0; struct timespec tm = { 0, 100000 }; // Loop until told not to - while( !terminated && this->running ) + while( this->running ) { // Get a frame from the attached producer - frame = mlt_consumer_rt_frame( consumer ); + frame = !terminated? mlt_consumer_rt_frame( consumer ) : NULL; // Check for termination - if ( terminate_on_pause && frame != NULL ) + if ( terminate_on_pause && frame ) terminated = mlt_properties_get_double( MLT_FRAME_PROPERTIES( frame ), "_speed" ) == 0.0; // Ensure that we have a frame - if ( frame != NULL ) + if ( frame ) { - // Get the frame properties - properties = MLT_FRAME_PROPERTIES( frame ); - // Play audio init_audio = consumer_play_audio( this, frame, init_audio, &duration ); @@ -802,7 +802,7 @@ } // Set playtime for this frame - mlt_properties_set_int( properties, "playtime", playtime ); + mlt_properties_set_int( MLT_FRAME_PROPERTIES( frame ), "playtime", playtime ); while ( this->running && mlt_deque_count( this->queue ) > 15 ) nanosleep( &tm, NULL ); @@ -816,9 +816,25 @@ // Calculate the next playtime playtime += ( duration * 1000 ); } + else if ( terminated ) + { + if ( init_video || mlt_deque_count( this->queue ) == 0 ) + break; + else + nanosleep( &tm, NULL ); + } } this->running = 0; + + // Unblock sdl_preview + if ( mlt_properties_get_int( MLT_CONSUMER_PROPERTIES( consumer ), "put_mode" ) == 1 ) + { + frame = mlt_consumer_get_frame( consumer ); + if ( frame ) + mlt_frame_close( frame ); + frame = NULL; + } // Kill the video thread if ( init_video == 0 ) @@ -855,6 +871,7 @@ // Get the wm structure if ( SDL_GetWMInfo( &wm ) == 1 ) { +#ifndef WIN32 // Check that we have the X11 wm if ( wm.subsystem == SDL_SYSWM_X11 ) { @@ -875,6 +892,7 @@ *width = attr.width; *height = attr.height; } +#endif } #endif diff -Nru mlt-0.6.2/src/modules/sdl/consumer_sdl_preview.c mlt-0.7.2/src/modules/sdl/consumer_sdl_preview.c --- mlt-0.6.2/src/modules/sdl/consumer_sdl_preview.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/sdl/consumer_sdl_preview.c 2011-05-02 05:59:12.000000000 +0000 @@ -22,12 +22,13 @@ #include #include #include +#include #include #include #include #include #include -#include +#include extern pthread_mutex_t mlt_sdl_mutex; @@ -92,6 +93,7 @@ mlt_properties_set( properties, "real_time", "0" ); mlt_properties_set( properties, "rescale", "nearest" ); mlt_properties_set( properties, "deinterlace_method", "onefield" ); + mlt_properties_set_int( properties, "prefill", 1 ); parent->close = consumer_close; parent->start = consumer_start; parent->stop = consumer_stop; @@ -196,10 +198,10 @@ mlt_properties_set_int( play, "progressive", progressive ); mlt_properties_set_int( still, "progressive", progressive ); - mlt_properties_pass_list( play, properties, "resize,rescale,width,height,aspect_ratio,display_ratio,volume" ); - mlt_properties_pass_list( still, properties, "resize,rescale,width,height,aspect_ratio,display_ratio" ); - mlt_properties_pass_list( play, properties, "deinterlace_method" ); - mlt_properties_pass_list( still, properties, "deinterlace_method" ); + mlt_properties_pass_list( play, properties, + "deinterlace_method,resize,rescale,width,height,aspect_ratio,display_ratio,volume,real_time,buffer,prefill" ); + mlt_properties_pass_list( still, properties, + "deinterlace_method,resize,rescale,width,height,aspect_ratio,display_ratio" ); mlt_properties_pass_list( play, properties, "preview_off,preview_format,window_background" ); mlt_properties_pass_list( still, properties, "preview_off,preview_format,window_background" ); @@ -249,7 +251,9 @@ pthread_mutex_lock( &this->refresh_mutex ); pthread_cond_broadcast( &this->refresh_cond ); pthread_mutex_unlock( &this->refresh_mutex ); +#ifndef WIN32 if ( this->thread ) +#endif pthread_join( this->thread, NULL ); this->joined = 1; @@ -344,6 +348,7 @@ mlt_position duration = mlt_producer_get_playtime( producer ); int pause = 0; +#ifndef SKIP_WAIT_EOS if ( this->active == this->play ) { // Do not interrupt the play consumer near the end @@ -358,10 +363,11 @@ } else { - // Send frame with speed 0 once to stop it - if ( frame && !eos && speed == 0.0 ) + // Send frame with speed 0 to stop it + if ( frame && !mlt_consumer_is_stopped( this->play ) ) { mlt_consumer_put_frame( this->play, frame ); + frame = NULL; eos = 1; } @@ -369,11 +375,21 @@ if ( mlt_consumer_is_stopped( this->play ) ) { // Stream has ended + mlt_log_verbose( MLT_CONSUMER_SERVICE( consumer ), "END OF STREAM\n" ); pause = 1; - eos = 0; // reset eof indicator + eos = 0; // reset eos indicator + } + else + { + // Prevent a tight busy loop + struct timespec tm = { 0, 100000L }; // 100 usec + nanosleep( &tm, NULL ); } } } +#else + pause = this->active == this->play; +#endif if ( pause ) { // Start the still consumer diff -Nru mlt-0.6.2/src/modules/sdl/consumer_sdl_still.c mlt-0.7.2/src/modules/sdl/consumer_sdl_still.c --- mlt-0.6.2/src/modules/sdl/consumer_sdl_still.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/sdl/consumer_sdl_still.c 2011-05-02 05:59:12.000000000 +0000 @@ -163,7 +163,7 @@ // Default window size double display_ratio = mlt_properties_get_double( this->properties, "display_ratio" ); - this->window_width = ( double )this->height * display_ratio; + this->window_width = ( double )this->height * display_ratio + 0.5; this->window_height = this->height; if ( sdl_started == 0 && preview_off == 0 ) @@ -614,10 +614,11 @@ // Specify the SDL Version SDL_VERSION( &wm.version ); +#ifndef __DARWIN__ // Get the wm structure if ( SDL_GetWMInfo( &wm ) == 1 ) { -#ifndef __DARWIN__ +#ifndef WIN32 // Check that we have the X11 wm if ( wm.subsystem == SDL_SYSWM_X11 ) { @@ -640,6 +641,7 @@ } #endif } +#endif return changed; } diff -Nru mlt-0.6.2/src/modules/sdl/Makefile mlt-0.7.2/src/modules/sdl/Makefile --- mlt-0.6.2/src/modules/sdl/Makefile 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/sdl/Makefile 2011-05-02 05:59:12.000000000 +0000 @@ -17,7 +17,7 @@ ifeq ($(targetos),Darwin) CFLAGS += -ObjC LDFLAGS += -lobjc -framework Foundation -else +else ifneq ($(targetos), MinGW) LDFLAGS += -lX11 endif @@ -37,6 +37,11 @@ SRCS += consumer_sdl_osx.m consumer_sdl_osx.h endif +ifeq ($(targetos), MinGW) +OBJS += ../../win32/win32.o +SRCS += ../../win32/win32.c +endif + all: $(TARGET) $(TARGET): $(OBJS) diff -Nru mlt-0.6.2/src/modules/sdl/producer_sdl_image.c mlt-0.7.2/src/modules/sdl/producer_sdl_image.c --- mlt-0.6.2/src/modules/sdl/producer_sdl_image.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/sdl/producer_sdl_image.c 2011-05-02 05:59:12.000000000 +0000 @@ -80,9 +80,7 @@ SDL_FreeSurface( converted ); // Update the frame - mlt_properties_set_data( properties, "image", *image, image_size, mlt_pool_release, NULL ); - mlt_properties_set_int( properties, "width", *width ); - mlt_properties_set_int( properties, "height", *height ); + mlt_frame_set_image( frame, *image, image_size, mlt_pool_release ); return 0; } diff -Nru mlt-0.6.2/src/modules/sox/configure mlt-0.7.2/src/modules/sox/configure --- mlt-0.6.2/src/modules/sox/configure 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/sox/configure 2011-05-02 05:59:12.000000000 +0000 @@ -19,7 +19,7 @@ if [ $? -eq 0 ] then disable_sox=0 - echo "CFLAGS += $(pkg-config --cflags sox) -I$(pkg-config --variable=prefix sox)" > config.mak + echo "CFLAGS += $(pkg-config --cflags sox)" > config.mak echo "LDFLAGS += $(pkg-config --libs sox)" >> config.mak [ $(pkg-config --modversion sox | cut -d. -f1) -gt 13 ] && echo "CFLAGS += -DSOX14" >> config.mak else diff -Nru mlt-0.6.2/src/modules/sox/filter_sox.c mlt-0.7.2/src/modules/sox/filter_sox.c --- mlt-0.6.2/src/modules/sox/filter_sox.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/sox/filter_sox.c 2011-05-02 05:59:12.000000000 +0000 @@ -195,6 +195,8 @@ // Get the filter properties mlt_properties filter_properties = MLT_FILTER_PROPERTIES( filter ); + mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); + // Get the properties st_sample_t *input_buffer;// = mlt_properties_get_data( filter_properties, "input_buffer", NULL ); st_sample_t *output_buffer = mlt_properties_get_data( filter_properties, "output_buffer", NULL ); @@ -243,7 +245,7 @@ if ( !strncmp( name, "effect", 6 ) ) { // Get the effect specification - char *value = mlt_properties_get( filter_properties, name ); + char *value = mlt_properties_get_value( filter_properties, j ); // Create an instance if ( create_effect( filter, value, count, i, *frequency ) == 0 ) @@ -364,6 +366,8 @@ } } + mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); + return 0; } diff -Nru mlt-0.6.2/src/modules/swfdec/configure mlt-0.7.2/src/modules/swfdec/configure --- mlt-0.6.2/src/modules/swfdec/configure 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/swfdec/configure 2011-05-02 05:59:12.000000000 +0000 @@ -2,17 +2,31 @@ if [ "$help" != "1" ] then - pkg-config swfdec-0.8 2> /dev/null + pkg-config swfdec-0.9 2> /dev/null disable_swfdec=$? - if [ "$disable_swfdec" != "0" ] + if [ "$disable_swfdec" = "0" ] then - pkg-config swfdec-0.9 2> /dev/null + echo "CFLAGS += $(pkg-config --cflags swfdec-0.9)" >> config.mak + echo "LDFLAGS += $(pkg-config --libs swfdec-0.9)" >> config.mak + else + pkg-config swfdec-0.8 2> /dev/null disable_swfdec=$? - if [ "$disable_swfdec" != "0" ] + if [ "$disable_swfdec" = "0" ] then - echo "- swfdec not found: disabling" - touch ../disable-swfdec - exit 0 + echo "CFLAGS += $(pkg-config --cflags swfdec-0.8)" >> config.mak + echo "LDFLAGS += $(pkg-config --libs swfdec-0.8)" >> config.mak + else + pkg-config swfdec-0.7 2> /dev/null + disable_swfdec=$? + if [ "$disable_swfdec" = "0" ] + then + echo "CFLAGS += $(pkg-config --cflags swfdec-0.7)" >> config.mak + echo "LDFLAGS += $(pkg-config --libs swfdec-0.7)" >> config.mak + else + echo "- swfdec not found: disabling" + touch ../disable-swfdec + exit 0 + fi fi fi fi diff -Nru mlt-0.6.2/src/modules/swfdec/Makefile mlt-0.7.2/src/modules/swfdec/Makefile --- mlt-0.6.2/src/modules/swfdec/Makefile 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/swfdec/Makefile 2011-05-02 05:59:12.000000000 +0000 @@ -3,16 +3,15 @@ LDFLAGS += -L../../framework -lmlt -lm include ../../../config.mak +include config.mak TARGET = ../libmltswfdec$(LIBSUF) OBJS = producer_swfdec.o -CFLAGS += `pkg-config --cflags swfdec-0.8 2>/dev/null` -CFLAGS += `pkg-config --cflags swfdec-0.9 2>/dev/null` - -LDFLAGS += `pkg-config --libs swfdec-0.8 2>/dev/null` -LDFLAGS += `pkg-config --libs swfdec-0.9 2>/dev/null` +ifeq ($(targetos), MinGW) +LDFLAGS += -enable-auto-import -lz +endif SRCS := $(OBJS:.o=.c) diff -Nru mlt-0.6.2/src/modules/swfdec/producer_swfdec.c mlt-0.7.2/src/modules/swfdec/producer_swfdec.c --- mlt-0.6.2/src/modules/swfdec/producer_swfdec.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/swfdec/producer_swfdec.c 2011-05-02 05:59:12.000000000 +0000 @@ -125,7 +125,7 @@ *format = mlt_image_rgb24a; *buffer = mlt_pool_alloc( *width * ( *height + 1 ) * 4 ); - mlt_properties_set_data( properties, "image", *buffer, *width * ( *height + 1 ) * 4, (mlt_destructor) mlt_pool_release, NULL ); + mlt_frame_set_image( frame, *buffer, *width * ( *height + 1 ) * 4, mlt_pool_release ); // Seek mlt_position pos = mlt_properties_get_position( properties, "swfdec.position" ); diff -Nru mlt-0.6.2/src/modules/vmfx/filter_shape.c mlt-0.7.2/src/modules/vmfx/filter_shape.c --- mlt-0.6.2/src/modules/vmfx/filter_shape.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/vmfx/filter_shape.c 2011-05-02 05:59:12.000000000 +0000 @@ -114,7 +114,7 @@ double alpha_mix = 0.0; // Calculate the position and length - int position = mlt_frame_get_position( frame ) - mlt_filter_get_in( this ); + int position = mlt_filter_get_position( this, frame ); int in = mlt_filter_get_in( this ); int out = mlt_filter_get_out( this ); int length; diff -Nru mlt-0.6.2/src/modules/vmfx/producer_pgm.c mlt-0.7.2/src/modules/vmfx/producer_pgm.c --- mlt-0.6.2/src/modules/vmfx/producer_pgm.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/vmfx/producer_pgm.c 2011-05-02 05:59:12.000000000 +0000 @@ -161,7 +161,7 @@ uint8_t *image = mlt_pool_alloc( size * 2 ); uint8_t *source = mlt_properties_get_data( MLT_PRODUCER_PROPERTIES( producer ), "image", NULL ); - mlt_properties_set_data( MLT_FRAME_PROPERTIES( this ), "image", image, size * 2, mlt_pool_release, NULL ); + mlt_frame_set_image( this, image, size * 2, mlt_pool_release ); *width = real_width; *height = real_height; diff -Nru mlt-0.6.2/src/modules/vorbis/producer_vorbis.c mlt-0.7.2/src/modules/vorbis/producer_vorbis.c --- mlt-0.6.2/src/modules/vorbis/producer_vorbis.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/vorbis/producer_vorbis.c 2011-05-02 05:59:12.000000000 +0000 @@ -220,6 +220,8 @@ // Get the producer properties mlt_properties properties = MLT_PRODUCER_PROPERTIES( this ); + mlt_service_lock( MLT_PRODUCER_SERVICE( this ) ); + // Get the ogg vorbis file OggVorbis_File *ov = mlt_properties_get_data( properties, "ogg_vorbis_file", NULL ); @@ -342,6 +344,8 @@ // Regardless of speed, we expect to get the next frame (cos we ain't too bright) mlt_properties_set_position( properties, "audio_expected", position + 1 ); + mlt_service_unlock( MLT_PRODUCER_SERVICE( this ) ); + return 0; } diff -Nru mlt-0.6.2/src/modules/xine/filter_deinterlace.c mlt-0.7.2/src/modules/xine/filter_deinterlace.c --- mlt-0.6.2/src/modules/xine/filter_deinterlace.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/xine/filter_deinterlace.c 2011-05-02 05:59:12.000000000 +0000 @@ -30,7 +30,73 @@ #include #include -int deinterlace_yadif( mlt_frame frame, mlt_filter filter, uint8_t **image, mlt_image_format *format, int *width, int *height, int mode ) +static yadif_filter *init_yadif( int width, int height ) +{ + yadif_filter *yadif = mlt_pool_alloc( sizeof( *yadif ) ); + + yadif->cpu = 0; // Pure C +#ifdef USE_SSE + yadif->cpu |= AVS_CPU_INTEGER_SSE; +#endif +#ifdef USE_SSE2 + yadif->cpu |= AVS_CPU_SSE2; +#endif + // Create intermediate planar planes + yadif->yheight = height; + yadif->ywidth = width; + yadif->uvwidth = yadif->ywidth / 2; + yadif->ypitch = ( yadif->ywidth + 15 ) / 16 * 16; + yadif->uvpitch = ( yadif->uvwidth + 15 ) / 16 * 16; + yadif->ysrc = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->ypitch ); + yadif->usrc = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch); + yadif->vsrc = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch ); + yadif->yprev = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->ypitch ); + yadif->uprev = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch ); + yadif->vprev = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch ); + yadif->ynext = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->ypitch ); + yadif->unext = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch ); + yadif->vnext = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch ); + yadif->ydest = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->ypitch ); + yadif->udest = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch ); + yadif->vdest = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch ); + + return yadif; +} + +static void close_yadif(yadif_filter *yadif) +{ + mlt_pool_release( yadif->ysrc ); + mlt_pool_release( yadif->usrc ); + mlt_pool_release( yadif->vsrc ); + mlt_pool_release( yadif->yprev ); + mlt_pool_release( yadif->uprev ); + mlt_pool_release( yadif->vprev ); + mlt_pool_release( yadif->ynext ); + mlt_pool_release( yadif->unext ); + mlt_pool_release( yadif->vnext ); + mlt_pool_release( yadif->ydest ); + mlt_pool_release( yadif->udest ); + mlt_pool_release( yadif->vdest ); + mlt_pool_release( yadif ); + +#if defined(__GNUC__) && !defined(PIC) + // Set SSSE3 bit to cpu + asm (\ + "mov $1, %%eax \n\t"\ + "push %%ebx \n\t"\ + "cpuid \n\t"\ + "pop %%ebx \n\t"\ + "mov %%ecx, %%edx \n\t"\ + "shr $9, %%edx \n\t"\ + "and $1, %%edx \n\t"\ + "shl $9, %%edx \n\t"\ + "and $511, %%ebx \n\t"\ + "or %%edx, %%ebx \n\t"\ + : "=b"(yadif->cpu) : "p"(yadif->cpu) : "%eax", "%ecx", "%edx"); +#endif +} + +static int deinterlace_yadif( mlt_frame frame, mlt_filter filter, uint8_t **image, mlt_image_format *format, int *width, int *height, int mode ) { mlt_properties properties = MLT_FRAME_PROPERTIES( frame ); mlt_frame previous_frame = mlt_properties_get_data( properties, "previous frame", NULL ); @@ -41,7 +107,6 @@ uint8_t* next_image = NULL; int next_width = *width; int next_height = *height; - yadif_filter *yadif = mlt_properties_get_data( MLT_FILTER_PROPERTIES( filter ), "yadif", NULL ); mlt_log_debug( MLT_FILTER_SERVICE(filter), "previous %d current %d next %d\n", previous_frame? mlt_frame_get_position(previous_frame) : -1, @@ -68,52 +133,35 @@ if ( !error && next_image && *format == mlt_image_yuv422 ) { - if ( !yadif->ysrc ) + yadif_filter *yadif = init_yadif( *width, *height ); + if ( yadif ) { - // Create intermediate planar planes - yadif->yheight = *height; - yadif->ywidth = *width; - yadif->uvwidth = yadif->ywidth / 2; - yadif->ypitch = ( yadif->ywidth + 15 ) / 16 * 16; - yadif->uvpitch = ( yadif->uvwidth + 15 ) / 16 * 16; - yadif->ysrc = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->ypitch ); - yadif->usrc = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch); - yadif->vsrc = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch ); - yadif->yprev = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->ypitch ); - yadif->uprev = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch ); - yadif->vprev = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch ); - yadif->ynext = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->ypitch ); - yadif->unext = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch ); - yadif->vnext = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch ); - yadif->ydest = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->ypitch ); - yadif->udest = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch ); - yadif->vdest = (unsigned char *) mlt_pool_alloc( yadif->yheight * yadif->uvpitch ); - + const int order = mlt_properties_get_int( properties, "top_field_first" ); + const int pitch = *width << 1; + const int parity = 0; + + // Convert packed to planar + YUY2ToPlanes( *image, pitch, *width, *height, yadif->ysrc, + yadif->ypitch, yadif->usrc, yadif->vsrc, yadif->uvpitch, yadif->cpu ); + YUY2ToPlanes( previous_image, pitch, *width, *height, yadif->yprev, + yadif->ypitch, yadif->uprev, yadif->vprev, yadif->uvpitch, yadif->cpu ); + YUY2ToPlanes( next_image, pitch, *width, *height, yadif->ynext, + yadif->ypitch, yadif->unext, yadif->vnext, yadif->uvpitch, yadif->cpu ); + + // Deinterlace each plane + filter_plane( mode, yadif->ydest, yadif->ypitch, yadif->yprev, yadif->ysrc, + yadif->ynext, yadif->ypitch, *width, *height, parity, order, yadif->cpu); + filter_plane( mode, yadif->udest, yadif->uvpitch,yadif->uprev, yadif->usrc, + yadif->unext, yadif->uvpitch, *width >> 1, *height, parity, order, yadif->cpu); + filter_plane( mode, yadif->vdest, yadif->uvpitch, yadif->vprev, yadif->vsrc, + yadif->vnext, yadif->uvpitch, *width >> 1, *height, parity, order, yadif->cpu); + + // Convert planar to packed + YUY2FromPlanes( *image, pitch, *width, *height, yadif->ydest, + yadif->ypitch, yadif->udest, yadif->vdest, yadif->uvpitch, yadif->cpu); + + close_yadif( yadif ); } - - const int order = mlt_properties_get_int( properties, "top_field_first" ); - const int pitch = *width << 1; - const int parity = 0; - - // Convert packed to planar - YUY2ToPlanes( *image, pitch, *width, *height, yadif->ysrc, - yadif->ypitch, yadif->usrc, yadif->vsrc, yadif->uvpitch, yadif->cpu ); - YUY2ToPlanes( previous_image, pitch, *width, *height, yadif->yprev, - yadif->ypitch, yadif->uprev, yadif->vprev, yadif->uvpitch, yadif->cpu ); - YUY2ToPlanes( next_image, pitch, *width, *height, yadif->ynext, - yadif->ypitch, yadif->unext, yadif->vnext, yadif->uvpitch, yadif->cpu ); - - // Deinterlace each plane - filter_plane( mode, yadif->ydest, yadif->ypitch, yadif->yprev, yadif->ysrc, - yadif->ynext, yadif->ypitch, *width, *height, parity, order, yadif->cpu); - filter_plane( mode, yadif->udest, yadif->uvpitch,yadif->uprev, yadif->usrc, - yadif->unext, yadif->uvpitch, *width >> 1, *height, parity, order, yadif->cpu); - filter_plane( mode, yadif->vdest, yadif->uvpitch, yadif->vprev, yadif->vsrc, - yadif->vnext, yadif->uvpitch, *width >> 1, *height, parity, order, yadif->cpu); - - // Convert planar to packed - YUY2FromPlanes( *image, pitch, *width, *height, yadif->ydest, - yadif->ypitch, yadif->udest, yadif->vdest, yadif->uvpitch, yadif->cpu); } } } @@ -199,7 +247,7 @@ uint8_t *new_image = mlt_pool_alloc( image_size ); deinterlace_yuv( new_image, image, *width * 2, *height, method ); - mlt_properties_set_data( properties, "image", new_image, image_size, mlt_pool_release, NULL ); + mlt_frame_set_image( this, new_image, image_size, mlt_pool_release ); *image = new_image; } } @@ -248,30 +296,6 @@ return frame; } -static void filter_close( mlt_filter this ) -{ - yadif_filter *yadif = mlt_properties_get_data( MLT_FILTER_PROPERTIES( this ), "yadif", NULL ); - if ( yadif ) - { - if ( yadif->ysrc ) - { - mlt_pool_release( yadif->ysrc ); - mlt_pool_release( yadif->usrc ); - mlt_pool_release( yadif->vsrc ); - mlt_pool_release( yadif->yprev ); - mlt_pool_release( yadif->uprev ); - mlt_pool_release( yadif->vprev ); - mlt_pool_release( yadif->ynext ); - mlt_pool_release( yadif->unext ); - mlt_pool_release( yadif->vnext ); - mlt_pool_release( yadif->ydest ); - mlt_pool_release( yadif->udest ); - mlt_pool_release( yadif->vdest ); - } - mlt_pool_release( yadif ); - } -} - static void on_service_changed( mlt_service owner, mlt_service filter ) { mlt_service service = mlt_properties_get_data( MLT_SERVICE_PROPERTIES(filter), "service", NULL ); @@ -286,37 +310,9 @@ mlt_filter this = mlt_filter_new( ); if ( this != NULL ) { - yadif_filter *yadif = mlt_pool_alloc( sizeof( *yadif ) ); - - yadif->cpu = 0; // Pure C -#ifdef USE_SSE - yadif->cpu |= AVS_CPU_INTEGER_SSE; -#endif -#ifdef USE_SSE2 - yadif->cpu |= AVS_CPU_SSE2; -#endif - yadif->ysrc = NULL; this->process = deinterlace_process; - this->close = filter_close; mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "method", arg ); - mlt_properties_set_data( MLT_FILTER_PROPERTIES( this ), "yadif", yadif, sizeof(*yadif), NULL, NULL ); mlt_events_listen( MLT_FILTER_PROPERTIES( this ), this, "service-changed", (mlt_listener) on_service_changed ); - -#if defined(__GNUC__) && !defined(PIC) - // Set SSSE3 bit to cpu - asm (\ - "mov $1, %%eax \n\t"\ - "push %%ebx \n\t"\ - "cpuid \n\t"\ - "pop %%ebx \n\t"\ - "mov %%ecx, %%edx \n\t"\ - "shr $9, %%edx \n\t"\ - "and $1, %%edx \n\t"\ - "shl $9, %%edx \n\t"\ - "and $511, %%ebx \n\t"\ - "or %%edx, %%ebx \n\t"\ - : "=b"(yadif->cpu) : "p"(yadif->cpu) : "%eax", "%ecx", "%edx"); -#endif } return this; } diff -Nru mlt-0.6.2/src/modules/xml/consumer_xml.c mlt-0.7.2/src/modules/xml/consumer_xml.c --- mlt-0.6.2/src/modules/xml/consumer_xml.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/xml/consumer_xml.c 2011-05-02 05:59:12.000000000 +0000 @@ -751,6 +751,10 @@ int length = 0; xmlDocDumpMemoryEnc( doc, &buffer, &length, "utf-8" ); mlt_properties_set( properties, resource, _s(buffer) ); +#ifdef WIN32 + xmlFreeFunc xmlFree = NULL; + xmlMemGet( &xmlFree, NULL, NULL, NULL); +#endif xmlFree( buffer ); } else diff -Nru mlt-0.6.2/src/modules/xml/producer_xml.c mlt-0.7.2/src/modules/xml/producer_xml.c --- mlt-0.6.2/src/modules/xml/producer_xml.c 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/modules/xml/producer_xml.c 2011-05-02 05:59:12.000000000 +0000 @@ -1095,6 +1095,10 @@ // Serialise the tree to get value xmlDocDumpMemory( context->value_doc, &value, &size ); mlt_properties_set( properties, context->property, _s(value) ); +#ifdef WIN32 + xmlFreeFunc xmlFree = NULL; + xmlMemGet( &xmlFree, NULL, NULL, NULL); +#endif xmlFree( value ); xmlFreeDoc( context->value_doc ); context->value_doc = NULL; @@ -1571,7 +1575,7 @@ for ( i = mlt_properties_count( properties ) - 1; i >= 1; i -- ) { char *name = mlt_properties_get_name( properties, i ); - if ( mlt_properties_get_data( properties, name, NULL ) == service ) + if ( mlt_properties_get_data_at( properties, i, NULL ) == service ) { mlt_properties_set_data( properties, name, service, 0, NULL, NULL ); break; diff -Nru mlt-0.6.2/src/swig/mlt.i mlt-0.7.2/src/swig/mlt.i --- mlt-0.6.2/src/swig/mlt.i 2011-01-24 01:22:29.000000000 +0000 +++ mlt-0.7.2/src/swig/mlt.i 2011-05-02 05:59:12.000000000 +0000 @@ -60,6 +60,7 @@ %newobject Repository::transitions( ); %newobject Repository::metadata( mlt_service_type, const char * ); %newobject Repository::languages( ); +%newobject Profile::list(); } /** Classes to wrap. diff -Nru mlt-0.6.2/src/win32/fnmatch.c mlt-0.7.2/src/win32/fnmatch.c --- mlt-0.6.2/src/win32/fnmatch.c 1970-01-01 00:00:00.000000000 +0000 +++ mlt-0.7.2/src/win32/fnmatch.c 2011-05-02 05:59:12.000000000 +0000 @@ -0,0 +1,198 @@ +/* + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Guido van Rossum. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * From FreeBSD fnmatch.c 1.11 + * $Id$ + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 4/16/94"; +#endif /* LIBC_SCCS and not lint */ + +/* + * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6. + * Compares a filename or pathname to a pattern. + */ + +#include +#include +#include + +#include "fnmatch.h" + +#define EOS '\0' + +static const char *rangematch(const char *, char, int); + +int fnmatch(const char *pattern, const char *string, int flags) +{ + const char *stringstart; + char c, test; + + for (stringstart = string;;) + switch (c = *pattern++) { + case EOS: + if ((flags & FNM_LEADING_DIR) && *string == '/') + return (0); + return (*string == EOS ? 0 : FNM_NOMATCH); + case '?': + if (*string == EOS) + return (FNM_NOMATCH); + if (*string == '/' && (flags & FNM_PATHNAME)) + return (FNM_NOMATCH); + if (*string == '.' && (flags & FNM_PERIOD) && + (string == stringstart || + ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) + return (FNM_NOMATCH); + ++string; + break; + case '*': + c = *pattern; + /* Collapse multiple stars. */ + while (c == '*') + c = *++pattern; + + if (*string == '.' && (flags & FNM_PERIOD) && + (string == stringstart || + ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) + return (FNM_NOMATCH); + + /* Optimize for pattern with * at end or before /. */ + if (c == EOS) + if (flags & FNM_PATHNAME) + return ((flags & FNM_LEADING_DIR) || + strchr(string, '/') == NULL ? + 0 : FNM_NOMATCH); + else + return (0); + else if (c == '/' && flags & FNM_PATHNAME) { + if ((string = strchr(string, '/')) == NULL) + return (FNM_NOMATCH); + break; + } + + /* General case, use recursion. */ + while ((test = *string) != EOS) { + if (!fnmatch(pattern, string, flags & ~FNM_PERIOD)) + return (0); + if (test == '/' && flags & FNM_PATHNAME) + break; + ++string; + } + return (FNM_NOMATCH); + case '[': + if (*string == EOS) + return (FNM_NOMATCH); + if (*string == '/' && flags & FNM_PATHNAME) + return (FNM_NOMATCH); + if ((pattern = + rangematch(pattern, *string, flags)) == NULL) + return (FNM_NOMATCH); + ++string; + break; + case '\\': + if (!(flags & FNM_NOESCAPE)) { + if ((c = *pattern++) == EOS) { + c = '\\'; + --pattern; + } + } + /* FALLTHROUGH */ + default: + if (c == *string) + ; + else if ((flags & FNM_CASEFOLD) && + (tolower((unsigned char)c) == + tolower((unsigned char)*string))) + ; + else if ((flags & FNM_PREFIX_DIRS) && *string == EOS && + (c == '/' && string != stringstart || + string == stringstart+1 && *stringstart == '/') ) + return (0); + else + return (FNM_NOMATCH); + string++; + break; + } + /* NOTREACHED */ +} + +static const char * +rangematch(const char *pattern, char test, int flags) +{ + int negate, ok; + char c, c2; + + /* + * A bracket expression starting with an unquoted circumflex + * character produces unspecified results (IEEE 1003.2-1992, + * 3.13.2). This implementation treats it like '!', for + * consistency with the regular expression syntax. + * J.T. Conklin (conklin@ngai.kaleida.com) + */ + if ( (negate = (*pattern == '!' || *pattern == '^')) ) + ++pattern; + + if (flags & FNM_CASEFOLD) + test = tolower((unsigned char)test); + + for (ok = 0; (c = *pattern++) != ']';) { + if (c == '\\' && !(flags & FNM_NOESCAPE)) + c = *pattern++; + if (c == EOS) + return (NULL); + + if (flags & FNM_CASEFOLD) + c = tolower((unsigned char)c); + + if (*pattern == '-' + && (c2 = *(pattern+1)) != EOS && c2 != ']') { + pattern += 2; + if (c2 == '\\' && !(flags & FNM_NOESCAPE)) + c2 = *pattern++; + if (c2 == EOS) + return (NULL); + + if (flags & FNM_CASEFOLD) + c2 = tolower((unsigned char)c2); + + if ((unsigned char)c <= (unsigned char)test && + (unsigned char)test <= (unsigned char)c2) + ok = 1; + } else if (c == test) + ok = 1; + } + return (ok == negate ? NULL : pattern); +} diff -Nru mlt-0.6.2/src/win32/fnmatch.h mlt-0.7.2/src/win32/fnmatch.h --- mlt-0.6.2/src/win32/fnmatch.h 1970-01-01 00:00:00.000000000 +0000 +++ mlt-0.7.2/src/win32/fnmatch.h 2011-05-02 05:59:12.000000000 +0000 @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)fnmatch.h 8.1 (Berkeley) 6/2/93 + * + * From FreeBSD fnmatch.h 1.7 + * $Id$ + */ + +#ifndef _FNMATCH_H_ +#define _FNMATCH_H_ + + +#define FNM_NOMATCH 1 /* Match failed. */ + +#define FNM_NOESCAPE 0x01 /* Disable backslash escaping. */ +#define FNM_PATHNAME 0x02 /* Slash must be matched by slash. */ +#define FNM_PERIOD 0x04 /* Period must be matched by period. */ +#define FNM_LEADING_DIR 0x08 /* Ignore / after Imatch. */ +#define FNM_CASEFOLD 0x10 /* Case insensitive search. */ +#define FNM_PREFIX_DIRS 0x20 /* Directory prefixes of pattern match too. */ + +int fnmatch(const char *pattern, const char *string, int flags); + +#endif /* !_FNMATCH_H_ */ diff -Nru mlt-0.6.2/src/win32/win32.c mlt-0.7.2/src/win32/win32.c --- mlt-0.6.2/src/win32/win32.c 1970-01-01 00:00:00.000000000 +0000 +++ mlt-0.7.2/src/win32/win32.c 2011-05-02 05:59:12.000000000 +0000 @@ -0,0 +1,43 @@ + +#include +#include +#include +#include + +int usleep(unsigned int useconds) +{ + HANDLE timer; + LARGE_INTEGER due; + + due.QuadPart = -(10 * (__int64)useconds); + + timer = CreateWaitableTimer(NULL, TRUE, NULL); + SetWaitableTimer(timer, &due, 0, NULL, NULL, 0); + WaitForSingleObject(timer, INFINITE); + CloseHandle(timer); + return 0; +} + + +int nanosleep( const struct timespec * rqtp, struct timespec * rmtp ) +{ + if (rqtp->tv_nsec > 999999999) { + /* The time interval specified 1,000,000 or more microseconds. */ + errno = EINVAL; + return -1; + } + return usleep( rqtp->tv_sec * 1000000 + rqtp->tv_nsec / 1000 ); +} + +int setenv(const char *name, const char *value, int overwrite) +{ + int result = 1; + if (overwrite == 0 && getenv (name)) { + result = 0; + } else { + result = SetEnvironmentVariable (name,value); + } + + return result; +} +