-/** @return All PlayerVideos at the given time. There may be none if the content
- * at `time' is a DCP which we are passing through (i.e. referring to by reference)
- * or 2 if we have 3D.
- */
-list<shared_ptr<PlayerVideo> >
-Player::get_video (DCPTime time, bool accurate)
-{
- if (!_have_valid_pieces) {
- setup_pieces ();
- }
-
- /* Find subtitles for possible burn-in */
-
- PlayerSubtitles ps = get_subtitles (time, DCPTime::from_frames (1, _film->video_frame_rate ()), false, true, accurate);
-
- list<PositionImage> sub_images;
-
- /* Image subtitles */
- list<PositionImage> c = transform_image_subtitles (ps.image);
- copy (c.begin(), c.end(), back_inserter (sub_images));
-
- /* Text subtitles (rendered to an image) */
- if (!ps.text.empty ()) {
- list<PositionImage> s = render_subtitles (ps.text, ps.fonts, _video_container_size, time);
- copy (s.begin (), s.end (), back_inserter (sub_images));
- }
-
- optional<PositionImage> subtitles;
- if (!sub_images.empty ()) {
- subtitles = merge (sub_images);
- }
-
- /* Find pieces containing video which is happening now */
-
- list<shared_ptr<Piece> > ov = overlaps (
- time,
- time + DCPTime::from_frames (1, _film->video_frame_rate ()),
- &has_video
- );
-
- list<shared_ptr<PlayerVideo> > pvf;
-
- if (ov.empty ()) {
- /* No video content at this time */
- pvf.push_back (black_player_video_frame (time));
- } else {
- /* Some video content at this time */
- shared_ptr<Piece> last = *(ov.rbegin ());
- VideoFrameType const last_type = last->content->video->frame_type ();
-
- /* Get video from appropriate piece(s) */
- BOOST_FOREACH (shared_ptr<Piece> piece, ov) {
-
- shared_ptr<VideoDecoder> decoder = piece->decoder->video;
- DCPOMATIC_ASSERT (decoder);
-
- shared_ptr<DCPContent> dcp_content = dynamic_pointer_cast<DCPContent> (piece->content);
- if (dcp_content && dcp_content->reference_video () && !_play_referenced) {
- continue;
- }
-
- bool const use =
- /* always use the last video */
- piece == last ||
- /* with a corresponding L/R eye if appropriate */
- (last_type == VIDEO_FRAME_TYPE_3D_LEFT && piece->content->video->frame_type() == VIDEO_FRAME_TYPE_3D_RIGHT) ||
- (last_type == VIDEO_FRAME_TYPE_3D_RIGHT && piece->content->video->frame_type() == VIDEO_FRAME_TYPE_3D_LEFT);
-
- if (use) {
- /* We want to use this piece */
- list<ContentVideo> content_video = decoder->get (dcp_to_content_video (piece, time), accurate);
- if (content_video.empty ()) {
- pvf.push_back (black_player_video_frame (time));
- } else {
- dcp::Size image_size = piece->content->video->scale().size (
- piece->content->video, _video_container_size, _film->frame_size ()
- );
-
- for (list<ContentVideo>::const_iterator i = content_video.begin(); i != content_video.end(); ++i) {
- pvf.push_back (
- shared_ptr<PlayerVideo> (
- new PlayerVideo (
- i->image,
- time,
- piece->content->video->crop (),
- piece->content->video->fade (i->frame.index()),
- image_size,
- _video_container_size,
- i->frame.eyes(),
- i->part,
- piece->content->video->colour_conversion ()
- )
- )
- );
- }
- }
- } else {
- /* Discard unused video */
- decoder->get (dcp_to_content_video (piece, time), accurate);
- }
- }
- }
-
- if (subtitles) {
- BOOST_FOREACH (shared_ptr<PlayerVideo> p, pvf) {
- p->set_subtitle (subtitles.get ());
- }
- }
-
- return pvf;
-}
-
-/** @return Audio data or 0 if the only audio data here is referenced DCP data */
-shared_ptr<AudioBuffers>
-Player::get_audio (DCPTime time, DCPTime length, bool accurate)
-{
- if (!_have_valid_pieces) {
- setup_pieces ();
- }
-
- Frame const length_frames = length.frames_round (_film->audio_frame_rate ());
-
- shared_ptr<AudioBuffers> audio (new AudioBuffers (_film->audio_channels(), length_frames));
- audio->make_silent ();
-
- list<shared_ptr<Piece> > ov = overlaps (time, time + length, has_audio);
- if (ov.empty ()) {
- return audio;
- }
-
- bool all_referenced = true;
- BOOST_FOREACH (shared_ptr<Piece> i, ov) {
- shared_ptr<DCPContent> dcp_content = dynamic_pointer_cast<DCPContent> (i->content);
- if (i->content->audio && (!dcp_content || !dcp_content->reference_audio ())) {
- /* There is audio content which is not from a DCP or not set to be referenced */
- all_referenced = false;
- }
- }
-
- if (all_referenced && !_play_referenced) {
- return shared_ptr<AudioBuffers> ();
- }
-
- BOOST_FOREACH (shared_ptr<Piece> i, ov) {
-
- DCPOMATIC_ASSERT (i->content->audio);
- shared_ptr<AudioDecoder> decoder = i->decoder->audio;
- DCPOMATIC_ASSERT (decoder);
-
- /* The time that we should request from the content */
- DCPTime request = time - DCPTime::from_seconds (i->content->audio->delay() / 1000.0);
- Frame request_frames = length_frames;
- 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_frames += request.frames_round (_film->audio_frame_rate ());
- if (request_frames < 0) {
- request_frames = 0;
- }
- request = DCPTime ();
- }
-
- Frame const content_frame = dcp_to_resampled_audio (i, request);
-
- BOOST_FOREACH (AudioStreamPtr j, i->content->audio->streams ()) {
-
- if (j->channels() == 0) {
- /* Some content (e.g. DCPs) can have streams with no channels */
- continue;
- }
-
- /* Audio from this piece's decoder stream (which might be more or less than what we asked for) */
- ContentAudio all = decoder->get (j, content_frame, request_frames, accurate);
-
- /* Gain */
- if (i->content->audio->gain() != 0) {
- shared_ptr<AudioBuffers> gain (new AudioBuffers (all.audio));
- gain->apply_gain (i->content->audio->gain ());
- all.audio = gain;
- }
-
- /* Remap channels */
- shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), all.audio->frames()));
- dcp_mapped->make_silent ();
- AudioMapping map = j->mapping ();
- for (int i = 0; i < map.input_channels(); ++i) {
- for (int j = 0; j < _film->audio_channels(); ++j) {
- if (map.get (i, j) > 0) {
- dcp_mapped->accumulate_channel (
- all.audio.get(),
- i,
- j,
- map.get (i, j)
- );
- }
- }
- }
-
- if (_audio_processor) {
- dcp_mapped = _audio_processor->run (dcp_mapped, _film->audio_channels ());
- }
-
- all.audio = dcp_mapped;
-
- audio->accumulate_frames (
- all.audio.get(),
- content_frame - all.frame,
- offset.frames_round (_film->audio_frame_rate()),
- min (Frame (all.audio->frames()), request_frames)
- );
- }
- }
-
- return audio;
-}
-