Various fixes.
authorCarl Hetherington <cth@carlh.net>
Sun, 16 Dec 2012 12:51:00 +0000 (12:51 +0000)
committerCarl Hetherington <cth@carlh.net>
Sun, 16 Dec 2012 12:51:00 +0000 (12:51 +0000)
src/lib/decoder.cc
src/lib/decoder.h
src/lib/ffmpeg_decoder.cc
src/lib/ffmpeg_decoder.h
src/lib/image.cc
src/lib/options.h
src/wx/film_viewer.cc
src/wx/film_viewer.h

index 5778949963ccb63cff592626b96094da2e4a6cc5..93ce2cdbb2c816d0b388fba69e556c70a27dffed 100644 (file)
@@ -57,7 +57,7 @@ Decoder::Decoder (boost::shared_ptr<Film> f, boost::shared_ptr<const Options> o,
        
 }
 
-void
+bool
 Decoder::seek (SourceFrame f)
 {
        throw DecodeError ("decoder does not support seek");
index 96d3a201460df5b2b9e9e0be77f44708c430b9d4..e4693fb6df76fa8db8558460c2963d7c5916be96 100644 (file)
@@ -58,7 +58,10 @@ public:
        virtual ~Decoder () {}
 
        virtual bool pass () = 0;
-       virtual void seek (SourceFrame);
+       /** Seek.
+        *  @return true on error.
+        */
+       virtual bool seek (SourceFrame);
 
 protected:
        /** our Film */
index f4c7d3d857f5e6cf04a92e2b23ce0ed3171aca28..c7c96ce68aafcfb78e35b5939a788bcce11b2c4c 100644 (file)
@@ -270,46 +270,10 @@ FFmpegDecoder::pass ()
                                _film->log()->log (String::compose ("Used only %1 bytes of %2 in packet", r, _packet.size));
                        }
 
-                       /* Where we are in the output, in seconds */
-                       double const out_pts_seconds = video_frame() / frames_per_second();
-
-                       /* Where we are in the source, in seconds */
-                       double const source_pts_seconds = av_q2d (_format_context->streams[_packet.stream_index]->time_base)
-                               * av_frame_get_best_effort_timestamp(_frame);
-
-                       _film->log()->log (
-                               String::compose ("Source video frame ready; source at %1, output at %2", source_pts_seconds, out_pts_seconds),
-                               Log::VERBOSE
-                               );
-
-                       if (!_first_video) {
-                               _first_video = source_pts_seconds;
-                       }
-
-                       /* Difference between where we are and where we should be */
-                       double const delta = source_pts_seconds - _first_video.get() - out_pts_seconds;
-                       double const one_frame = 1 / frames_per_second();
-
-                       /* Insert frames if required to get out_pts_seconds up to pts_seconds */
-                       if (delta > one_frame) {
-                               int const extra = rint (delta / one_frame);
-                               for (int i = 0; i < extra; ++i) {
-                                       repeat_last_video ();
-                                       _film->log()->log (
-                                               String::compose (
-                                                       "Extra video frame inserted at %1s; source frame %2, source PTS %3 (at %4 fps)",
-                                                       out_pts_seconds, video_frame(), source_pts_seconds, frames_per_second()
-                                                       )
-                                               );
-                               }
-                       }
-
-                       if (delta > -one_frame) {
-                               /* Process this frame */
-                               filter_and_emit_video (_frame);
+                       if (_opt->decoder_alignment) {
+                               out_careful ();
                        } else {
-                               /* Otherwise we are omitting a frame to keep things right */
-                               _film->log()->log (String::compose ("Frame removed at %1s", out_pts_seconds));
+                               filter_and_emit_video (_frame);
                        }
                }
 
@@ -584,12 +548,13 @@ FFmpegDecoder::filter_and_emit_video (AVFrame* frame)
        }
 }
 
