X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fvideo_decoder.cc;h=cba21d280aae20a51fff025cb470fde6d3f5cb10;hb=f385ef03e5ea27519a31c0839447735a7fba0602;hp=fd82384416b6166a461b0f9d9d43e1430ae2695b;hpb=28dbf4fd074d2046a3c8ddebac9a537a80fd457a;p=dcpomatic.git diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc index fd8238441..cba21d280 100644 --- a/src/lib/video_decoder.cc +++ b/src/lib/video_decoder.cc @@ -21,65 +21,94 @@ #include "subtitle.h" #include "film.h" #include "image.h" -#include "log.h" -#include "job.h" +#include "ratio.h" #include "i18n.h" using std::cout; using boost::shared_ptr; -using boost::optional; -VideoDecoder::VideoDecoder (shared_ptr f) +VideoDecoder::VideoDecoder (shared_ptr f, shared_ptr c) : Decoder (f) - , _video_frame (0) - , _last_content_time (0) + , _next_video (0) + , _video_content (c) + , _frame_rate_conversion (c->video_frame_rate(), f->dcp_video_frame_rate()) + , _odd (false) { } -/** Called by subclasses to tell the world that some video data is ready. - * We find a subtitle then emit it for listeners. +/** Called by subclasses when some video is ready. * @param image frame to emit. - * @param t Time of the frame within the source, in seconds. + * @param same true if this frame is the same as the last one passed to this call. + * @param t Time of the frame within the source. */ void -VideoDecoder::emit_video (shared_ptr image, bool same, double t) +VideoDecoder::video (shared_ptr image, bool same, Time t) { + if (_frame_rate_conversion.skip && _odd) { + _odd = !_odd; + return; + } + + image->crop (_video_content->crop(), true); + + shared_ptr film = _film.lock (); + assert (film); + + libdcp::Size const container_size = film->container()->size (film->full_frame ()); + libdcp::Size const image_size = _video_content->ratio()->size (container_size); + + shared_ptr out = image->scale_and_convert_to_rgb (image_size, film->scaler(), true); + shared_ptr sub; if (_timed_subtitle && _timed_subtitle->displayed_at (t)) { sub = _timed_subtitle->subtitle (); } - TIMING (N_("Decoder emits %1"), _video_frame); - Video (image, same, sub, t); - ++_video_frame; + if (sub) { + Rect const tx = subtitle_transformed_area ( + float (image_size.width) / video_size().width, + float (image_size.height) / video_size().height, + sub->area(), film->subtitle_offset(), film->subtitle_scale() + ); + + shared_ptr im = sub->image()->scale (tx.size(), film->scaler(), true); + out->alpha_blend (im, tx.position()); + } + + if (image_size != container_size) { + assert (image_size.width <= container_size.width); + assert (image_size.height <= container_size.height); + shared_ptr im (new SimpleImage (PIX_FMT_RGB24, container_size, true)); + im->make_black (); + im->copy (out, Position ((container_size.width - image_size.width) / 2, (container_size.height - image_size.height) / 2)); + out = im; + } + + Video (out, same, t); + + if (_frame_rate_conversion.repeat) { + Video (image, true, t + film->video_frames_to_time (1)); + _next_video = t + film->video_frames_to_time (2); + } else { + _next_video = t + film->video_frames_to_time (1); + } - _last_content_time = t; + _odd = !_odd; } -/** Set up the current subtitle. This will be put onto frames that - * fit within its time specification. s may be 0 to say that there - * is no current subtitle. +/** Called by subclasses when a subtitle is ready. + * s may be 0 to say that there is no current subtitle. * @param s New current subtitle, or 0. */ void -VideoDecoder::emit_subtitle (shared_ptr s) +VideoDecoder::subtitle (shared_ptr s) { _timed_subtitle = s; if (_timed_subtitle) { Position const p = _timed_subtitle->subtitle()->position (); - _timed_subtitle->subtitle()->set_position (Position (p.x - _film->crop().left, p.y - _film->crop().top)); - } -} - -void -VideoDecoder::set_progress (Job* j) const -{ - assert (j); - - if (_film->video_length()) { - j->set_progress (float (_video_frame) / _film->video_length()); + _timed_subtitle->subtitle()->set_position (Position (p.x - _video_content->crop().left, p.y - _video_content->crop().top)); } }