}
/* Set up the decoder to use the film's set streams */
- _da.first->set_subtitle_stream (_film_a->subtitle_stream ());
- _db.first->set_subtitle_stream (_film_a->subtitle_stream ());
- _da.second->set_audio_stream (_film_a->audio_stream ());
+ _da.video->set_subtitle_stream (_film_a->subtitle_stream ());
+ _db.video->set_subtitle_stream (_film_a->subtitle_stream ());
+ _da.audio->set_audio_stream (_film_a->audio_stream ());
- _da.first->Video.connect (bind (&Combiner::process_video, _combiner, _1, _2));
- _db.first->Video.connect (bind (&Combiner::process_video_b, _combiner, _1, _2));
+ _da.video->Video.connect (bind (&Combiner::process_video, _combiner, _1, _2));
+ _db.video->Video.connect (bind (&Combiner::process_video_b, _combiner, _1, _2));
if (_matcher) {
_combiner->connect_video (_matcher);
}
if (_matcher && _delay_line) {
- _da.second->connect_audio (_delay_line);
+ _da.audio->connect_audio (_delay_line);
_delay_line->connect_audio (_matcher);
_matcher->connect_audio (_gain);
_gain->connect_audio (_encoder);
_encoder->process_begin ();
while (1) {
- bool const va = _da.first->pass ();
- bool const vb = _db.first->pass ();
- bool const a = _da.first->pass ();
+ bool const va = _da.video->pass ();
+ bool const vb = _db.video->pass ();
+ bool const a = _da.audio->pass ();
- _da.first->set_progress ();
+ _da.video->set_progress ();
if (va && vb && a) {
break;
#include <boost/shared_ptr.hpp>
#include <stdint.h>
#include "util.h"
+#include "decoder_factory.h"
class Job;
class Encoder;
boost::shared_ptr<const Options> _opt;
Job* _job;
boost::shared_ptr<Encoder> _encoder;
- std::pair<boost::shared_ptr<VideoDecoder>, boost::shared_ptr<AudioDecoder> > _da;
- std::pair<boost::shared_ptr<VideoDecoder>, boost::shared_ptr<AudioDecoder> > _db;
+ Decoders _da;
+ Decoders _db;
boost::shared_ptr<Combiner> _combiner;
boost::shared_ptr<Matcher> _matcher;
boost::shared_ptr<DelayLine> _delay_line;
{
}
+
+void
+Decoder::seek (SourceFrame f)
+{
+ throw DecodeError ("decoder does not support seek");
+}
virtual ~Decoder () {}
virtual bool pass () = 0;
+ virtual void seek (SourceFrame);
protected:
/** our Film */
#include "imagemagick_decoder.h"
#include "film.h"
#include "external_audio_decoder.h"
+#include "decoder_factory.h"
using std::string;
using std::pair;
using boost::shared_ptr;
using boost::dynamic_pointer_cast;
-pair<shared_ptr<VideoDecoder>, shared_ptr<AudioDecoder> >
+Decoders
decoder_factory (
shared_ptr<Film> f, shared_ptr<const Options> o, Job* j
)
{
if (boost::filesystem::is_directory (f->content_path()) || f->content_type() == STILL) {
/* A single image file, or a directory of them */
- return make_pair (
+ return Decoders (
shared_ptr<VideoDecoder> (new ImageMagickDecoder (f, o, j)),
shared_ptr<AudioDecoder> ()
);
shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (f, o, j));
if (f->use_content_audio()) {
- return make_pair (fd, fd);
+ return Decoders (fd, fd);
}
- return make_pair (fd, shared_ptr<AudioDecoder> (new ExternalAudioDecoder (f, o, j)));
+ return Decoders (fd, shared_ptr<AudioDecoder> (new ExternalAudioDecoder (f, o, j)));
}
*/
+#ifndef DVDOMATIC_DECODER_FACTORY_H
+#define DVDOMATIC_DECODER_FACTORY_H
+
/** @file src/decoder_factory.h
* @brief A method to create appropriate decoders for some content.
*/
class VideoDecoder;
class AudioDecoder;
-extern std::pair<boost::shared_ptr<VideoDecoder>, boost::shared_ptr<AudioDecoder> > decoder_factory (
+struct Decoders {
+ Decoders () {}
+
+ Decoders (boost::shared_ptr<VideoDecoder> v, boost::shared_ptr<AudioDecoder> a)
+ : video (v)
+ , audio (a)
+ {}
+
+ boost::shared_ptr<VideoDecoder> video;
+ boost::shared_ptr<AudioDecoder> audio;
+};
+
+extern Decoders decoder_factory (
boost::shared_ptr<Film>, boost::shared_ptr<const Options>, Job *
);
+
+#endif
descend (1);
- pair<shared_ptr<VideoDecoder>, shared_ptr<AudioDecoder> > decoders = decoder_factory (_film, o, this);
+ Decoders decoders = decoder_factory (_film, o, this);
set_progress_unknown ();
- while (!decoders.first->pass()) {
+ while (!decoders.video->pass()) {
/* keep going */
}
- _film->set_length (decoders.first->video_frame());
+ _film->set_length (decoders.video->video_frame());
_film->log()->log (String::compose ("Video length is %1 frames", _film->length()));
}
}
+void
+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);
+ avcodec_flush_buffers (_video_codec_context);
+}
+
shared_ptr<FFmpegAudioStream>
FFmpegAudioStream::create (string t, optional<int> v)
{
return String::compose ("ffmpeg %1 %2 %3 %4", _id, _sample_rate, _channel_layout, _name);
}
+
void set_audio_stream (boost::shared_ptr<AudioStream>);
void set_subtitle_stream (boost::shared_ptr<SubtitleStream>);
+ void seek (SourceFrame);
+
private:
bool pass ();
shared_ptr<Options> o (new Options ("", "", ""));
o->out_size = Size (1024, 1024);
- pair<shared_ptr<VideoDecoder>, shared_ptr<AudioDecoder> > d = decoder_factory (shared_from_this(), o, 0);
+ Decoders d = decoder_factory (shared_from_this(), o, 0);
- set_size (d.first->native_size ());
- set_frames_per_second (d.first->frames_per_second ());
- set_subtitle_streams (d.first->subtitle_streams ());
- set_content_audio_streams (d.second->audio_streams ());
+ set_size (d.video->native_size ());
+ set_frames_per_second (d.video->frames_per_second ());
+ set_subtitle_streams (d.video->subtitle_streams ());
+ set_content_audio_streams (d.audio->audio_streams ());
/* Start off with the first audio and subtitle streams */
- if (!d.second->audio_streams().empty()) {
- set_content_audio_stream (d.second->audio_streams().front());
+ if (!d.audio->audio_streams().empty()) {
+ set_content_audio_stream (d.audio->audio_streams().front());
}
- if (!d.first->subtitle_streams().empty()) {
- set_subtitle_stream (d.first->subtitle_streams().front());
+ if (!d.video->subtitle_streams().empty()) {
+ set_subtitle_stream (d.video->subtitle_streams().front());
}
{
}
/* Set up the decoder to use the film's set streams */
- _decoders.first->set_subtitle_stream (f->subtitle_stream ());
- _decoders.second->set_audio_stream (f->audio_stream ());
+ _decoders.video->set_subtitle_stream (f->subtitle_stream ());
+ _decoders.audio->set_audio_stream (f->audio_stream ());
if (_matcher) {
- _decoders.first->connect_video (_matcher);
+ _decoders.video->connect_video (_matcher);
_matcher->connect_video (_encoder);
} else {
- _decoders.first->connect_video (_encoder);
+ _decoders.video->connect_video (_encoder);
}
if (_matcher && _delay_line) {
- _decoders.second->connect_audio (_delay_line);
+ _decoders.audio->connect_audio (_delay_line);
_delay_line->connect_audio (_matcher);
_matcher->connect_audio (_gain);
_gain->connect_audio (_encoder);
while (1) {
if (!done[0]) {
- done[0] = _decoders.first->pass ();
- _decoders.first->set_progress ();
+ done[0] = _decoders.video->pass ();
+ _decoders.video->set_progress ();
}
- if (!done[1] && dynamic_pointer_cast<Decoder> (_decoders.second) != dynamic_pointer_cast<Decoder> (_decoders.first)) {
- done[1] = _decoders.second->pass ();
+ if (!done[1] && dynamic_pointer_cast<Decoder> (_decoders.audio) != dynamic_pointer_cast<Decoder> (_decoders.video)) {
+ done[1] = _decoders.audio->pass ();
} else {
done[1] = true;
}
* as a parameter to the constructor.
*/
+#include "decoder_factory.h"
+
class Film;
class Job;
class Encoder;
/** The encoder that we will use */
boost::shared_ptr<Encoder> _encoder;
/** The decoders that we will use */
- std::pair<boost::shared_ptr<VideoDecoder>, boost::shared_ptr<AudioDecoder> > _decoders;
+ Decoders _decoders;
boost::shared_ptr<Matcher> _matcher;
boost::shared_ptr<DelayLine> _delay_line;
boost::shared_ptr<Gain> _gain;
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <wx/wx.h>
-#include <wx/tglbtn.h>
-#include <iostream>
-#include <stdint.h>
-extern "C" {
-#include <libavcodec/avcodec.h>
-#include <libavformat/avformat.h>
-#include <libswscale/swscale.h>
-}
-#include "lib/exceptions.h"
-#include "wx/ffmpeg_player.h"
-
-using namespace std;
-
-FFmpegPlayer::FFmpegPlayer (wxWindow* parent)
- : _format_context (0)
- , _video_stream (-1)
- , _frame (0)
- , _video_codec_context (0)
- , _video_codec (0)
- , _scale_context (0)
- , _frame_valid (false)
- , _last_frame_in_seconds (0)
- , _panel (new wxPanel (parent))
- , _slider (new wxSlider (parent, wxID_ANY, 0, 0, 4096))
- , _play_button (new wxToggleButton (parent, wxID_ANY, wxT ("Play")))
- , _panel_width (0)
- , _panel_height (0)
- , _full_width (0)
- , _full_height (0)
- , _top_crop_in_source (0)
- , _bottom_crop_in_source (0)
- , _left_crop_in_source (0)
- , _right_crop_in_source (0)
- , _ratio (1.85)
-{
- _rgb[0] = 0;
-
- avcodec_register_all ();
- av_register_all ();
-
- _frame = avcodec_alloc_frame ();
- if (!_frame) {
- throw DecodeError ("could not allocate frame");
- }
-
- _panel->Bind (wxEVT_PAINT, &FFmpegPlayer::paint_panel, this);
- _panel->Bind (wxEVT_SIZE, &FFmpegPlayer::panel_sized, this);
- _slider->Bind (wxEVT_SCROLL_THUMBTRACK, &FFmpegPlayer::slider_moved, this);
- _slider->Bind (wxEVT_SCROLL_PAGEUP, &FFmpegPlayer::slider_moved, this);
- _slider->Bind (wxEVT_SCROLL_PAGEDOWN, &FFmpegPlayer::slider_moved, this);
- _play_button->Bind (wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, &FFmpegPlayer::play_clicked, this);
- _timer.Bind (wxEVT_TIMER, &FFmpegPlayer::timer, this);
-}
-
-FFmpegPlayer::~FFmpegPlayer ()
-{
- delete[] _rgb[0];
-
- if (_scale_context) {
- sws_freeContext (_scale_context);
- }
-
- if (_video_codec_context) {
- avcodec_close (_video_codec_context);
- }
-
- av_free (_frame);
-
- if (_format_context) {
- avformat_close_input (&_format_context);
- }
-}
-
-void
-FFmpegPlayer::timer (wxTimerEvent& ev)
-{
- if (!can_display ()) {
- return;
- }
-
- _panel->Refresh ();
- _panel->Update ();
- decode_frame ();
- convert_frame ();
-
- if (_last_frame_in_seconds) {
- double const video_length_in_seconds = static_cast<double>(_format_context->duration) / AV_TIME_BASE;
- int const new_slider_position = 4096 * _last_frame_in_seconds / video_length_in_seconds;
- if (new_slider_position != _slider->GetValue()) {
- _slider->SetValue (new_slider_position);
- }
- }
-}
-
-void
-FFmpegPlayer::update_panel ()
-{
- _panel->Refresh ();
- _panel->Update ();
-}
-
-void
-FFmpegPlayer::decode_frame ()
-{
- assert (_format_context);
-
- while (1) {
- int r = av_read_frame (_format_context, &_packet);
- if (r < 0) {
- return;
- }
-
- avcodec_get_frame_defaults (_frame);
- if (_packet.stream_index == _video_stream) {
- int frame_finished;
- int const r = avcodec_decode_video2 (_video_codec_context, _frame, &frame_finished, &_packet);
- if (r >= 0 && frame_finished) {
- _frame_valid = true;
- _last_frame_in_seconds = av_q2d (_format_context->streams[_packet.stream_index]->time_base)
- * av_frame_get_best_effort_timestamp(_frame);
- av_free_packet (&_packet);
- return;
- }
- }
-
- av_free_packet (&_packet);
- }
-}
-
-void
-FFmpegPlayer::convert_frame ()
-{
- if (!_scale_context || !_rgb[0] || !_frame_valid) {
- return;
- }
-
- sws_scale (
- _scale_context,
- _frame->data, _frame->linesize,
- 0, _video_codec_context->height,
- _rgb, _rgb_stride
- );
-
- uint8_t* in = _rgb[0];
- uint8_t* out = _rgb[0];
-
- in += top_crop_in_view() * _full_width * 3;
- for (int y = 0; y < cropped_height_in_view(); ++y) {
- /* in is the start of the appropriate full-width line */
- memmove (out, in + left_crop_in_view() * 3, cropped_width_in_view() * 3);
- in += _full_width * 3;
- out += cropped_width_in_view() * 3;
- }
-}
-
-void
-FFmpegPlayer::paint_panel (wxPaintEvent& ev)
-{
- wxPaintDC dc (_panel);
-
- wxImage i (cropped_width_in_view(), cropped_height_in_view(), _rgb[0], true);
- wxBitmap b (i);
- dc.DrawBitmap (b, 0, 0);
-}
-
-void
-FFmpegPlayer::slider_moved (wxCommandEvent& ev)
-{
- if (!can_display ()) {
- return;
- }
-
- double const video_length_in_seconds = static_cast<double>(_format_context->duration) / AV_TIME_BASE;
- double const new_position_in_seconds = video_length_in_seconds * _slider->GetValue() / 4096;
- int64_t const t = static_cast<int64_t>(new_position_in_seconds) / av_q2d (_format_context->streams[_video_stream]->time_base);
- av_seek_frame (_format_context, _video_stream, t, 0);
- avcodec_flush_buffers (_video_codec_context);
-
- decode_frame ();
- convert_frame ();
- update_panel ();
-}
-
-float
-FFmpegPlayer::frames_per_second () const
-{
- assert (_format_context);
-
- AVStream* s = _format_context->streams[_video_stream];
-
- if (s->avg_frame_rate.num && s->avg_frame_rate.den) {
- return av_q2d (s->avg_frame_rate);
- }
-
- return av_q2d (s->r_frame_rate);
-}
-
-void
-FFmpegPlayer::allocate_buffer_and_scaler ()
-{
- if (!_format_context || !_panel_width || !_panel_height) {
- return;
- }
-
- float const panel_ratio = static_cast<float> (_panel_width) / _panel_height;
-
- int new_width;
- int new_height;
- if (panel_ratio < _ratio) {
- /* panel is less widescreen than the target ratio; clamp width */
- new_width = _panel_width;
- new_height = new_width / _ratio;
- } else {
- /* panel is more widescreen than the target ratio; clamp height */
- new_height = _panel_height;
- new_width = new_height * _ratio;
- }
-
- if (new_width == 0 || new_height == 0) {
- return;
- }
-
- _full_height = new_height + ((_top_crop_in_source + _bottom_crop_in_source) * height_source_to_view_scaling());
- _full_width = new_width + ((_left_crop_in_source + _right_crop_in_source) * width_source_to_view_scaling());
-
- delete[] _rgb[0];
-
- _rgb[0] = new uint8_t[_full_width * _full_height * 3];
- memset (_rgb[0], 0, _full_width * _full_height * 3);
- _rgb_stride[0] = _full_width * 3;
-
- if (_scale_context) {
- sws_freeContext (_scale_context);
- }
-
- _scale_context = sws_getContext (
- _video_codec_context->width, _video_codec_context->height, _video_codec_context->pix_fmt,
- _full_width, _full_height, PIX_FMT_RGB24,
- SWS_BICUBIC, 0, 0, 0
- );
-
- if (!_scale_context) {
- throw DecodeError ("could not create scaler");
- }
-}
-
-float
-FFmpegPlayer::width_source_to_view_scaling () const
-{
- return static_cast<float> (_full_width) / _video_codec_context->width;
-}
-
-float
-FFmpegPlayer::height_source_to_view_scaling () const
-{
- return static_cast<float> (_full_height) / _video_codec_context->height;
-}
-
-int
-FFmpegPlayer::cropped_width_in_view () const
-{
- return _full_width - ((_left_crop_in_source + _right_crop_in_source) * width_source_to_view_scaling());
-}
-
-int
-FFmpegPlayer::cropped_height_in_view () const
-{
- return _full_height - ((_top_crop_in_source + _bottom_crop_in_source) * height_source_to_view_scaling());
-}
-
-int
-FFmpegPlayer::left_crop_in_view () const
-{
- return _left_crop_in_source * width_source_to_view_scaling();
-}
-
-int
-FFmpegPlayer::top_crop_in_view () const
-{
- return _top_crop_in_source * height_source_to_view_scaling();
-}
-
-void
-FFmpegPlayer::panel_sized (wxSizeEvent& ev)
-{
- _panel_width = ev.GetSize().GetWidth();
- _panel_height = ev.GetSize().GetHeight();
- allocate_buffer_and_scaler ();
-
- convert_frame ();
- update_panel ();
-}
-
-void
-FFmpegPlayer::set_file (string f)
-{
- if (_video_codec_context) {
- avcodec_close (_video_codec_context);
- }
-
- if (_format_context) {
- avformat_close_input (&_format_context);
- }
-
- if (avformat_open_input (&_format_context, f.c_str(), 0, 0) < 0) {
- throw OpenFileError (f);
- }
-
- if (avformat_find_stream_info (_format_context, 0) < 0) {
- throw DecodeError ("could not find stream information");
- }
-
- for (uint32_t i = 0; i < _format_context->nb_streams; ++i) {
- AVStream* s = _format_context->streams[i];
- if (s->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
- _video_stream = i;
- } else if (s->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
- /* XXX */
- }
- }
-
- if (_video_stream < 0) {
- throw DecodeError ("could not find video stream");
- }
-
- _video_codec_context = _format_context->streams[_video_stream]->codec;
- _video_codec = avcodec_find_decoder (_video_codec_context->codec_id);
-
- if (_video_codec == 0) {
- throw DecodeError ("could not find video stream");
- }
-
- if (avcodec_open2 (_video_codec_context, _video_codec, 0) < 0) {
- throw DecodeError ("could not open video decoder");
- }
-
- allocate_buffer_and_scaler ();
- check_play_state ();
- update_panel ();
-}
-
-void
-FFmpegPlayer::set_top_crop (int t)
-{
- _top_crop_in_source = t;
-
- allocate_buffer_and_scaler ();
- convert_frame ();
- update_panel ();
-}
-
-void
-FFmpegPlayer::set_bottom_crop (int b)
-{
- _bottom_crop_in_source = b;
-
- allocate_buffer_and_scaler ();
- convert_frame ();
- update_panel ();
-}
-
-void
-FFmpegPlayer::set_left_crop (int l)
-{
- _left_crop_in_source = l;
-
- allocate_buffer_and_scaler ();
- convert_frame ();
- update_panel ();
-}
-
-void
-FFmpegPlayer::set_right_crop (int r)
-{
- _right_crop_in_source = r;
-
- allocate_buffer_and_scaler ();
- convert_frame ();
- update_panel ();
-}
-
-void
-FFmpegPlayer::set_ratio (float r)
-{
- _ratio = r;
-
- allocate_buffer_and_scaler ();
- convert_frame ();
- update_panel ();
-}
-
-void
-FFmpegPlayer::play_clicked (wxCommandEvent &)
-{
- check_play_state ();
-}
-
-void
-FFmpegPlayer::check_play_state ()
-{
- if (_play_button->GetValue()) {
- _timer.Start (1000 / frames_per_second());
- } else {
- _timer.Stop ();
- }
-}
-
-bool
-FFmpegPlayer::can_display () const
-{
- return (_format_context && _scale_context);
-}
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <wx/wx.h>
-#include <stdint.h>
-extern "C" {
-#include <libavcodec/avcodec.h>
-#include <libavformat/avformat.h>
-#include <libswscale/swscale.h>
-}
-
-class wxToggleButton;
-
-class FFmpegPlayer
-{
-public:
- FFmpegPlayer (wxWindow* parent);
- ~FFmpegPlayer ();
-
- void set_file (std::string);
-
- wxPanel* panel () const {
- return _panel;
- }
-
- wxSlider* slider () const {
- return _slider;
- }
-
- wxToggleButton* play_button () const {
- return _play_button;
- }
-
- void set_top_crop (int t);
- void set_bottom_crop (int b);
- void set_left_crop (int l);
- void set_right_crop (int r);
- void set_ratio (float r);
-
-private:
- void timer (wxTimerEvent& ev);
- void decode_frame ();
- void convert_frame ();
- void paint_panel (wxPaintEvent& ev);
- void slider_moved (wxCommandEvent& ev);
- float frames_per_second () const;
- void allocate_buffer_and_scaler ();
- float width_source_to_view_scaling () const;
- float height_source_to_view_scaling () const;
- int cropped_width_in_view () const;
- int cropped_height_in_view () const;
- int left_crop_in_view () const;
- int top_crop_in_view () const;
- void panel_sized (wxSizeEvent &);
- void play_clicked (wxCommandEvent &);
- void check_play_state ();
- void update_panel ();
- bool can_display () const;
-
- AVFormatContext* _format_context;
- int _video_stream;
- AVFrame* _frame;
- AVCodecContext* _video_codec_context;
- AVCodec* _video_codec;
- AVPacket _packet;
- struct SwsContext* _scale_context;
- bool _frame_valid;
- uint8_t* _rgb[1];
- int _rgb_stride[1];
- double _last_frame_in_seconds;
-
- wxPanel* _panel;
- wxSlider* _slider;
- wxToggleButton* _play_button;
-
- wxTimer _timer;
- int _panel_width;
- int _panel_height;
- int _full_width;
- int _full_height;
- int _top_crop_in_source;
- int _bottom_crop_in_source;
- int _left_crop_in_source;
- int _right_crop_in_source;
- float _ratio;
-};
#include "lib/job_manager.h"
#include "lib/options.h"
#include "lib/subtitle.h"
+#include "lib/image.h"
+#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;
FilmViewer::FilmViewer (shared_ptr<Film> f, wxWindow* p)
: wxPanel (p)
- , _player (new FFmpegPlayer (this))
+ , _panel (new wxPanel (this))
+ , _slider (new wxSlider (this, wxID_ANY, 0, 0, 4096))
+ , _play_button (new wxToggleButton (this, wxID_ANY, wxT ("Play")))
+ , _out_width (0)
+ , _out_height (0)
+ , _panel_width (0)
+ , _panel_height (0)
{
wxBoxSizer* v_sizer = new wxBoxSizer (wxVERTICAL);
SetSizer (v_sizer);
- v_sizer->Add (_player->panel(), 1, wxEXPAND);
+ v_sizer->Add (_panel, 1, wxEXPAND);
wxBoxSizer* h_sizer = new wxBoxSizer (wxHORIZONTAL);
- h_sizer->Add (_player->play_button(), 0, wxEXPAND);
- h_sizer->Add (_player->slider(), 1, wxEXPAND);
+ h_sizer->Add (_play_button, 0, wxEXPAND);
+ h_sizer->Add (_slider, 1, wxEXPAND);
v_sizer->Add (h_sizer, 0, wxEXPAND);
+ _panel->Bind (wxEVT_PAINT, &FilmViewer::paint_panel, this);
+ _panel->Bind (wxEVT_SIZE, &FilmViewer::panel_sized, this);
+ _slider->Bind (wxEVT_SCROLL_THUMBTRACK, &FilmViewer::slider_moved, this);
+ _slider->Bind (wxEVT_SCROLL_PAGEUP, &FilmViewer::slider_moved, this);
+ _slider->Bind (wxEVT_SCROLL_PAGEDOWN, &FilmViewer::slider_moved, this);
+ _play_button->Bind (wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, &FilmViewer::play_clicked, this);
+ _timer.Bind (wxEVT_TIMER, &FilmViewer::timer, this);
+
set_film (_film);
}
+
void
-FilmViewer::film_changed (Film::Property p)
+FilmViewer::set_film (shared_ptr<Film> f)
{
- ensure_ui_thread ();
+ if (_film == f) {
+ return;
+ }
- switch (p) {
-
- case Film::CONTENT:
- _player->set_file (_film->content_path ());
- break;
-
- case Film::CROP:
- {
- Crop c = _film->crop ();
- _player->set_left_crop (c.left);
- _player->set_right_crop (c.right);
- _player->set_top_crop (c.top);
- _player->set_bottom_crop (c.bottom);
+ _film = f;
+
+ if (!_film) {
+ return;
+ }
+
+ /* XXX: Options is not decoder-specific at all */
+ shared_ptr<Options> o (new Options ("", "", ""));
+ o->decode_audio = false;
+ _decoders = decoder_factory (_film, o, 0);
+ _decoders.video->Video.connect (bind (&FilmViewer::process_video, this, _1, _2));
+}
+
+void
+FilmViewer::timer (wxTimerEvent& ev)
+{
+ _panel->Refresh ();
+ _panel->Update ();
+
+ shared_ptr<Image> last = _display;
+ while (last == _display) {
+ _decoders.video->pass ();
}
- break;
- case Film::FORMAT:
- if (_film->format()) {
- _player->set_ratio (_film->format()->ratio_as_float(_film));
+#if 0
+ if (_last_frame_in_seconds) {
+ double const video_length_in_seconds = static_cast<double>(_format_context->duration) / AV_TIME_BASE;
+ int const new_slider_position = 4096 * _last_frame_in_seconds / video_length_in_seconds;
+ if (new_slider_position != _slider->GetValue()) {
+ _slider->SetValue (new_slider_position);
}
- break;
-
- default:
- break;
}
+#endif
}
+
void
-FilmViewer::set_film (shared_ptr<Film> f)
+FilmViewer::paint_panel (wxPaintEvent& ev)
{
- if (_film == f) {
+ wxPaintDC dc (_panel);
+ if (!_display) {
return;
}
-
- _film = f;
- if (!_film) {
+ wxImage i (_out_width, _out_height, _display->data()[0], true);
+ wxBitmap b (i);
+ dc.DrawBitmap (b, 0, 0);
+}
+
+
+void
+FilmViewer::slider_moved (wxCommandEvent& ev)
+{
+ _decoders.video->seek (_slider->GetValue() * _film->length().get() / 4096);
+ shared_ptr<Image> last = _display;
+ while (last == _display) {
+ _decoders.video->pass ();
+ }
+ _panel->Refresh ();
+ _panel->Update ();
+}
+
+void
+FilmViewer::panel_sized (wxSizeEvent& ev)
+{
+ _panel_width = ev.GetSize().GetWidth();
+ _panel_height = ev.GetSize().GetHeight();
+ calculate_sizes ();
+
+ if (!_raw) {
return;
}
- _film->Changed.connect (bind (&FilmViewer::film_changed, this, _1));
- film_changed (Film::CONTENT);
- film_changed (Film::CROP);
- film_changed (Film::FORMAT);
+ _display = _raw->scale_and_convert_to_rgb (Size (_out_width, _out_height), 0, Scaler::from_id ("bicubic"));
+ _panel->Refresh ();
+ _panel->Update ();
+}
+
+void
+FilmViewer::calculate_sizes ()
+{
+ float const panel_ratio = static_cast<float> (_panel_width) / _panel_height;
+ float const film_ratio = _film->format() ? _film->format()->ratio_as_float(_film) : 1.78;
+ if (panel_ratio < film_ratio) {
+ /* panel is less widscreen than the film; clamp width */
+ _out_width = _panel_width;
+ _out_height = _out_width / film_ratio;
+ } else {
+ /* panel is more widescreen than the film; clamp heignt */
+ _out_height = _panel_height;
+ _out_width = _out_height * film_ratio;
+ }
+}
+
+void
+FilmViewer::play_clicked (wxCommandEvent &)
+{
+ check_play_state ();
+}
+
+void
+FilmViewer::check_play_state ()
+{
+ if (_play_button->GetValue()) {
+ _timer.Start (1000 / _film->frames_per_second());
+ } else {
+ _timer.Stop ();
+ }
+}
+
+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"))));
}
#include <wx/wx.h>
#include "lib/film.h"
+#include "lib/decoder_factory.h"
+class wxToggleButton;
class FFmpegPlayer;
+class Image;
+class Subtitle;
/** @class FilmViewer
* @brief A wx widget to view a preview of a Film.
private:
void film_changed (Film::Property);
+ void paint_panel (wxPaintEvent &);
+ void panel_sized (wxSizeEvent &);
+ void slider_moved (wxCommandEvent &);
+ void play_clicked (wxCommandEvent &);
+ void timer (wxTimerEvent &);
+ void process_video (boost::shared_ptr<Image>, boost::shared_ptr<Subtitle>);
+ void calculate_sizes ();
+ void check_play_state ();
boost::shared_ptr<Film> _film;
- FFmpegPlayer* _player;
+
+ wxPanel* _panel;
+ wxSlider* _slider;
+ wxToggleButton* _play_button;
+ wxTimer _timer;
+
+ Decoders _decoders;
+ boost::shared_ptr<Image> _raw;
+ boost::shared_ptr<Image> _display;
+
+ int _out_width;
+ int _out_height;
+ int _panel_width;
+ int _panel_height;
};
film_viewer.cc
filter_dialog.cc
filter_view.cc
- ffmpeg_player.cc
gain_calculator_dialog.cc
job_manager_view.cc
job_wrapper.cc