+/*
+ Copyright (C) 2013 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.
+
+*/
+
#ifndef DVDOMATIC_CONTENT_H
#define DVDOMATIC_CONTENT_H
virtual bool seek (double);
virtual bool seek_to_last ();
- boost::signals2::signal<void()> OutputChanged;
-
protected:
boost::shared_ptr<const Film> _film;
static int const _history_size;
/** Number of video frames received so far */
- SourceFrame _video_frames_in;
+ ContentVideoFrame _video_frames_in;
/** Number of video frames written for the DCP so far */
int _video_frames_out;
+/*
+ Copyright (C) 2013 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 <libcxml/cxml.h>
#include "ffmpeg_content.h"
#include "ffmpeg_decoder.h"
+/*
+ Copyright (C) 2013 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.
+
+*/
+
#ifndef DVDOMATIC_FFMPEG_CONTENT_H
#define DVDOMATIC_FFMPEG_CONTENT_H
boost::mutex::scoped_lock lm (_filter_graphs_mutex);
_filter_graphs.clear ();
}
- OutputChanged ();
break;
default:
examine_content (c);
}
+void
+Film::remove_content (shared_ptr<Content> c)
+{
+ {
+ boost::mutex::scoped_lock lm (_state_mutex);
+ ContentList::iterator i = find (_content.begin(), _content.end(), c);
+ if (i != _content.end ()) {
+ _content.erase (i);
+ }
+ }
+
+ signal_changed (CONTENT);
+}
+
+void
+Film::move_content_earlier (shared_ptr<Content> c)
+{
+ {
+ boost::mutex::scoped_lock lm (_state_mutex);
+ ContentList::iterator i = find (_content.begin(), _content.end(), c);
+ if (i == _content.begin () || i == _content.end()) {
+ return;
+ }
+
+ ContentList::iterator j = i;
+ --j;
+
+ swap (*i, *j);
+ }
+
+ signal_changed (CONTENT);
+}
+
+void
+Film::move_content_later (shared_ptr<Content> c)
+{
+ {
+ boost::mutex::scoped_lock lm (_state_mutex);
+ ContentList::iterator i = find (_content.begin(), _content.end(), c);
+ if (i == _content.end()) {
+ return;
+ }
+
+ ContentList::iterator j = i;
+ ++j;
+ if (j == _content.end ()) {
+ return;
+ }
+
+ swap (*i, *j);
+ }
+
+ signal_changed (CONTENT);
+
+}
+
ContentAudioFrame
Film::audio_length () const
{
#include "dcp_content_type.h"
#include "util.h"
#include "dci_metadata.h"
+#include "types.h"
class Format;
class Job;
return _trust_content_headers;
}
- std::list<boost::shared_ptr<Content> > content () const {
+ ContentList content () const {
boost::mutex::scoped_lock lm (_state_mutex);
return _content;
}
void set_use_dci_name (bool);
void set_trust_content_headers (bool);
void add_content (boost::shared_ptr<Content>);
+ void remove_content (boost::shared_ptr<Content>);
+ void move_content_earlier (boost::shared_ptr<Content>);
+ void move_content_later (boost::shared_ptr<Content>);
void set_dcp_content_type (DCPContentType const *);
void set_format (Format const *);
void set_crop (Crop);
std::string _name;
/** True if a auto-generated DCI-compliant name should be used for our DCP */
bool _use_dci_name;
- typedef std::list<boost::shared_ptr<Content> > ContentList;
ContentList _content;
bool _trust_content_headers;
/** The type of content that this Film represents (feature, trailer etc.) */
+/*
+ Copyright (C) 2013 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 <libcxml/cxml.h>
#include "imagemagick_content.h"
+#include "imagemagick_decoder.h"
#include "compose.hpp"
#include "i18n.h"
: Content (f)
, VideoContent (f)
{
- /* XXX */
- _video_length = 10 * 24;
+
}
ImageMagickContent::ImageMagickContent (shared_ptr<const cxml::Node> node)
transform (ext.begin(), ext.end(), ext.begin(), ::tolower);
return (ext == ".tif" || ext == ".tiff" || ext == ".jpg" || ext == ".jpeg" || ext == ".png" || ext == ".bmp");
}
+
+void
+ImageMagickContent::as_xml (xmlpp::Node* node) const
+{
+ node->add_child("Type")->add_child_text ("ImageMagick");
+ Content::as_xml (node);
+ VideoContent::as_xml (node);
+}
+
+void
+ImageMagickContent::examine (shared_ptr<Film> film, shared_ptr<Job> job, bool quick)
+{
+ Content::examine (film, job, quick);
+ shared_ptr<ImageMagickDecoder> decoder (new ImageMagickDecoder (film, shared_from_this()));
+
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ /* XXX */
+ _video_length = 10 * 24;
+ }
+
+ take_from_video_decoder (decoder);
+}
+/*
+ Copyright (C) 2013 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 <boost/enable_shared_from_this.hpp>
#include "video_content.h"
namespace cxml {
class Node;
}
-class ImageMagickContent : public VideoContent
+class ImageMagickContent : public VideoContent, public boost::enable_shared_from_this<ImageMagickContent>
{
public:
ImageMagickContent (boost::filesystem::path);
ImageMagickContent (boost::shared_ptr<const cxml::Node>);
+ void examine (boost::shared_ptr<Film>, boost::shared_ptr<Job>, bool);
std::string summary () const;
+ void as_xml (xmlpp::Node *) const;
static bool valid_file (boost::filesystem::path);
};
return s;
}
+int
+ImageMagickDecoder::video_length () const
+{
+ return _imagemagick_content->video_length ();
+}
+
bool
ImageMagickDecoder::pass ()
{
_position = f;
return false;
}
-
-void
-ImageMagickDecoder::film_changed (Film::Property p)
-{
- if (p == Film::CROP) {
- OutputChanged ();
- }
-}
ImageMagickDecoder (boost::shared_ptr<const Film>, boost::shared_ptr<const ImageMagickContent>);
float frames_per_second () const {
- /* We don't know */
- return 0;
+ return 24;
}
libdcp::Size native_size () const;
-
- ContentVideoFrame video_length () const {
- /* We don't know */
- return 0;
- }
+ ContentVideoFrame video_length () const;
int audio_channels () const {
return 0;
}
private:
- void film_changed (Film::Property);
-
boost::shared_ptr<const ImageMagickContent> _imagemagick_content;
ContentVideoFrame _position;
};
#include "imagemagick_decoder.h"
using std::list;
+using std::cout;
using boost::shared_ptr;
using boost::dynamic_pointer_cast;
}
void
-Playlist::setup (list<shared_ptr<Content> > content)
+Playlist::setup (ContentList content)
{
_video_from = VIDEO_NONE;
_audio_from = AUDIO_NONE;
- for (list<shared_ptr<Content> >::const_iterator i = content.begin(); i != content.end(); ++i) {
+ for (ContentList::const_iterator i = content.begin(); i != content.end(); ++i) {
shared_ptr<FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (*i);
if (fc) {
assert (!_ffmpeg);
Audio (b);
}
+/** @return true on error */
bool
Player::seek (double t)
{
bool r = false;
-
+
switch (_playlist->video_from()) {
case Playlist::VIDEO_NONE:
break;
}
break;
case Playlist::VIDEO_IMAGEMAGICK:
- if ((*_imagemagick_decoder)->seek (t)) {
+ /* Find the decoder that contains this position */
+ _imagemagick_decoder = _imagemagick_decoders.begin ();
+ while (_imagemagick_decoder != _imagemagick_decoders.end ()) {
+ double const this_length = (*_imagemagick_decoder)->video_length() / _film->video_frame_rate ();
+ if (this_length < t) {
+ break;
+ }
+ t -= this_length;
+ ++_imagemagick_decoder;
+ }
+
+ if (_imagemagick_decoder != _imagemagick_decoders.end()) {
+ (*_imagemagick_decoder)->seek (t);
+ } else {
r = true;
}
break;
public:
Playlist ();
- void setup (std::list<boost::shared_ptr<Content> >);
+ void setup (ContentList);
ContentAudioFrame audio_length () const;
int audio_channels () const;
return 96000;
}
-bool operator== (Crop const & a, Crop const & b)
-{
- return (a.left == b.left && a.right == b.right && a.top == b.top && a.bottom == b.bottom);
-}
-
-bool operator!= (Crop const & a, Crop const & b)
-{
- return !(a == b);
-}
-
/** @param index Colour LUT index.
* @return Human-readable name.
*/
assert (this_thread::get_id() == ui_thread);
}
-/** @param v Source video frame.
+/** @param v Content video frame.
* @param audio_sample_rate Source audio sample rate.
* @param frames_per_second Number of video frames per second.
* @return Equivalent number of audio frames for `v'.
*/
int64_t
-video_frames_to_audio_frames (SourceFrame v, float audio_sample_rate, float frames_per_second)
+video_frames_to_audio_frames (ContentVideoFrame v, float audio_sample_rate, float frames_per_second)
{
return ((int64_t) v * audio_sample_rate / frames_per_second);
}
#include <libavfilter/avfilter.h>
}
#include "compose.hpp"
+#include "types.h"
#ifdef DVDOMATIC_DEBUG
#define TIMING(...) _film->log()->microsecond_log (String::compose (__VA_ARGS__), Log::TIMING);
extern boost::filesystem::path mo_path ();
#endif
-typedef int SourceFrame;
-typedef int64_t ContentAudioFrame;
-typedef int ContentVideoFrame;
-
struct FrameRateConversion
{
FrameRateConversion (float, int);
int best_dcp_frame_rate (float);
-/** @struct Crop
- * @brief A description of the crop of an image or video.
- */
-struct Crop
-{
- Crop () : left (0), right (0), top (0), bottom (0) {}
-
- /** Number of pixels to remove from the left-hand side */
- int left;
- /** Number of pixels to remove from the right-hand side */
- int right;
- /** Number of pixels to remove from the top */
- int top;
- /** Number of pixels to remove from the bottom */
- int bottom;
-};
-
-extern bool operator== (Crop const & a, Crop const & b);
-extern bool operator!= (Crop const & a, Crop const & b);
-
-/** @struct Position
- * @brief A position.
- */
-struct Position
-{
- Position ()
- : x (0)
- , y (0)
- {}
-
- Position (int x_, int y_)
- : x (x_)
- , y (y_)
- {}
-
- /** x coordinate */
- int x;
- /** y coordinate */
- int y;
-};
-
-/** @struct Rect
- * @brief A rectangle.
- */
-struct Rect
-{
- Rect ()
- : x (0)
- , y (0)
- , width (0)
- , height (0)
- {}
-
- Rect (int x_, int y_, int w_, int h_)
- : x (x_)
- , y (y_)
- , width (w_)
- , height (h_)
- {}
-
- int x;
- int y;
- int width;
- int height;
-
- Position position () const {
- return Position (x, y);
- }
-
- libdcp::Size size () const {
- return libdcp::Size (width, height);
- }
-
- Rect intersection (Rect const & other) const;
-};
-
extern std::string crop_string (Position, libdcp::Size);
extern int dcp_audio_sample_rate (int);
extern std::string colour_lut_index_to_name (int index);
int _source_channels;
};
-extern int64_t video_frames_to_audio_frames (SourceFrame v, float audio_sample_rate, float frames_per_second);
+extern int64_t video_frames_to_audio_frames (ContentVideoFrame v, float audio_sample_rate, float frames_per_second);
extern std::pair<std::string, int> cpu_info ();
#endif
void
VideoContent::take_from_video_decoder (shared_ptr<VideoDecoder> d)
{
+ /* These decoder calls could call other content methods which take a lock on the mutex */
+ libdcp::Size const vs = d->native_size ();
+ float const vfr = d->frames_per_second ();
+
{
boost::mutex::scoped_lock lm (_mutex);
- _video_size = d->native_size ();
- _video_frame_rate = d->frames_per_second ();
+ _video_size = vs;
+ _video_frame_rate = vfr;
}
Changed (VideoContentProperty::VIDEO_SIZE);
timer.cc
transcode_job.cc
transcoder.cc
+ types.cc
ui_signaller.cc
util.cc
version.cc
_trust_content_headers->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::trust_content_headers_changed), 0, this);
_content->Connect (wxID_ANY, wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler (FilmEditor::content_item_selected), 0, this);
_content_add->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::content_add_clicked), 0, this);
- _content_remove->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::content_add_clicked), 0, this);
- _content_earlier->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::content_add_clicked), 0, this);
- _content_later->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::content_add_clicked), 0, this);
+ _content_remove->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::content_remove_clicked), 0, this);
+ _content_earlier->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::content_earlier_clicked), 0, this);
+ _content_later->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::content_later_clicked), 0, this);
_left_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::left_crop_changed), 0, this);
_right_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::right_crop_changed), 0, this);
_top_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::top_crop_changed), 0, this);
return;
}
-// _film->set_dcp_frame_rate (best_dcp_frame_rate (_film->source_frame_rate ()));
+ _film->set_dcp_frame_rate (best_dcp_frame_rate (_film->video_frame_rate ()));
}
void
FilmEditor::setup_show_audio_sensitivity ()
{
-// _show_audio->Enable (_film && _film->has_audio ());
+ _show_audio->Enable (_film && _film->has_audio ());
}
void
{
_content->DeleteAllItems ();
- list<shared_ptr<Content> > content = _film->content ();
- for (list<shared_ptr<Content> >::iterator i = content.begin(); i != content.end(); ++i) {
+ ContentList content = _film->content ();
+ for (ContentList::iterator i = content.begin(); i != content.end(); ++i) {
_content->InsertItem (_content->GetItemCount(), std_to_wx ((*i)->summary ()));
}
}
void
FilmEditor::content_remove_clicked (wxCommandEvent &)
{
+ int const s = _content->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
+ if (s == -1) {
+ return;
+ }
+ ContentList c = _film->content ();
+ assert (s >= 0 && size_t (s) < c.size ());
+ _film->remove_content (c[s]);
}
void
FilmEditor::content_earlier_clicked (wxCommandEvent &)
{
+ int const s = _content->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
+ if (s == -1) {
+ return;
+ }
+ ContentList c = _film->content ();
+ assert (s >= 0 && size_t (s) < c.size ());
+ _film->move_content_earlier (c[s]);
}
void
FilmEditor::content_later_clicked (wxCommandEvent &)
{
+ int const s = _content->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
+ if (s == -1) {
+ return;
+ }
+ ContentList c = _film->content ();
+ assert (s >= 0 && size_t (s) < c.size ());
+ _film->move_content_later (c[s]);
}
void
_player->disable_video_sync ();
_player->Video.connect (bind (&FilmViewer::process_video, this, _1, _2, _3));
-// _player->OutputChanged.connect (boost::bind (&FilmViewer::decoder_changed, this));
calculate_sizes ();
get_frame ();
_panel->Refresh ();
case Film::SUBTITLE_SCALE:
case Film::SCALER:
case Film::FILTERS:
- update_from_raw ();
- break;
- case Film::SUBTITLE_STREAM:
-// if (_decoders.video) {
-// _decoders.video->set_subtitle_stream (_film->subtitle_stream ());
-// }
+ case Film::CROP:
+ update_from_decoder ();
break;
default:
break;
}
void
-FilmViewer::decoder_changed ()
+FilmViewer::update_from_decoder ()
{
if (!_player || _player->seek_to_last ()) {
return;
if (!_film || !_player) {
return;
}
-
+
if (_player->seek (_slider->GetValue() * _film->video_length() / (4096 * _film->video_frame_rate()))) {
return;
}
_got_frame = true;
}
+/** Get a new _raw_frame from the decoder and then do
+ * raw_to_display ().
+ */
void
FilmViewer::get_frame ()
{
void calculate_sizes ();
void check_play_state ();
void update_from_raw ();
- void decoder_changed ();
+ void update_from_decoder ();
void raw_to_display ();
void get_frame ();
void active_jobs_changed (bool);