X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fvideo_decoder.cc;h=cba21d280aae20a51fff025cb470fde6d3f5cb10;hb=f385ef03e5ea27519a31c0839447735a7fba0602;hp=99d711693e44fa942b268375f7f2f6bfda955c3e;hpb=9bdd8cc51942a13e360dde4efc04b3ca417c8b94;p=dcpomatic.git diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc index 99d711693..cba21d280 100644 --- a/src/lib/video_decoder.cc +++ b/src/lib/video_decoder.cc @@ -21,98 +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, 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 (); } - signal_video (image, false, sub, t); -} + 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() + ); -bool -VideoDecoder::have_last_video () const -{ - return _last_image; -} - -/** Called by subclasses to repeat the last video frame that we - * passed to emit_video(). If emit_video hasn't yet been called, - * we will generate a black frame. - */ -void -VideoDecoder::repeat_last_video (double t) -{ - if (!_last_image) { - _last_image.reset (new SimpleImage (pixel_format(), native_size(), true)); - _last_image->make_black (); + shared_ptr im = sub->image()->scale (tx.size(), film->scaler(), true); + out->alpha_blend (im, tx.position()); } - signal_video (_last_image, true, _last_subtitle, t); -} - -/** Emit our signal to say that some video data is ready. - * @param image Video frame. - * @param same true if `image' is the same as the last one we emitted. - * @param sub Subtitle for this frame, or 0. - */ -void -VideoDecoder::signal_video (shared_ptr image, bool same, shared_ptr sub, double t) -{ - TIMING (N_("Decoder emits %1"), _video_frame); - Video (image, same, sub); - ++_video_frame; + 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_image = image; - _last_subtitle = sub; - _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)); } }