+2014-03-07 Carl Hetherington <cth@carlh.net>
+
+ * Add subtitle view.
+
+ 2014-06-18 Carl Hetherington <cth@carlh.net>
+
+ * Version 1.69.29 released.
+
+ 2014-06-18 Carl Hetherington <cth@carlh.net>
+
+ * Fix thinko causing incorrect audio sample rates in some cases.
+
+ 2014-06-15 Carl Hetherington <cth@carlh.net>
+
+ * Version 1.69.28 released.
+
2014-06-12 Carl Hetherington <cth@carlh.net>
* Version 1.69.27 released.
#include <boost/shared_ptr.hpp>
#include <boost/signals2.hpp>
#include <boost/filesystem.hpp>
-#include <libdcp/metadata.h>
+#include <dcp/metadata.h>
#include "isdcf_metadata.h"
#include "colour_conversion.h"
--#include "server.h"
class ServerDescription;
class Scaler;
#include "util.h"
#include "config.h"
#include "cross.h"
++#include "exceptions.h"
class Image;
class AudioBuffers;
#include <libcxml/cxml.h>
#include "image_content.h"
#include "image_examiner.h"
--#include "config.h"
#include "compose.hpp"
#include "film.h"
#include "job.h"
#include "frame_rate_change.h"
++#include "exceptions.h"
#include "i18n.h"
using boost::bind;
using boost::scoped_array;
using boost::optional;
-using libdcp::Size;
-using libdcp::raw_convert;
+using dcp::Size;
+using dcp::raw_convert;
Server::Server (shared_ptr<Log> log, bool verbose)
-- : _log (log)
++ : _terminate (false)
++ , _log (log)
, _verbose (verbose)
++ , _acceptor (_io_service, boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4(), Config::instance()->server_port_base()))
{
}
++Server::~Server ()
++{
++ {
++ boost::mutex::scoped_lock lm (_worker_mutex);
++ _terminate = true;
++ _worker_condition.notify_all ();
++ }
++
++ for (vector<boost::thread*>::iterator i = _worker_threads.begin(); i != _worker_threads.end(); ++i) {
++ (*i)->join ();
++ delete *i;
++ }
++
++ _io_service.stop ();
++
++ _broadcast.io_service.stop ();
++ _broadcast.thread->join ();
++}
++
/** @param after_read Filled in with gettimeofday() after reading the input from the network.
* @param after_encode Filled in with gettimeofday() after encoding the image.
*/
{
while (1) {
boost::mutex::scoped_lock lock (_worker_mutex);
-- while (_queue.empty ()) {
++ while (_queue.empty () && !_terminate) {
_worker_condition.wait (lock);
}
++ if (_terminate) {
++ return;
++ }
++
shared_ptr<Socket> socket = _queue.front ();
_queue.pop_front ();
_broadcast.thread = new thread (bind (&Server::broadcast_thread, this));
-- boost::asio::io_service io_service;
--
-- boost::asio::ip::tcp::acceptor acceptor (
-- io_service,
-- boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4(), Config::instance()->server_port_base ())
-- );
--
-- while (1) {
-- shared_ptr<Socket> socket (new Socket);
-- acceptor.accept (socket->socket ());
--
-- boost::mutex::scoped_lock lock (_worker_mutex);
--
-- /* Wait until the queue has gone down a bit */
-- while (int (_queue.size()) >= num_threads * 2) {
-- _worker_condition.wait (lock);
-- }
--
-- _queue.push_back (socket);
-- _worker_condition.notify_all ();
-- }
++ start_accept ();
++ _io_service.run ();
}
void
Server::broadcast_thread ()
try
{
-- boost::asio::io_service io_service;
--
boost::asio::ip::address address = boost::asio::ip::address_v4::any ();
boost::asio::ip::udp::endpoint listen_endpoint (address, Config::instance()->server_port_base() + 1);
-- _broadcast.socket = new boost::asio::ip::udp::socket (io_service);
++ _broadcast.socket = new boost::asio::ip::udp::socket (_broadcast.io_service);
_broadcast.socket->open (listen_endpoint.protocol ());
_broadcast.socket->bind (listen_endpoint);
boost::bind (&Server::broadcast_received, this)
);
-- io_service.run ();
++ _broadcast.io_service.run ();
}
catch (...)
{
_broadcast.send_endpoint, boost::bind (&Server::broadcast_received, this)
);
}
++
++void
++Server::start_accept ()
++{
++ if (_terminate) {
++ return;
++ }
++
++ shared_ptr<Socket> socket (new Socket);
++ _acceptor.async_accept (socket->socket (), boost::bind (&Server::handle_accept, this, socket, boost::asio::placeholders::error));
++}
++
++void
++Server::handle_accept (shared_ptr<Socket> socket, boost::system::error_code const & error)
++{
++ if (error) {
++ return;
++ }
++
++ boost::mutex::scoped_lock lock (_worker_mutex);
++
++ /* Wait until the queue has gone down a bit */
++ while (_queue.size() >= _worker_threads.size() * 2 && !_terminate) {
++ _worker_condition.wait (lock);
++ }
++
++ _queue.push_back (socket);
++ _worker_condition.notify_all ();
++
++ start_accept ();
++}
++
{
public:
Server (boost::shared_ptr<Log> log, bool verbose);
++ ~Server ();
void run (int num_threads);
int process (boost::shared_ptr<Socket> socket, struct timeval &, struct timeval &);
void broadcast_thread ();
void broadcast_received ();
++ void start_accept ();
++ void handle_accept (boost::shared_ptr<Socket>, boost::system::error_code const &);
++
++ bool _terminate;
std::vector<boost::thread *> _worker_threads;
std::list<boost::shared_ptr<Socket> > _queue;
boost::mutex _worker_mutex;
boost::condition _worker_condition;
++
boost::shared_ptr<Log> _log;
bool _verbose;
++ boost::asio::io_service _io_service;
++ boost::asio::ip::tcp::acceptor _acceptor;
++
++ int _num_threads;
++
struct Broadcast {
Broadcast ()
boost::asio::ip::udp::socket* socket;
char buffer[64];
boost::asio::ip::udp::endpoint send_endpoint;
++ boost::asio::io_service io_service;
} _broadcast;
};
#include <wx/wx.h>
#include <wx/renderer.h>
#include <wx/grid.h>
-#include <libdcp/types.h>
-#include <libdcp/raw_convert.h>
+#include <dcp/types.h>
++#include <dcp/raw_convert.h>
#include "lib/audio_mapping.h"
#include "lib/util.h"
#include "audio_mapping_view.h"
_grid->SetCellValue (i, 0, wxString::Format (wxT("%d"), i + 1));
for (int j = 1; j < _grid->GetNumberCols(); ++j) {
- _grid->SetCellValue (i, j, std_to_wx (lexical_cast<string> (_map.get (i, static_cast<dcp::Channel> (j - 1)))));
- _grid->SetCellValue (i, j, std_to_wx (libdcp::raw_convert<string> (_map.get (i, static_cast<libdcp::Channel> (j - 1)))));
++ _grid->SetCellValue (i, j, std_to_wx (dcp::raw_convert<string> (_map.get (i, static_cast<dcp::Channel> (j - 1)))));
}
}
#include "lib/filter.h"
#include "lib/dcp_content_type.h"
#include "lib/colour_conversion.h"
++#include "lib/log.h"
#include "config_dialog.h"
#include "wx_util.h"
#include "editable_list.h"
for (list<thread*>::iterator i = threads.begin(); i != threads.end(); ++i) {
delete *i;
}
++
++ delete server;
}
BOOST_AUTO_TEST_CASE (client_server_test_yuv)
for (list<thread*>::iterator i = threads.begin(); i != threads.end(); ++i) {
delete *i;
}
++
++ delete server;
}
--- /dev/null
- BOOST_CHECK_EQUAL (A->full_length(), DCPTime::from_seconds (3));
+/*
+ Copyright (C) 2014 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.
+
+*/
+
+/** @file test/player_test.cc
+ * @brief Various tests of Player.
+ */
+
+#include <iostream>
+#include <boost/test/unit_test.hpp>
+#include "lib/film.h"
+#include "lib/ffmpeg_content.h"
+#include "lib/dcp_content_type.h"
+#include "lib/ratio.h"
+#include "lib/audio_buffers.h"
+#include "lib/player.h"
+#include "test.h"
+
+using std::cout;
+using std::list;
+using boost::shared_ptr;
+
+/** Player::overlaps */
+BOOST_AUTO_TEST_CASE (player_overlaps_test)
+{
+ shared_ptr<Film> film = new_test_film ("player_overlaps_test");
+ film->set_container (Ratio::from_id ("185"));
+ shared_ptr<FFmpegContent> A (new FFmpegContent (film, "test/data/test.mp4"));
+ shared_ptr<FFmpegContent> B (new FFmpegContent (film, "test/data/test.mp4"));
+ shared_ptr<FFmpegContent> C (new FFmpegContent (film, "test/data/test.mp4"));
+
+ film->examine_and_add_content (A);
+ film->examine_and_add_content (B);
+ film->examine_and_add_content (C);
+ wait_for_jobs ();
+
++ BOOST_CHECK_EQUAL (A->full_length(), DCPTime (280000));
+
+ A->set_position (DCPTime::from_seconds (0));
+ B->set_position (DCPTime::from_seconds (10));
+ C->set_position (DCPTime::from_seconds (20));
+
+ shared_ptr<Player> player = film->make_player ();
+
+ list<shared_ptr<Piece> > o = player->overlaps<FFmpegContent> (DCPTime::from_seconds (0), DCPTime::from_seconds (5));
+ BOOST_CHECK_EQUAL (o.size(), 1);
+ BOOST_CHECK_EQUAL (o.front()->content, A);
+
+ o = player->overlaps<FFmpegContent> (DCPTime::from_seconds (5), DCPTime::from_seconds (8));
+ BOOST_CHECK_EQUAL (o.size(), 0);
+
+ o = player->overlaps<FFmpegContent> (DCPTime::from_seconds (8), DCPTime::from_seconds (12));
+ BOOST_CHECK_EQUAL (o.size(), 1);
+ BOOST_CHECK_EQUAL (o.front()->content, B);
+
+ o = player->overlaps<FFmpegContent> (DCPTime::from_seconds (2), DCPTime::from_seconds (12));
+ BOOST_CHECK_EQUAL (o.size(), 2);
+ BOOST_CHECK_EQUAL (o.front()->content, A);
+ BOOST_CHECK_EQUAL (o.back()->content, B);
+
+ o = player->overlaps<FFmpegContent> (DCPTime::from_seconds (8), DCPTime::from_seconds (11));
+ BOOST_CHECK_EQUAL (o.size(), 1);
+ BOOST_CHECK_EQUAL (o.front()->content, B);
+}
+
+/** Check that the Player correctly generates silence when used with a silent FFmpegContent */
+BOOST_AUTO_TEST_CASE (player_silence_padding_test)
+{
+ shared_ptr<Film> film = new_test_film ("player_silence_padding_test");
+ film->set_name ("player_silence_padding_test");
+ shared_ptr<FFmpegContent> c (new FFmpegContent (film, "test/data/test.mp4"));
+ film->set_container (Ratio::from_id ("185"));
+ film->set_audio_channels (6);
+
+ film->examine_and_add_content (c);
+ wait_for_jobs ();
+
+ shared_ptr<Player> player = film->make_player ();
+ shared_ptr<AudioBuffers> test = player->get_audio (DCPTime (0), DCPTime::from_seconds (1), true);
+ BOOST_CHECK_EQUAL (test->frames(), 48000);
+ BOOST_CHECK_EQUAL (test->channels(), film->audio_channels ());
+
+ for (int i = 0; i < test->frames(); ++i) {
+ for (int c = 0; c < test->channels(); ++c) {
+ BOOST_CHECK_EQUAL (test->data()[c][i], 0);
+ }
+ }
+}
+
film->make_dcp ();
wait_for_jobs ();
- boost::filesystem::path const video = "build/test/recover_test/video/185_2K_3651eded785682b85f4baca4b1d3b7a9_24_bicubic_200000000_P_S_3D.mxf";
++ boost::filesystem::path const video = "build/test/recover_test/video/185_2K_e8efb95857b62aa6ff94e3d669e75776_24_bicubic_100000000_P_S_3D.mxf";
+
boost::filesystem::copy_file (
- "build/test/recover_test/video/185_2K_58a090f8d70a2b410c534120d35e5256_24_bicubic_200000000_P_S_3D.mxf",
+ video,
"build/test/recover_test/original.mxf"
);
}
static void
-note (libdcp::NoteType t, string n)
+note (dcp::NoteType t, string n)
{
- if (t == dcp::ERROR) {
- if (t == libdcp::ERROR) {
++ if (t == dcp::DCP_ERROR) {
cerr << n << "\n";
}
}