--- /dev/null
+#!/usr/bin/python
+
+import wave
+import sys
+import struct
+from pylab import *
+import numpy
+
+f = wave.open(sys.argv[1], 'rb')
+width = f.getsampwidth()
+peak = pow(2, width * 8) / 2
+channels = f.getnchannels()
+frames = f.getnframes()
+print '%d bytes per sample' % width
+print '%d channels' % channels
+print '%d frames' % frames
+data = []
+for i in range(0, channels):
+ data.append([])
+
+for i in range(0, frames):
+ frame = f.readframes(1)
+ for j in range(0, channels):
+ v = 0
+ for k in range(0, width):
+ v |= ord(frame[j * width + k]) << (k * 8)
+ if v >= peak:
+ v = v - 2 * peak
+ data[j].append(v)
+
+f.close()
+
+names = ['L', 'R', 'C', 'Lfe', 'Ls', 'Rs']
+dyn_range = 20 * log10(pow(2, 23))
+
+for i in range(0, channels):
+ s = numpy.fft.fft(data[i])
+# subplot(channels, 1, i + 1)
+ # 138.5 is a fudge factor:
+ semilogx(arange(0, frames / 2, 0.5), 20 * log10(abs(s) + 0.1) - dyn_range, label = names[i])
+ xlim(100, frames / 4)
+plt.gca().xaxis.grid(True, which='major')
+plt.gca().xaxis.grid(True, which='minor')
+plt.gca().yaxis.grid(True)
+legend(loc = 'lower right')
+show()
+
+#plot(abs(numpy.fft.fft(data[0])))
+#plot(data[0])
+#show()
#include "job.h"
#include "film.h"
#include "config.h"
+#include "overlaps.h"
#include "compose.hpp"
#include "dcp_decoder.h"
#include <dcp/dcp.h>
signal_changed (DCPContentProperty::REFERENCE_SUBTITLE);
}
+list<DCPTimePeriod>
+DCPContent::reels () const
+{
+ list<DCPTimePeriod> p;
+ DCPDecoder decoder (shared_from_this(), false);
+
+ shared_ptr<const Film> film = _film.lock ();
+ DCPOMATIC_ASSERT (film);
+ DCPTime from = position ();
+ BOOST_FOREACH (shared_ptr<dcp::Reel> i, decoder.reels()) {
+ DCPTime const to = from + DCPTime::from_frames (i->main_picture()->duration(), film->video_frame_rate());
+ p.push_back (DCPTimePeriod (from, to));
+ from = to;
+ }
+
+ return p;
+}
+
list<DCPTime>
DCPContent::reel_split_points () const
{
list<DCPTime> s;
- DCPDecoder decoder (shared_from_this(), false);
- DCPTime t = position();
+ BOOST_FOREACH (DCPTimePeriod i, reels()) {
+ s.push_back (i.from);
+ }
+ return s;
+}
+template <class T>
+bool
+DCPContent::can_reference (string overlapping, list<string>& why_not) const
+{
shared_ptr<const Film> film = _film.lock ();
DCPOMATIC_ASSERT (film);
- BOOST_FOREACH (shared_ptr<dcp::Reel> k, decoder.reels()) {
- s.push_back (t);
- t += DCPTime::from_frames (k->main_picture()->duration(), film->video_frame_rate());
+
+ list<DCPTimePeriod> const fr = film->reels ();
+ /* fr must contain reels(). It can also contain other reels, but it must at
+ least contain reels().
+ */
+ BOOST_FOREACH (DCPTimePeriod i, reels()) {
+ if (find (fr.begin(), fr.end(), i) == fr.end ()) {
+ why_not.push_back (_("Reel lengths in the project differ from those in the DCP; set the reel mode to `split by video content'."));
+ return false;
+ }
}
- return s;
+ list<shared_ptr<T> > a = overlaps<T> (film->content(), position(), end());
+ if (a.size() != 1 || a.front().get() != this) {
+ why_not.push_back (overlapping);
+ return false;
+ }
+
+ return true;
+}
+
+bool
+DCPContent::can_reference_video (list<string>& why_not) const
+{
+ return can_reference<VideoContent> (_("There is other video content overlapping this DCP; remove it."), why_not);
+}
+
+bool
+DCPContent::can_reference_audio (list<string>& why_not) const
+{
+ return can_reference<AudioContent> (_("There is other audio content overlapping this DCP; remove it."), why_not);
+}
+
+bool
+DCPContent::can_reference_subtitle (list<string>& why_not) const
+{
+ return can_reference<SubtitleContent> (_("There is other subtitle content overlapping this DCP; remove it."), why_not);
}
return _reference_video;
}
+ bool can_reference_video (std::list<std::string> &) const;
+
void set_reference_audio (bool r);
bool reference_audio () const {
return _reference_audio;
}
+ bool can_reference_audio (std::list<std::string> &) const;
+
void set_reference_subtitle (bool r);
bool reference_subtitle () const {
return _reference_subtitle;
}
+ bool can_reference_subtitle (std::list<std::string> &) const;
+
protected:
void add_properties (std::list<std::pair<std::string, std::string> >& p) const;
private:
void read_directory (boost::filesystem::path);
+ std::list<DCPTimePeriod> reels () const;
+ template <class T> bool can_reference (std::string overlapping, std::list<std::string>& why_not) const;
std::string _name;
bool _has_subtitles;
return (from <= other && other < to);
}
- bool operator== (TimePeriod<T> const & other) {
+ bool operator== (TimePeriod<T> const & other) const {
return from == other.from && to == other.to;
}
};
--- /dev/null
+/*
+ Copyright (C) 2013-2015 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.
+
+*/
+
+/** @return Pieces of content type C that overlap a specified time range in the given ContentList */
+template<class C>
+std::list<boost::shared_ptr<C> >
+overlaps (ContentList cl, DCPTime from, DCPTime to)
+{
+ std::list<boost::shared_ptr<C> > overlaps;
+ DCPTimePeriod period (from, to);
+ for (typename ContentList::const_iterator i = cl.begin(); i != cl.end(); ++i) {
+ boost::shared_ptr<C> c = boost::dynamic_pointer_cast<C> (*i);
+ if (!c) {
+ continue;
+ }
+
+ if (DCPTimePeriod(c->position(), c->end()).overlaps (period)) {
+ overlaps.push_back (c);
+ }
+ }
+
+ return overlaps;
+}
--- /dev/null
+/*
+ Copyright (C) 2015 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 ReferencedReelAsset
+{
+public:
+ ReferencedReelAsset (boost::shared_ptr<dcp::ReelAsset> asset_, DCPTimePeriod period_)
+ : asset (asset_)
+ , period (period_)
+ {}
+
+ /** The asset */
+ boost::shared_ptr<dcp::ReelAsset> asset;
+ /** Period that this asset covers in the DCP */
+ DCPTimePeriod period;
+};
case Film::VIDEO_FRAME_RATE:
setup_description ();
break;
+ case Film::REEL_TYPE:
+ setup_sensitivity ();
default:
break;
}
AudioPanel::setup_sensitivity ()
{
AudioContentList sel = _parent->selected_audio ();
- _reference->Enable (sel.size() == 1 && dynamic_pointer_cast<DCPContent> (sel.front ()));
+
+ shared_ptr<DCPContent> dcp;
+ if (sel.size() == 1) {
+ dcp = dynamic_pointer_cast<DCPContent> (sel.front ());
+ }
+
+ list<string> why_not;
+ bool const can_reference = dcp && dcp->can_reference_audio (why_not);
+ _reference->Enable (can_reference);
+
+ wxString s;
+ if (!can_reference) {
+ s = _("Cannot reference this DCP. ");
+ BOOST_FOREACH (string i, why_not) {
+ s += std_to_wx(i) + wxT(" ");
+ }
+ }
+ _reference->SetToolTip (s);
if (_reference->GetValue ()) {
_gain->wrapped()->Enable (false);
using std::vector;
using std::string;
+using std::list;
using boost::shared_ptr;
using boost::lexical_cast;
using boost::dynamic_pointer_cast;
void
SubtitlePanel::film_changed (Film::Property property)
{
- if (property == Film::CONTENT) {
+ if (property == Film::CONTENT || property == Film::REEL_TYPE) {
setup_sensitivity ();
}
}
int ffmpeg_subs = 0;
int subrip_or_dcp_subs = 0;
int image_subs = 0;
- BOOST_FOREACH (shared_ptr<SubtitleContent> i, _parent->selected_subtitle ()) {
+ SubtitleContentList sel = _parent->selected_subtitle ();
+ BOOST_FOREACH (shared_ptr<SubtitleContent> i, sel) {
shared_ptr<const FFmpegContent> fc = boost::dynamic_pointer_cast<const FFmpegContent> (i);
shared_ptr<const SubRipContent> sc = boost::dynamic_pointer_cast<const SubRipContent> (i);
shared_ptr<const DCPSubtitleContent> dsc = boost::dynamic_pointer_cast<const DCPSubtitleContent> (i);
}
}
+ shared_ptr<DCPContent> dcp;
+ if (sel.size() == 1) {
+ dcp = dynamic_pointer_cast<DCPContent> (sel.front ());
+ }
+
+ list<string> why_not;
+ bool const can_reference = dcp && dcp->can_reference_subtitle (why_not);
+ _reference->Enable (can_reference);
+
+ wxString s;
+ if (!can_reference) {
+ s = _("Cannot reference this DCP. ");
+ BOOST_FOREACH (string i, why_not) {
+ s += std_to_wx(i) + wxT(" ");
+ }
+ }
+ _reference->SetToolTip (s);
+
bool const reference = _reference->GetValue ();
_use->Enable (!reference && any_subs > 0);
_stream->Enable (!reference && ffmpeg_subs == 1);
_subtitle_view_button->Enable (!reference && subrip_or_dcp_subs == 1);
_fonts_dialog_button->Enable (!reference && subrip_or_dcp_subs == 1);
-
- ContentList sel = _parent->selected ();
- _reference->Enable (sel.size() == 1 && dynamic_pointer_cast<DCPContent> (sel.front ()));
}
void
}
shared_ptr<Content> content = cv->content();
+ DCPTimePeriod content_period (content->position(), content->end());
int t = 0;
while (true) {
shared_ptr<Content> test_content = test->content();
if (test && test->track() && test->track().get() == t) {
- bool const no_overlap =
- (content->position() < test_content->position() && content->end() < test_content->position()) ||
- (content->position() > test_content->end() && content->end() > test_content->end());
-
- if (!no_overlap) {
+ if (content_period.overlaps (DCPTimePeriod(test_content->position(), test_content->end()))) {
/* we have an overlap on track `t' */
++t;
break;
if (_snap) {
- DCPTime const new_end = new_position + _down_view->content()->length_after_trim () - DCPTime (1);
+ DCPTime const new_end = new_position + _down_view->content()->length_after_trim();
/* Signed `distance' to nearest thing (i.e. negative is left on the timeline,
positive is right).
*/
}
maybe_snap (cv->content()->position(), new_position, nearest_distance);
- maybe_snap (cv->content()->position(), new_end + DCPTime (1), nearest_distance);
- maybe_snap (cv->content()->end() + DCPTime (1), new_position, nearest_distance);
- maybe_snap (cv->content()->end() + DCPTime (1), new_end, nearest_distance);
+ maybe_snap (cv->content()->position(), new_end, nearest_distance);
+ maybe_snap (cv->content()->end(), new_position, nearest_distance);
+ maybe_snap (cv->content()->end(), new_end, nearest_distance);
}
if (nearest_distance) {
case Film::RESOLUTION:
setup_description ();
break;
+ case Film::REEL_TYPE:
+ setup_sensitivity ();
default:
break;
}
VideoPanel::setup_sensitivity ()
{
ContentList sel = _parent->selected ();
- _reference->Enable (sel.size() == 1 && dynamic_pointer_cast<DCPContent> (sel.front ()));
+
+ shared_ptr<DCPContent> dcp;
+ if (sel.size() == 1) {
+ dcp = dynamic_pointer_cast<DCPContent> (sel.front ());
+ }
+
+ list<string> why_not;
+ bool const can_reference = dcp && dcp->can_reference_video(why_not);
+ _reference->Enable (can_reference);
+
+ wxString s;
+ if (!can_reference) {
+ s = _("Cannot reference this DCP. ");
+ BOOST_FOREACH (string i, why_not) {
+ s += std_to_wx(i) + wxT(" ");
+ }
+ }
+ _reference->SetToolTip (s);
if (_reference->GetValue ()) {
_frame_type->wrapped()->Enable (false);
--- /dev/null
+#!/usr/bin/python
+
+from pylab import *
+import numpy
+
+f = open('build/test/lpf_ir')
+ir = []
+while True:
+ l = f.readline()
+ if l == "":
+ break
+
+ ir.append(float(l.strip()))
+
+#plot(abs(numpy.fft.fft(ir)))
+plot(ir)
+show()
--- /dev/null
+/*
+ Copyright (C) 2015 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 "lib/film.h"
+#include "lib/ratio.h"
+#include "lib/ffmpeg_content.h"
+#include "lib/image_content.h"
+#include "lib/dcp_content_type.h"
+#include "lib/dcp_content.h"
+#include "test.h"
+#include <boost/test/unit_test.hpp>
+
+using std::list;
+using boost::shared_ptr;
+
+/** Test Film::reels() */
+BOOST_AUTO_TEST_CASE (reels_test1)
+{
+ shared_ptr<Film> film = new_test_film ("reels_test1");
+ film->set_container (Ratio::from_id ("185"));
+ shared_ptr<FFmpegContent> A (new FFmpegContent (film, "test/data/test.mp4"));
+ film->examine_and_add_content (A);
+ shared_ptr<FFmpegContent> B (new FFmpegContent (film, "test/data/test.mp4"));
+ film->examine_and_add_content (B);
+ wait_for_jobs ();
+ BOOST_CHECK_EQUAL (A->full_length(), DCPTime (288000));
+
+ film->set_reel_type (REELTYPE_SINGLE);
+ list<DCPTimePeriod> r = film->reels ();
+ BOOST_CHECK_EQUAL (r.size(), 1);
+ BOOST_CHECK_EQUAL (r.front().from, DCPTime (0));
+ BOOST_CHECK_EQUAL (r.front().to, DCPTime (288000 * 2));
+
+ film->set_reel_type (REELTYPE_BY_VIDEO_CONTENT);
+ r = film->reels ();
+ BOOST_CHECK_EQUAL (r.size(), 2);
+ BOOST_CHECK_EQUAL (r.front().from, DCPTime (0));
+ BOOST_CHECK_EQUAL (r.front().to, DCPTime (288000));
+ BOOST_CHECK_EQUAL (r.back().from, DCPTime (288000));
+ BOOST_CHECK_EQUAL (r.back().to, DCPTime (288000 * 2));
+
+ film->set_j2k_bandwidth (100000000);
+ film->set_reel_type (REELTYPE_BY_LENGTH);
+ /* This is just over 2.5s at 100Mbit/s; should correspond to 60 frames */
+ film->set_reel_length (31253154);
+ r = film->reels ();
+ BOOST_CHECK_EQUAL (r.size(), 3);
+ list<DCPTimePeriod>::const_iterator i = r.begin ();
+ BOOST_CHECK_EQUAL (i->from, DCPTime (0));
+ BOOST_CHECK_EQUAL (i->to, DCPTime::from_frames (60, 24));
+ ++i;
+ BOOST_CHECK_EQUAL (i->from, DCPTime::from_frames (60, 24));
+ BOOST_CHECK_EQUAL (i->to, DCPTime::from_frames (120, 24));
+ ++i;
+ BOOST_CHECK_EQUAL (i->from, DCPTime::from_frames (120, 24));
+ BOOST_CHECK_EQUAL (i->to, DCPTime::from_frames (144, 24));
+}
+
+/** Make a short DCP with multi reels split by video content, then import
+ * this into a new project and make a new DCP referencing it.
+ */
+BOOST_AUTO_TEST_CASE (reels_test2)
+{
+ shared_ptr<Film> film = new_test_film ("reels_test2");
+ film->set_name ("reels_test2");
+ film->set_container (Ratio::from_id ("185"));
+ film->set_dcp_content_type (DCPContentType::from_pretty_name ("Test"));
+
+ {
+ shared_ptr<ImageContent> c (new ImageContent (film, "test/data/flat_red.png"));
+ film->examine_and_add_content (c);
+ wait_for_jobs ();
+ c->set_video_length (24);
+ }
+
+ {
+ shared_ptr<ImageContent> c (new ImageContent (film, "test/data/flat_green.png"));
+ film->examine_and_add_content (c);
+ wait_for_jobs ();
+ c->set_video_length (24);
+ }
+
+ {
+ shared_ptr<ImageContent> c (new ImageContent (film, "test/data/flat_blue.png"));
+ film->examine_and_add_content (c);
+ wait_for_jobs ();
+ c->set_video_length (24);
+ }
+
+ film->set_reel_type (REELTYPE_BY_VIDEO_CONTENT);
+ wait_for_jobs ();
+
+ film->make_dcp ();
+ wait_for_jobs ();
+
+ check_dcp ("test/data/reels_test2", film->dir (film->dcp_name()));
+
+ shared_ptr<Film> film2 = new_test_film ("reels_test3");
+ film2->set_name ("reels_test3");
+ film2->set_container (Ratio::from_id ("185"));
+ film2->set_dcp_content_type (DCPContentType::from_pretty_name ("Test"));
+ film2->set_reel_type (REELTYPE_BY_VIDEO_CONTENT);
+
+ shared_ptr<DCPContent> c (new DCPContent (film2, film->dir (film->dcp_name ())));
+ film2->examine_and_add_content (c);
+ wait_for_jobs ();
+
+ list<DCPTimePeriod> r = film2->reels ();
+ BOOST_CHECK_EQUAL (r.size(), 3);
+ list<DCPTimePeriod>::const_iterator i = r.begin ();
+ BOOST_CHECK_EQUAL (i->from, DCPTime (0));
+ BOOST_CHECK_EQUAL (i->to, DCPTime (96000));
+ ++i;
+ BOOST_CHECK_EQUAL (i->from, DCPTime (96000));
+ BOOST_CHECK_EQUAL (i->to, DCPTime (96000 * 2));
+ ++i;
+ BOOST_CHECK_EQUAL (i->from, DCPTime (96000 * 2));
+ BOOST_CHECK_EQUAL (i->to, DCPTime (96000 * 3));
+
+ c->set_reference_video (true);
+ c->set_reference_audio (true);
+
+ film2->make_dcp ();
+ wait_for_jobs ();
+}
--- /dev/null
+/*
+ Copyright (C) 2015 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 "lib/film.h"
+#include "lib/dcp_content.h"
+#include "lib/ffmpeg_content.h"
+#include "test.h"
+#include <boost/test/unit_test.hpp>
+
+using std::list;
+using std::string;
+using boost::shared_ptr;
+
+/** Test the logic which decides whether a DCP can be referenced or not */
+BOOST_AUTO_TEST_CASE (vf_test1)
+{
+ shared_ptr<Film> film = new_test_film ("vf_test1");
+ shared_ptr<DCPContent> dcp (new DCPContent (film, "test/data/reels_test2"));
+ film->examine_and_add_content (dcp);
+ wait_for_jobs ();
+
+ /* Multi-reel DCP can't be referenced if we are using a single reel for the project */
+ film->set_reel_type (REELTYPE_SINGLE);
+ list<string> why_not;
+ BOOST_CHECK (!dcp->can_reference_video(why_not));
+ BOOST_CHECK (!dcp->can_reference_audio(why_not));
+ BOOST_CHECK (!dcp->can_reference_subtitle(why_not));
+
+ /* Multi-reel DCP can be referenced if we are using by-video-content */
+ film->set_reel_type (REELTYPE_BY_VIDEO_CONTENT);
+ BOOST_CHECK (dcp->can_reference_video(why_not));
+ BOOST_CHECK (dcp->can_reference_audio(why_not));
+ BOOST_CHECK (dcp->can_reference_subtitle(why_not));
+
+ shared_ptr<FFmpegContent> other (new FFmpegContent (film, "test/data/test.mp4"));
+ film->examine_and_add_content (other);
+ wait_for_jobs ();
+
+ /* Not possible if there is overlap */
+ other->set_position (DCPTime (0));
+ BOOST_CHECK (!dcp->can_reference_video(why_not));
+ BOOST_CHECK (!dcp->can_reference_audio(why_not));
+ BOOST_CHECK (!dcp->can_reference_subtitle(why_not));
+
+ /* This should not be considered an overlap */
+ other->set_position (dcp->end ());
+ BOOST_CHECK (dcp->can_reference_video(why_not));
+ BOOST_CHECK (dcp->can_reference_audio(why_not));
+ BOOST_CHECK (dcp->can_reference_subtitle(why_not));
+}
update_checker_test.cc
upmixer_a_test.cc
util_test.cc
+ vf_test.cc
video_content_scale_test.cc
video_decoder_fill_test.cc
xml_subtitle_test.cc