-void
+bool
 FFmpegDecoder::seek (SourceFrame f)
 {
        int64_t const t = static_cast<int64_t>(f) / (av_q2d (_format_context->streams[_video_stream]->time_base) * frames_per_second());
-       av_seek_frame (_format_context, _video_stream, t, 0);
+       int const r = av_seek_frame (_format_context, _video_stream, t, 0);
        avcodec_flush_buffers (_video_codec_context);
+       return r < 0;
 }
 
 shared_ptr<FFmpegAudioStream>
@@ -645,3 +610,48 @@ FFmpegAudioStream::to_string () const
 }
 
 
+void
+FFmpegDecoder::out_careful ()
+{
+       /* Where we are in the output, in seconds */
+       double const out_pts_seconds = video_frame() / frames_per_second();
+       
+       /* Where we are in the source, in seconds */
+       double const source_pts_seconds = av_q2d (_format_context->streams[_packet.stream_index]->time_base)
+               * av_frame_get_best_effort_timestamp(_frame);
+       
+       _film->log()->log (
+               String::compose ("Source video frame ready; source at %1, output at %2", source_pts_seconds, out_pts_seconds),
+               Log::VERBOSE
+               );
+       
+       if (!_first_video) {
+               _first_video = source_pts_seconds;
+       }
+       
+       /* Difference between where we are and where we should be */
+       double const delta = source_pts_seconds - _first_video.get() - out_pts_seconds;
+       double const one_frame = 1 / frames_per_second();
+       
+       /* Insert frames if required to get out_pts_seconds up to pts_seconds */
+       if (delta > one_frame) {
+               int const extra = rint (delta / one_frame);
+               for (int i = 0; i < extra; ++i) {
+                       repeat_last_video ();
+                       _film->log()->log (
+                               String::compose (
+                                       "Extra video frame inserted at %1s; source frame %2, source PTS %3 (at %4 fps)",
+                                       out_pts_seconds, video_frame(), source_pts_seconds, frames_per_second()
+                                                       )
+                               );
+               }
+       }
+       
+       if (delta > -one_frame) {
+               /* Process this frame */
+               filter_and_emit_video (_frame);
+       } else {
+               /* Otherwise we are omitting a frame to keep things right */
+               _film->log()->log (String::compose ("Frame removed at %1s", out_pts_seconds));
+       }
+}
index de0a6a67c377bc7859f1c164ca9c5dab30230a78..89e42f9786e33e584d88417aaf4d51fabc091ae4 100644 (file)
@@ -97,7 +97,7 @@ public:
        void set_audio_stream (boost::shared_ptr<AudioStream>);
        void set_subtitle_stream (boost::shared_ptr<SubtitleStream>);
 
-       void seek (SourceFrame);
+       bool seek (SourceFrame);
 
 private:
 
@@ -106,6 +106,7 @@ private:
        AVSampleFormat audio_sample_format () const;
        int bytes_per_audio_sample () const;
 
+       void out_careful ();
        void filter_and_emit_video (AVFrame *);
 
        void setup_general ();
