X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fplayer.cc;h=4fbd906c64ec9591538d05d9399bea9f2df2a572;hb=d33a11798fc39336eb9442f11a06a9a1f2470d83;hp=03c5dc3220333fd67ec67c81e3d422a5089b11ca;hpb=45f9912aa850546e319e32a4052517d67f4e3d8f;p=dcpomatic.git diff --git a/src/lib/player.cc b/src/lib/player.cc index 03c5dc322..4fbd906c6 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -48,8 +48,6 @@ using boost::shared_ptr; using boost::weak_ptr; using boost::dynamic_pointer_cast; -//#define DEBUG_PLAYER 1 - class Piece { public: @@ -57,6 +55,8 @@ public: : content (c) , video_position (c->position ()) , audio_position (c->position ()) + , repeat_to_do (0) + , repeat_done (0) {} Piece (shared_ptr c, shared_ptr d) @@ -65,29 +65,52 @@ public: , video_position (c->position ()) , audio_position (c->position ()) {} + + /** Set this piece to repeat a video frame a given number of times */ + void set_repeat (IncomingVideo video, int num) + { + repeat_video = video; + repeat_to_do = num; + repeat_done = 0; + } + + void reset_repeat () + { + repeat_video.image.reset (); + repeat_to_do = 0; + repeat_done = 0; + } + + bool repeating () const + { + return repeat_done != repeat_to_do; + } + + void repeat (Player* player) + { + player->process_video ( + repeat_video.weak_piece, + repeat_video.image, + repeat_video.eyes, + repeat_done > 0, + repeat_video.frame, + (repeat_done + 1) * (TIME_HZ / player->_film->video_frame_rate ()) + ); + + ++repeat_done; + } shared_ptr content; shared_ptr decoder; + /** Time of the last video we emitted relative to the start of the DCP */ Time video_position; + /** Time of the last audio we emitted relative to the start of the DCP */ Time audio_position; -}; -#ifdef DEBUG_PLAYER -std::ostream& operator<<(std::ostream& s, Piece const & p) -{ - if (dynamic_pointer_cast (p.content)) { - s << "\tffmpeg "; - } else if (dynamic_pointer_cast (p.content)) { - s << "\tstill image"; - } else if (dynamic_pointer_cast (p.content)) { - s << "\tsndfile "; - } - - s << " at " << p.content->position() << " until " << p.content->end(); - - return s; -} -#endif + IncomingVideo repeat_video; + int repeat_to_do; + int repeat_done; +}; Player::Player (shared_ptr f, shared_ptr p) : _film (f) @@ -126,10 +149,6 @@ Player::pass () _have_valid_pieces = true; } -#ifdef DEBUG_PLAYER - cout << "= PASS\n"; -#endif - Time earliest_t = TIME_MAX; shared_ptr earliest; enum { @@ -142,7 +161,10 @@ Player::pass () continue; } - if (_video && dynamic_pointer_cast ((*i)->decoder)) { + shared_ptr vd = dynamic_pointer_cast ((*i)->decoder); + shared_ptr ad = dynamic_pointer_cast ((*i)->decoder); + + if (_video && vd) { if ((*i)->video_position < earliest_t) { earliest_t = (*i)->video_position; earliest = *i; @@ -150,7 +172,7 @@ Player::pass () } } - if (_audio && dynamic_pointer_cast ((*i)->decoder)) { + if (_audio && ad && ad->has_audio ()) { if ((*i)->audio_position < earliest_t) { earliest_t = (*i)->audio_position; earliest = *i; @@ -160,10 +182,6 @@ Player::pass () } if (!earliest) { -#ifdef DEBUG_PLAYER - cout << "no earliest piece.\n"; -#endif - flush (); return true; } @@ -171,28 +189,20 @@ Player::pass () switch (type) { case VIDEO: if (earliest_t > _video_position) { -#ifdef DEBUG_PLAYER - cout << "no video here; emitting black frame (earliest=" << earliest_t << ", video_position=" << _video_position << ").\n"; -#endif emit_black (); } else { -#ifdef DEBUG_PLAYER - cout << "Pass video " << *earliest << "\n"; -#endif - earliest->decoder->pass (); + if (earliest->repeating ()) { + earliest->repeat (this); + } else { + earliest->decoder->pass (); + } } break; case AUDIO: if (earliest_t > _audio_position) { -#ifdef DEBUG_PLAYER - cout << "no audio here (none until " << earliest_t << "); emitting silence.\n"; -#endif emit_silence (_film->time_to_audio_frames (earliest_t - _audio_position)); } else { -#ifdef DEBUG_PLAYER - cout << "Pass audio " << *earliest << "\n"; -#endif earliest->decoder->pass (); if (earliest->decoder->done()) { @@ -223,16 +233,21 @@ Player::pass () _audio_position += _film->audio_frames_to_time (tb.audio->frames ()); } -#ifdef DEBUG_PLAYER - cout << "\tpost pass _video_position=" << _video_position << " _audio_position=" << _audio_position << "\n"; -#endif - return false; } +/** @param extra Amount of extra time to add to the content frame's time (for repeat) */ void -Player::process_video (weak_ptr weak_piece, shared_ptr image, Eyes eyes, bool same, VideoContent::Frame frame) +Player::process_video (weak_ptr weak_piece, shared_ptr image, Eyes eyes, bool same, VideoContent::Frame frame, Time extra) { + /* Keep a note of what came in so that we can repeat it if required */ + _last_incoming_video.weak_piece = weak_piece; + _last_incoming_video.image = image; + _last_incoming_video.eyes = eyes; + _last_incoming_video.same = same; + _last_incoming_video.frame = frame; + _last_incoming_video.extra = extra; + shared_ptr piece = weak_piece.lock (); if (!piece) { return; @@ -261,7 +276,7 @@ Player::process_video (weak_ptr weak_piece, shared_ptr image work_image = work_image->scale (image_size, _film->scaler(), PIX_FMT_RGB24, true); - Time time = content->position() + relative_time - content->trim_start (); + Time time = content->position() + relative_time + extra - content->trim_start (); if (_film->with_subtitles () && _out_subtitle.image && time >= _out_subtitle.from && time <= _out_subtitle.to) { work_image->alpha_blend (_out_subtitle.image, _out_subtitle.position); @@ -281,16 +296,14 @@ Player::process_video (weak_ptr weak_piece, shared_ptr image #endif Video (work_image, eyes, content->colour_conversion(), same, time); - time += TIME_HZ / _film->video_frame_rate(); - - if (frc.repeat) { - Video (work_image, eyes, content->colour_conversion(), true, time); - time += TIME_HZ / _film->video_frame_rate(); - } + time += TIME_HZ / _film->video_frame_rate(); _last_emit_was_black = false; - _video_position = piece->video_position = time; + + if (frc.repeat > 1 && !piece->repeating ()) { + piece->set_repeat (_last_incoming_video, frc.repeat - 1); + } } void @@ -325,7 +338,7 @@ Player::process_audio (weak_ptr weak_piece, shared_ptrposition() + (content->audio_delay() * TIME_HZ / 1000) + relative_time; + Time time = content->position() + (content->audio_delay() * TIME_HZ / 1000) + relative_time - content->trim_start (); /* Remap channels */ shared_ptr dcp_mapped (new AudioBuffers (_film->audio_channels(), audio->frames())); @@ -397,24 +410,25 @@ Player::seek (Time t, bool accurate) if (!vc) { continue; } - + + /* s is the offset of t from the start position of this content */ Time s = t - vc->position (); s = max (static_cast