AnalyseAudioJob::AnalyseAudioJob (shared_ptr<Film> f)
: Job (f)
- , _next (0)
+ , _done (0)
, _samples_per_point (1)
{
_current.resize (MAX_AUDIO_CHANNELS);
_analysis.reset (new AudioAnalysis (MAX_AUDIO_CHANNELS));
- _next = 0;
- while (_next < _film->length()) {
- set_progress (double (_next) / _film->length ());
+ _done = 0;
+ while (player->pass ()) {
+ set_progress (double (_done) / _film->length ());
}
_analysis->write (_film->audio_analysis_path ());
}
}
- _next = (t + _film->audio_frames_to_time (b->frames()));
+ _done = t;
}
void run ();
private:
- void audio (boost::shared_ptr<const AudioBuffers>);
+ void audio (boost::shared_ptr<const AudioBuffers>, Time);
- Time _next;
+ Time _done;
int64_t _samples_per_point;
std::vector<AudioPoint> _current;
int const AudioContentProperty::AUDIO_GAIN = 203;
int const AudioContentProperty::AUDIO_DELAY = 204;
+AudioContent::AudioContent (Time s)
+ : Content (s)
+ , _audio_gain (0)
+ , _audio_delay (0)
+{
+
+}
+
AudioContent::AudioContent (boost::filesystem::path f)
: Content (f)
, _audio_gain (0)
class AudioContent : public virtual Content
{
public:
+ AudioContent (Time);
AudioContent (boost::filesystem::path);
AudioContent (boost::shared_ptr<const cxml::Node>);
AudioContent (AudioContent const &);
#endif
void
-AudioDecoder::emit_audio (shared_ptr<const AudioBuffers> data, Time time)
+AudioDecoder::audio (shared_ptr<const AudioBuffers> data, Time time)
{
/* XXX: map audio to 5.1 */
AudioDecoder (boost::shared_ptr<const Film>, boost::shared_ptr<const AudioContent>);
~AudioDecoder ();
- void emit_audio (boost::shared_ptr<const AudioBuffers>, Time);
-
protected:
+
+ void audio (boost::shared_ptr<const AudioBuffers>, Time);
+
Time _next_audio;
private:
+/*
+ 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 "black_decoder.h"
-BlackDecoder::BlackDecoder (shared_ptr<NullContent> c)
- : Decoder (c)
+BlackDecoder::BlackDecoder (shared_ptr<Film> f, shared_ptr<NullContent> c)
+ : VideoDecoder (f, c)
{
}
void
BlackDecoder::pass ()
{
-
+ if (!_image) {
+ _image.reset (new SimpleImage (AV_PIX_FMT_RGB24, video_size ()));
+ _image->make_black ();
+ video (_image, false, _next_video);
+ } else {
+ video (_image, true, _next_video);
+ }
+}
+
+float
+BlackDecoder::video_frame_rate () const
+{
+ boost::shared_ptr<const Film> f = _film.lock ();
+ if (!f) {
+ return 24;
+ }
+
+ return f->dcp_video_frame_rate ();
+}
+
+ContentVideoFrame
+BlackDecoder::video_length () const
+{
+ return _video_content->length() * video_frame_rate() / TIME_HZ;
+}
+
+Time
+BlackDecoder::next () const
+{
+ return _next_video;
}
+/*
+ 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 "video_decoder.h"
class BlackDecoder : public VideoDecoder
{
public:
- BlackDecoder (boost::shared_ptr<NullContent>);
+ BlackDecoder (boost::shared_ptr<const Film>, boost::shared_ptr<NullContent>);
- bool pass ();
- bool seek (double);
+ /* Decoder */
+
+ void pass ();
+ void seek (Time);
Time next () const;
- /** @return video frame rate second, or 0 if unknown */
- float video_frame_rate () const {
- return 24;
- }
-
- /** @return native size in pixels */
- libdcp::Size native_size () const {
+ /* VideoDecoder */
+
+ float video_frame_rate () const;
+ libdcp::Size video_size () const {
return libdcp::Size (256, 256);
}
-
- /** @return length according to our content's header */
- ContentVideoFrame video_length () const {
- return _content_length;
- }
-
-protected:
+ ContentVideoFrame video_length () const;
- int time_base_numerator () const {
- return 0;
- }
-
- int time_base_denominator () const {
- return 1;
- }
-
- int sample_aspect_ratio_numerator () const {
- return 0;
- }
-
- int sample_aspect_ratio_denominator () const {
- return 1;
- }
+private:
+ boost::shared_ptr<Image> _image;
};
void
ImageMagickDecoder::pass ()
{
- if (_position < 0 || _position >= _imagemagick_content->video_length ()) {
+ if (_next_video >= _imagemagick_content->video_length ()) {
return;
}
if (_image) {
- video (_image, true, double (_position) / video_frame_rate());
- _position++;
+ video (_image, true, _next_video);
return;
}
delete magick_image;
_image = _image->crop (_imagemagick_content->crop(), true);
- video (_image, false, double (_position) / 24);
-
- ++_position;
- return false;
-}
-
-PixelFormat
-ImageMagickDecoder::pixel_format () const
-{
- /* XXX: always true? */
- return PIX_FMT_RGB24;
+ video (_image, false, _next_video);
}
-bool
-ImageMagickDecoder::seek (double t)
+void
+ImageMagickDecoder::seek (Time t)
{
- int const f = t * _imagemagick_content->video_frame_rate ();
-
- if (f >= _imagemagick_content->video_length()) {
- _position = 0;
- return true;
- }
-
- _position = f;
- return false;
+ _next_video = t;
}
Time
/* Decoder */
void pass ();
- void seek (double);
+ void seek (Time);
Time next () const;
/* VideoDecoder */
--- /dev/null
+/*
+ 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.
+
+*/
+
+NullContent::NullContent (Time s, Time len, shared_ptr<const Film> f)
+ : Content (s)
+ , VideoContent (s, f->time_to_video_frames (len))
+ , AudioContent (s)
+ , _audio_length (f->time_to_audio_frames (len))
+ , _content_audio_frame_rate (f->dcp_audio_frame_rate ())
+{
+
+}
+/*
+ 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 <string>
#include <boost/shared_ptr.hpp>
#include "content.h"
class NullContent : public VideoContent, public AudioContent
{
public:
- NullContent (Time s, Time len)
- : Content (s)
- , VideoContent (s)
- , AudioContent (s)
- , _length (len)
- {}
+ NullContent (Time, Time, boost::shared_ptr<const Film>);
std::string summary () const {
return "";
std::string information () const {
return "";
}
+
+ void as_xml (xmlpp::Node *) const {}
boost::shared_ptr<Content> clone () const {
- return shared_ptr<Content> ();
+ return boost::shared_ptr<Content> ();
}
int audio_channels () const {
}
ContentAudioFrame audio_length () const {
- return _length * content_audio_frame_rate() / TIME_HZ;
+ return _audio_length;
}
int content_audio_frame_rate () const {
- return 48000;
+ return _content_audio_frame_rate;
}
- int output_audio_frame_rate (boost::shared_ptr<const Film>) const {
- return _film->dcp_audio_frame_rate (content_audio_frame_rate ());
+ int output_audio_frame_rate (boost::shared_ptr<const Film> f) const {
+ return f->dcp_audio_frame_rate ();
}
AudioMapping audio_mapping () const {
}
private:
- Time _length;
+ ContentAudioFrame _audio_length;
+ ContentAudioFrame _content_audio_frame_rate;
};
#include "playlist.h"
#include "job.h"
#include "image.h"
+#include "null_content.h"
+#include "black_decoder.h"
+#include "silence_decoder.h"
using std::list;
using std::cout;
}
void
-Player::process_video (shared_ptr<Piece> piece, shared_ptr<const Image> image, bool same, shared_ptr<Subtitle> sub, Time time)
+Player::process_video (weak_ptr<Content> weak_content, shared_ptr<const Image> image, bool same, shared_ptr<Subtitle> sub, Time time)
{
- time += piece->content->start ();
+ shared_ptr<Content> content = weak_content.lock ();
+ if (!content) {
+ return;
+ }
+
+ time += content->start ();
Video (image, same, sub, time);
}
void
-Player::process_audio (shared_ptr<Piece> piece, shared_ptr<const AudioBuffers> audio, Time time)
+Player::process_audio (weak_ptr<Content> weak_content, shared_ptr<const AudioBuffers> audio, Time time)
{
+ shared_ptr<Content> content = weak_content.lock ();
+ if (!content) {
+ return;
+ }
+
/* XXX: mapping */
/* The time of this audio may indicate that some of our buffered audio is not going to
be added to any more, so it can be emitted.
*/
- time += piece->content->start ();
+ time += content->start ();
if (time > _next_audio) {
/* We can emit some audio from our buffers */
};
void
-Player::setup_decoders ()
+Player::setup_pieces ()
{
list<shared_ptr<Piece> > old_pieces = _pieces;
_pieces.clear ();
Playlist::ContentList content = _playlist->content ();
- content.sort (ContentSorter ());
+ sort (content.begin(), content.end(), ContentSorter ());
for (Playlist::ContentList::iterator i = content.begin(); i != content.end(); ++i) {
if (fc) {
shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (_film, fc, _video, _audio, _subtitles));
- fd->Video.connect (bind (&Player::process_video, this, dr, _1, _2, _3, _4));
- fd->Audio.connect (bind (&Player::process_audio, this, dr, _1, _2));
+ fd->Video.connect (bind (&Player::process_video, this, *i, _1, _2, _3, _4));
+ fd->Audio.connect (bind (&Player::process_audio, this, *i, _1, _2));
decoder = fd;
}
shared_ptr<ImageMagickDecoder> id;
/* See if we can re-use an old ImageMagickDecoder */
- for (list<shared_ptr<Piece> >::const_iterator i = old_pieces.begin(); i != old_pieces.end(); ++i) {
- shared_ptr<ContentPiece> cp = dynamic_pointer_cast<ContentPiece> (*i);
- if (cp) {
- shared_ptr<ImageMagickDecoder> imd = dynamic_pointer_cast<ImageMagickDecoder> (cp->decoder ());
- if (imd && imd->content() == ic) {
- id = imd;
- }
+ for (list<shared_ptr<Piece> >::const_iterator j = old_pieces.begin(); j != old_pieces.end(); ++j) {
+ shared_ptr<ImageMagickDecoder> imd = dynamic_pointer_cast<ImageMagickDecoder> ((*j)->decoder);
+ if (imd && imd->content() == ic) {
+ id = imd;
}
}
if (!id) {
id.reset (new ImageMagickDecoder (_film, ic));
- id->Video.connect (bind (&Player::process_video, this, dr, _1, _2, _3, _4));
+ id->Video.connect (bind (&Player::process_video, this, *i, _1, _2, _3, _4));
}
decoder = id;
shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
if (sc) {
shared_ptr<AudioDecoder> sd (new SndfileDecoder (_film, sc));
- sd->Audio.connect (bind (&Player::process_audio, this, dr, _1, _2));
+ sd->Audio.connect (bind (&Player::process_audio, this, *i, _1, _2));
decoder = sd;
}
- _pieces.push_back (shared_ptr<new ContentPiece> (*i, decoder));
+ _pieces.push_back (shared_ptr<Piece> (new Piece (*i, decoder)));
}
/* Fill in visual gaps with black and audio gaps with silence */
list<shared_ptr<Piece> > pieces_copy = _pieces;
for (list<shared_ptr<Piece> >::iterator i = pieces_copy.begin(); i != pieces_copy.end(); ++i) {
if (dynamic_pointer_cast<VideoContent> ((*i)->content)) {
- Time const diff = video_pos - (*i)->content->time();
+ Time const diff = video_pos - (*i)->content->start();
if (diff > 0) {
- _pieces.push_back (
- shared_ptr<Piece> (
- shared_ptr<Content> (new NullContent (video_pos, diff)),
- shared_ptr<Decoder> (new BlackDecoder (video_pos, diff))
- )
- );
+ shared_ptr<NullContent> nc (new NullContent (video_pos, diff));
+ _pieces.push_back (shared_ptr<Piece> (new Piece (nc, shared_ptr<Decoder> (new BlackDecoder (_film, nc)))));
}
- video_pos = (*i)->content->time() + (*i)->content->length();
+ video_pos = (*i)->content->start() + (*i)->content->length(_film);
} else {
- Time const diff = audio_pos - (*i)->content->time();
+ Time const diff = audio_pos - (*i)->content->start();
if (diff > 0) {
- _pieces.push_back (
- shared_ptr<Piece> (
- shared_ptr<Content> (new NullContent (audio_pos, diff)),
- shared_ptr<Decoder> (new SilenceDecoder (audio_pos, diff))
- )
- );
+ shared_ptr<NullContent> nc (new NullContent (audio_pos, diff));
+ _pieces.push_back (shared_ptr<Piece> (new Piece (nc, shared_ptr<Decoder> (new SilenceDecoder (_film, nc)))));
}
- audio_pos = (*i)->content->time() + (*i)->content->length();
+ audio_pos = (*i)->content->start() + (*i)->content->length(_film);
}
}
{
_have_valid_pieces = false;
}
-
-void
-Player::emit_black_frame ()
-{
- shared_ptr<SimpleImage> image (new SimpleImage (AV_PIX_FMT_RGB24, libdcp::Size (128, 128), true));
- Video (image, _last_was_black, shared_ptr<Subtitle> (), _last_video);
- _last_video += _film->video_frames_to_time (1);
-}
-
-void
-Player::emit_silence (Time t)
-{
- OutputAudioFrame frames = _film->time_to_audio_frames (t);
- while (frames) {
- /* Do this in half-second chunks so we don't overwhelm anybody */
- OutputAudioFrame this_time = min (_film->dcp_audio_frame_rate() / 2, frames);
- shared_ptr<AudioBuffers> silence (new AudioBuffers (MAX_AUDIO_CHANNELS, this_time));
- silence->make_silent ();
- Audio (silence, _last_audio);
- _last_audio += _film->audio_frames_to_time (this_time);
- frames -= this_time;
- }
-}
void disable_audio ();
void disable_subtitles ();
- void pass ();
+ bool pass ();
void seek (Time);
void seek_back ();
void seek_forward ();
private:
- void process_video (boost::shared_ptr<Piece>, boost::shared_ptr<const Image>, bool, boost::shared_ptr<Subtitle>, Time);
- void process_audio (boost::shared_ptr<Piece>, boost::shared_ptr<const AudioBuffers>, Time);
+ void process_video (boost::weak_ptr<Content>, boost::shared_ptr<const Image>, bool, boost::shared_ptr<Subtitle>, Time);
+ void process_audio (boost::weak_ptr<Content>, boost::shared_ptr<const AudioBuffers>, Time);
void setup_pieces ();
void playlist_changed ();
void content_changed (boost::weak_ptr<Content>, int);
- void emit_black_frame ();
- void emit_silence (Time);
boost::shared_ptr<const Film> _film;
boost::shared_ptr<const Playlist> _playlist;
{
Time len = 0;
for (ContentList::const_iterator i = _content.begin(); i != _content.end(); ++i) {
- Time const t = (*i)->time() + (*i)->length (film);
- len = max (len, t);
+ len = max (len, (*i)->end (film));
}
return len;
--- /dev/null
+/*
+ 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.
+
+*/
+
+class SilenceDecoder : public AudioDecoder
+{
+public:
+ SilenceDecoder (boost::shared_ptr<const Film>, boost::shared_ptr<NullContent>);
+
+ void pass ();
+ void seek (Time);
+ Time next () const;
+};
~SndfileDecoder ();
void pass ();
- Time next ();
+ Time next () const;
int audio_channels () const;
ContentAudioFrame audio_length () const;
using boost::shared_ptr;
using boost::lexical_cast;
+VideoContent::VideoContent (Time s, ContentVideoFrame len)
+ : Content (s)
+ , _video_length (len)
+{
+
+}
+
VideoContent::VideoContent (boost::filesystem::path f)
: Content (f)
, _video_length (0)
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 ();
+ libdcp::Size const vs = d->video_size ();
float const vfr = d->video_frame_rate ();
{
: Decoder (f)
, _next_video (0)
, _video_content (c)
- , _frame_rate_conversion (c->video_frame_rate(), f->dcp_frame_rate())
+ , _frame_rate_conversion (c->video_frame_rate(), f->dcp_video_frame_rate())
, _odd (false)
{
Video (image, same, sub, t);
+ shared_ptr<const Film> film = _film.lock ();
+ assert (film);
+
if (_frame_rate_conversion.repeat) {
- Video (image, true, sub, t + _film->video_frames_to_time (1));
- _next_video = t + _film->video_frames_to_time (2);
+ Video (image, true, sub, t + film->video_frames_to_time (1));
+ _next_video = t + film->video_frames_to_time (2);
} else {
- _next_video = t + _film->video_frames_to_time (1);
+ _next_video = t + film->video_frames_to_time (1);
}
_odd = !_odd;
void
FilmViewer::update_from_decoder ()
{
- if (!_player || _player->seek (_player->last_video ())) {
+ if (!_player) {
return;
}
+ _player->seek (_player->last_video ());
get_frame ();
_panel->Refresh ();
_panel->Update ();
return;
}
- Time const start = content->time ();
+ Time const start = content->start ();
Time const len = content->length (film);
gc->SetPen (*wxBLACK_PEN);
}
return Rect (
- time_x (content->time ()),
+ time_x (content->start ()),
y_pos (_track),
content->length (film) * _timeline.pixels_per_time_unit(),
_timeline.track_height()