index 72828ed4644cf5d862e8bd72f132f5188221bb2f..748e9ae4ba9f10ce819e18eda2fd55f9bd419590 100644 (file)
@@ -125,7 +125,7 @@ Image::scale_and_convert_to_rgb (Size out_size, int padding, Scaler const * scal
        Size content_size = out_size;
        content_size.width -= (padding * 2);
 
-       shared_ptr<Image> rgb (new AlignedImage (PIX_FMT_RGB24, content_size));
+       shared_ptr<Image> rgb (new CompactImage (PIX_FMT_RGB24, content_size));
 
        struct SwsContext* scale_context = sws_getContext (
                size().width, size().height, pixel_format(),
index 29b3b71cd4a91e01bc8d76494608d076d6c4452c..65c7b9ebc802bed72a5cc6de493076fd4e2bdb51 100644 (file)
@@ -43,6 +43,7 @@ public:
                , decode_video_skip (0)
                , decode_audio (true)
                , decode_subtitles (false)
+               , decoder_alignment (true)
                , _frame_out_path (f)
                , _frame_out_extension (e)
                , _multichannel_audio_out_path (m)
@@ -110,6 +111,8 @@ public:
        bool decode_audio;          ///< true to decode audio, otherwise false
        bool decode_subtitles;
 
+       bool decoder_alignment;
+
 private:
        /** Path of the directory to write video frames to */
        std::string _frame_out_path;
index 2dc578e658e5ee9d382a64f8901ddf822eb05e2c..12fe302f4564bd849cbec7813470947412e5da1f 100644 (file)
 #include "lib/scaler.h"
 #include "film_viewer.h"
 #include "wx_util.h"
-#include "ffmpeg_player.h"
 #include "video_decoder.h"
 
 using std::string;
 using std::pair;
 using std::max;
+using std::cout;
 using boost::shared_ptr;
 
 FilmViewer::FilmViewer (shared_ptr<Film> f, wxWindow* p)
@@ -74,6 +74,22 @@ FilmViewer::FilmViewer (shared_ptr<Film> f, wxWindow* p)
        set_film (_film);
 }
 
+void
+FilmViewer::film_changed (Film::Property p)
+{
+       switch (p) {
+       case Film::CROP:
+               calculate_sizes ();
+               update_from_raw ();
+               break;
+       case Film::FORMAT:
+               calculate_sizes ();
+               update_from_raw ();
+               break;
+       default:
+               break;
+       }
+}
 
 void
 FilmViewer::set_film (shared_ptr<Film> f)
@@ -91,8 +107,12 @@ FilmViewer::set_film (shared_ptr<Film> f)
        /* XXX: Options is not decoder-specific at all */
        shared_ptr<Options> o (new Options ("", "", ""));
        o->decode_audio = false;
+       o->decoder_alignment = false;
        _decoders = decoder_factory (_film, o, 0);
        _decoders.video->Video.connect (bind (&FilmViewer::process_video, this, _1, _2));
+
+       film_changed (Film::CROP);
+       film_changed (Film::FORMAT);
 }
 
 void
@@ -135,7 +155,10 @@ FilmViewer::paint_panel (wxPaintEvent& ev)
 void
 FilmViewer::slider_moved (wxCommandEvent& ev)
 {
-       _decoders.video->seek (_slider->GetValue() * _film->length().get() / 4096);
+       if (_decoders.video->seek (_slider->GetValue() * _film->length().get() / 4096)) {
+               return;
+       }
+       
        shared_ptr<Image> last = _display;
        while (last == _display) {
                _decoders.video->pass ();
@@ -150,12 +173,20 @@ FilmViewer::panel_sized (wxSizeEvent& ev)
        _panel_width = ev.GetSize().GetWidth();
        _panel_height = ev.GetSize().GetHeight();
        calculate_sizes ();
+       update_from_raw ();
+}
 
+void
+FilmViewer::update_from_raw ()
+{
        if (!_raw) {
                return;
        }
 
-       _display = _raw->scale_and_convert_to_rgb (Size (_out_width, _out_height), 0, Scaler::from_id ("bicubic"));
+       if (_out_width && _out_height) {
+               _display = _raw->scale_and_convert_to_rgb (Size (_out_width, _out_height), 0, Scaler::from_id ("bicubic"));
+       }
+       
        _panel->Refresh ();
        _panel->Update ();
 }
@@ -196,5 +227,7 @@ void
 FilmViewer::process_video (shared_ptr<Image> image, shared_ptr<Subtitle> sub)
 {
        _raw = image;
-       _display.reset (new CompactImage (_raw->scale_and_convert_to_rgb (Size (_out_width, _out_height), 0, Scaler::from_id ("bicubic"))));
+       if (_out_width && _out_height) {
+               _display = _raw->scale_and_convert_to_rgb (Size (_out_width, _out_height), 0, Scaler::from_id ("bicubic"));
+       }
 }
index f5427551db64319413d3407ef1bc666820514215..f0d4b628005ddb98ca140464b2223c9e37ad15d8 100644 (file)
@@ -50,6 +50,7 @@ private:
        void process_video (boost::shared_ptr<Image>, boost::shared_ptr<Subtitle>);
        void calculate_sizes ();
        void check_play_state ();
+       void update_from_raw ();
 
        boost::shared_ptr<Film> _film;