diff --git a/src/modules/core/filter_autofade.c b/src/modules/core/filter_autofade.c index c70f55c12..47d6cfca4 100644 --- a/src/modules/core/filter_autofade.c +++ b/src/modules/core/filter_autofade.c @@ -74,9 +74,6 @@ static int filter_get_audio(mlt_frame frame, data++; } } - mlt_properties_set_int(filter_properties, - "fade_in_count", - mlt_properties_get_int(filter_properties, "fade_in_count") + 1); } else if ((samples_to_clip_end - *samples) <= fade_samples) { // Fade out for (int i = 0; i < audio.samples; i++) { @@ -86,28 +83,102 @@ static int filter_get_audio(mlt_frame frame, data++; } } - mlt_properties_set_int(filter_properties, - "fade_out_count", - mlt_properties_get_int(filter_properties, "fade_out_count") + 1); } return 0; } +static int filter_get_image(mlt_frame frame, + uint8_t **image, + mlt_image_format *format, + int *width, + int *height, + int writable) +{ + int error = 0; + mlt_filter filter = (mlt_filter) mlt_frame_pop_service(frame); + + // Get the current image + *format = mlt_image_rgba; + error = mlt_frame_get_image(frame, image, format, width, height, 1); + + if (error) + return error; + + mlt_properties filter_properties = MLT_FILTER_PROPERTIES(filter); + int clip_position = mlt_properties_get_int(MLT_FRAME_PROPERTIES(frame), + "meta.playlist.clip_position"); + int clip_length = mlt_properties_get_int(MLT_FRAME_PROPERTIES(frame), + "meta.playlist.clip_length"); + double fade_duration = mlt_properties_get_int(filter_properties, "fade_duration"); + double fps = mlt_profile_fps(mlt_service_profile(MLT_FILTER_SERVICE(filter))); + int fade_duration_frames = lrint(fade_duration * fps / 1000.0); + float image_factor = 1.0; + int frames_from_begining = clip_position + 1; + int frames_to_end = clip_length - clip_position - 1; + + if (frames_from_begining <= fade_duration_frames) { + // Fade In + image_factor = decay_factor(clip_position, fade_duration_frames); + } else if (frames_to_end <= fade_duration_frames) { + // Fade Out + image_factor = decay_factor(frames_to_end, fade_duration_frames); + } + + if (image_factor < 1.0) { + mlt_color color = mlt_properties_get_color(filter_properties, "fade_color"); + float color_factor = 1.0 - image_factor; + float r_value = color.r * color_factor; + float g_value = color.g * color_factor; + float b_value = color.b * color_factor; + float a_value = color.a * color_factor; + uint8_t *p = *image; + int pixels = *width * *height; + for (int i = 0; i < pixels; i++) { + p[0] = ((float) p[0] * image_factor) + r_value; + p[1] = ((float) p[1] * image_factor) + g_value; + p[2] = ((float) p[2] * image_factor) + b_value; + p[3] = ((float) p[3] * image_factor) + a_value; + p += 4; + } + } + + return error; +} + static mlt_frame filter_process(mlt_filter filter, mlt_frame frame) { + mlt_properties filter_properties = MLT_FILTER_PROPERTIES(filter); int clip_position = mlt_properties_get_int(MLT_FRAME_PROPERTIES(frame), "meta.playlist.clip_position"); int clip_length = mlt_properties_get_int(MLT_FRAME_PROPERTIES(frame), "meta.playlist.clip_length"); - int fade_duration = mlt_properties_get_int(MLT_FILTER_PROPERTIES(filter), "fade_duration"); + int fade_duration = mlt_properties_get_int(filter_properties, "fade_duration"); double fps = mlt_profile_fps(mlt_service_profile(MLT_FILTER_SERVICE(filter))); int ms_from_begining = (double) clip_position * 1000.0 / fps; int ms_from_end = (double) (clip_length - clip_position - 1) * 1000.0 / fps; - if (ms_from_begining <= fade_duration || ms_from_end <= fade_duration) { + int fade = 0; + + if (ms_from_begining <= fade_duration) { + fade = 1; + mlt_properties_set_int(filter_properties, + "fade_in_count", + mlt_properties_get_int(filter_properties, "fade_in_count") + 1); + } else if (ms_from_end <= fade_duration) { + fade = 1; + mlt_properties_set_int(filter_properties, + "fade_out_count", + mlt_properties_get_int(filter_properties, "fade_out_count") + 1); + } + + if (fade && mlt_properties_get_int(filter_properties, "fade_audio")) { mlt_frame_push_audio(frame, filter); mlt_frame_push_audio(frame, filter_get_audio); } + if (fade && mlt_properties_get_int(filter_properties, "fade_video")) { + mlt_frame_push_get_image(frame, (void *) filter); + mlt_frame_push_get_image(frame, filter_get_image); + } return frame; } @@ -129,6 +200,11 @@ mlt_filter filter_autofade_init(mlt_profile profile, if (filter) { filter->close = filter_close; filter->process = filter_process; + mlt_properties filter_properties = MLT_FILTER_PROPERTIES(filter); + mlt_properties_set_int(filter_properties, "fade_duration", 20); + mlt_properties_set_int(filter_properties, "fade_audio", 1); + mlt_properties_set_int(filter_properties, "fade_video", 0); + mlt_properties_set_string(filter_properties, "fade_color", "0x000000ff"); } return filter; diff --git a/src/modules/core/filter_autofade.yml b/src/modules/core/filter_autofade.yml index de8362083..d0a6866e2 100644 --- a/src/modules/core/filter_autofade.yml +++ b/src/modules/core/filter_autofade.yml @@ -30,6 +30,32 @@ parameters: maximum: 1000 unit: ms + - identifier: fade_video + title: Fade Video + type: boolean + description: Fade the video to/from the fade color + mutable: yes + default: 0 + + - identifier: fade_audio + title: Fade Audio + type: boolean + description: Fade the audio to/from silence + mutable: yes + default: 1 + + - identifier: fade_color + title: Fade color + type: color + description: > + The color to fade to. + A color value is a hexadecimal representation of RGB plus alpha channel + as 0xrrggbbaa. Colors can also be the words: white, black, red, green, + or blue. You can also use a HTML-style color values #rrggbb or #aarrggbb + default: 0x000000ff + mutable: yes + widget: color + - identifier: fade_in_count title: Fade In Count type: integer