#include "playlist.h"
#include "job.h"
#include "image.h"
+#include "image_proxy.h"
#include "ratio.h"
#include "log.h"
#include "scaler.h"
#include "render_subtitles.h"
-#include "dcp_video.h"
#include "config.h"
#include "content_video.h"
+#include "player_video_frame.h"
using std::list;
using std::cout;
}
list<PositionImage>
-Player::process_content_image_subtitles (shared_ptr<SubtitleContent> content, list<shared_ptr<ContentImageSubtitle> > subs)
+Player::process_content_image_subtitles (shared_ptr<SubtitleContent> content, list<shared_ptr<ContentImageSubtitle> > subs) const
{
list<PositionImage> all;
}
list<PositionImage>
-Player::process_content_text_subtitles (list<shared_ptr<ContentTextSubtitle> > sub)
+Player::process_content_text_subtitles (list<shared_ptr<ContentTextSubtitle> > sub) const
{
list<PositionImage> all;
for (list<shared_ptr<ContentTextSubtitle> >::const_iterator i = sub.begin(); i != sub.end(); ++i) {
_approximate_size = true;
}
-shared_ptr<DCPVideo>
-Player::get_video (DCPTime time, bool accurate)
+shared_ptr<PlayerVideoFrame>
+Player::black_player_video_frame () const
{
- if (!_have_valid_pieces) {
- setup_pieces ();
- }
-
- list<shared_ptr<Piece> > ov = overlaps<VideoContent> (time);
- if (ov.empty ()) {
- /* No video content at this time: return a black frame */
- return shared_ptr<DCPVideo> (
- new DCPVideo (
- _black_image,
- EYES_BOTH,
- Crop (),
- _video_container_size,
- _video_container_size,
- Scaler::from_id ("bicubic"),
- Config::instance()->colour_conversions().front().conversion,
- time
- )
- );
- }
-
- /* Create a DCPVideo from the content's video at this time */
-
- shared_ptr<Piece> piece = ov.back ();
- shared_ptr<VideoDecoder> decoder = dynamic_pointer_cast<VideoDecoder> (piece->decoder);
- assert (decoder);
- shared_ptr<VideoContent> content = dynamic_pointer_cast<VideoContent> (piece->content);
- assert (content);
-
- shared_ptr<ContentVideo> dec = decoder->get_video (dcp_to_content_video (piece, time), accurate);
-
- dcp::Size image_size = content->scale().size (content, _video_container_size, _film->frame_size ());
- if (_approximate_size) {
- image_size.width &= ~3;
- image_size.height &= ~3;
- }
+ return shared_ptr<PlayerVideoFrame> (
+ new PlayerVideoFrame (
+ shared_ptr<const ImageProxy> (new RawImageProxy (_black_image)),
+ Crop (),
+ _video_container_size,
+ _video_container_size,
+ Scaler::from_id ("bicubic"),
+ EYES_BOTH,
+ PART_WHOLE,
+ Config::instance()->colour_conversions().front().conversion
+ )
+ );
+}
- shared_ptr<DCPVideo> dcp_video (
- new DCPVideo (
- dec->image,
- dec->eyes,
+shared_ptr<PlayerVideoFrame>
+Player::content_to_player_video_frame (
+ shared_ptr<VideoContent> content,
+ ContentVideo content_video,
+ list<shared_ptr<Piece> > subs,
+ DCPTime time,
+ dcp::Size image_size) const
+{
+ shared_ptr<PlayerVideoFrame> pvf (
+ new PlayerVideoFrame (
+ content_video.image,
content->crop (),
image_size,
_video_container_size,
_film->scaler(),
- content->colour_conversion (),
- time
+ content_video.eyes,
+ content_video.part,
+ content->colour_conversion ()
)
);
-
+
+
/* Add subtitles */
-
- ov = overlaps<SubtitleContent> (time);
+
list<PositionImage> sub_images;
- for (list<shared_ptr<Piece> >::const_iterator i = ov.begin(); i != ov.end(); ++i) {
+ for (list<shared_ptr<Piece> >::const_iterator i = subs.begin(); i != subs.end(); ++i) {
shared_ptr<SubtitleDecoder> subtitle_decoder = dynamic_pointer_cast<SubtitleDecoder> ((*i)->decoder);
shared_ptr<SubtitleContent> subtitle_content = dynamic_pointer_cast<SubtitleContent> ((*i)->content);
ContentTime const from = dcp_to_content_subtitle (*i, time);
subtitle_content,
image_subtitles
);
-
+
copy (im.begin(), im.end(), back_inserter (sub_images));
}
-
+
if (_burn_subtitles) {
list<shared_ptr<ContentTextSubtitle> > text_subtitles = subtitle_decoder->get_text_subtitles (from, to);
if (!text_subtitles.empty ()) {
}
}
}
-
+
if (!sub_images.empty ()) {
- dcp_video->set_subtitle (merge (sub_images));
+ pvf->set_subtitle (merge (sub_images));
+ }
+
+ return pvf;
+}
+
+/** @return All PlayerVideoFrames at the given time (there may be two frames for 3D) */
+list<shared_ptr<PlayerVideoFrame> >
+Player::get_video (DCPTime time, bool accurate)
+{
+ if (!_have_valid_pieces) {
+ setup_pieces ();
+ }
+
+ list<shared_ptr<Piece> > ov = overlaps<VideoContent> (
+ time,
+ time + DCPTime::from_frames (1, _film->video_frame_rate ())
+ );
+
+ list<shared_ptr<PlayerVideoFrame> > pvf;
+
+ if (ov.empty ()) {
+ /* No video content at this time */
+ pvf.push_back (black_player_video_frame ());
+ return pvf;
}
- return dcp_video;
+ /* Create a PlayerVideoFrame from the content's video at this time */
+
+ shared_ptr<Piece> piece = ov.back ();
+ shared_ptr<VideoDecoder> decoder = dynamic_pointer_cast<VideoDecoder> (piece->decoder);
+ assert (decoder);
+ shared_ptr<VideoContent> content = dynamic_pointer_cast<VideoContent> (piece->content);
+ assert (content);
+
+ list<ContentVideo> content_video = decoder->get_video (dcp_to_content_video (piece, time), accurate);
+ if (content_video.empty ()) {
+ pvf.push_back (black_player_video_frame ());
+ return pvf;
+ }
+
+ dcp::Size image_size = content->scale().size (content, _video_container_size, _film->frame_size ());
+ if (_approximate_size) {
+ image_size.width &= ~3;
+ image_size.height &= ~3;
+ }
+
+ for (list<ContentVideo>::const_iterator i = content_video.begin(); i != content_video.end(); ++i) {
+ list<shared_ptr<Piece> > subs = overlaps<SubtitleContent> (
+ time,
+ time + DCPTime::from_frames (1, _film->video_frame_rate ())
+ );
+
+ pvf.push_back (content_to_player_video_frame (content, *i, subs, time, image_size));
+ }
+
+ return pvf;
}
shared_ptr<AudioBuffers>
shared_ptr<AudioBuffers> audio (new AudioBuffers (_film->audio_channels(), length_frames));
audio->make_silent ();
- list<shared_ptr<Piece> > ov = overlaps<AudioContent> (time);
+ list<shared_ptr<Piece> > ov = overlaps<AudioContent> (time, time + length);
if (ov.empty ()) {
return audio;
}
shared_ptr<AudioDecoder> decoder = dynamic_pointer_cast<AudioDecoder> ((*i)->decoder);
assert (decoder);
- AudioFrame const content_time = dcp_to_content_audio (*i, time);
+ if (content->audio_frame_rate() == 0) {
+ /* This AudioContent has no audio (e.g. if it is an FFmpegContent with no
+ * audio stream).
+ */
+ continue;
+ }
+
+ /* The time that we should request from the content */
+ DCPTime request = time - DCPTime::from_seconds (content->audio_delay() / 1000.0);
+ DCPTime offset;
+ if (request < DCPTime ()) {
+ /* We went off the start of the content, so we will need to offset
+ the stuff we get back.
+ */
+ offset = -request;
+ request = DCPTime ();
+ }
- /* Audio from this piece's decoder (which might be more than what we asked for) */
- shared_ptr<ContentAudio> all = decoder->get_audio (content_time, length_frames, accurate);
+ AudioFrame const content_frame = dcp_to_content_audio (*i, request);
+
+ /* Audio from this piece's decoder (which might be more or less than what we asked for) */
+ shared_ptr<ContentAudio> all = decoder->get_audio (content_frame, length_frames, accurate);
/* Gain */
if (content->audio_gain() != 0) {
}
all->audio = dcp_mapped;
-
- /* Delay */
- /* XXX
- audio->dcp_time += content->audio_delay() * TIME_HZ / 1000;
- if (audio->dcp_time < 0) {
- int const frames = - audio->dcp_time * _film->audio_frame_rate() / TIME_HZ;
- if (frames >= audio->audio->frames ()) {
- return;
- }
-
- shared_ptr<AudioBuffers> trimmed (new AudioBuffers (audio->audio->channels(), audio->audio->frames() - frames));
- trimmed->copy_from (audio->audio.get(), audio->audio->frames() - frames, frames, 0);
-
- audio->audio = trimmed;
- audio->dcp_time = 0;
- }
- */
- audio->accumulate_frames (all->audio.get(), all->frame - content_time, 0, min (AudioFrame (all->audio->frames()), length_frames));
+ audio->accumulate_frames (
+ all->audio.get(),
+ content_frame - all->frame,
+ offset.frames (_film->audio_frame_rate()),
+ min (AudioFrame (all->audio->frames()), length_frames) - offset.frames (_film->audio_frame_rate ())
+ );
}
return audio;