From 4985bbd615df73bf92fa14ba5cd585aa051e5b12 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 11 Jul 2013 11:06:41 +0100 Subject: Prevent crash when there is no subtitle after there having been one. --- src/lib/player.cc | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/lib') diff --git a/src/lib/player.cc b/src/lib/player.cc index 58ba57bdc..467f92374 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -521,6 +521,11 @@ Player::update_subtitle () return; } + if (!_in_subtitle.image) { + _out_subtitle.image.reset (); + return; + } + shared_ptr sc = dynamic_pointer_cast (piece->content); assert (sc); -- cgit v1.2.3 From 2f848b51a4ac00f7f25691fad40841d066f867cc Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 11 Jul 2013 12:41:09 +0100 Subject: Basics of allowing setup of DCP audio channels. --- src/lib/film.cc | 10 ++++++ src/lib/film.h | 2 ++ src/wx/audio_mapping_view.cc | 75 +++++++++++++++++++++++++++++++++++--------- src/wx/audio_mapping_view.h | 3 ++ src/wx/film_editor.cc | 22 +++++++++++++ src/wx/film_editor.h | 2 ++ 6 files changed, 99 insertions(+), 15 deletions(-) (limited to 'src/lib') diff --git a/src/lib/film.cc b/src/lib/film.cc index dad9d6808..16b34110c 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -625,6 +625,16 @@ Film::set_dcp_video_frame_rate (int f) signal_changed (DCP_VIDEO_FRAME_RATE); } +void +Film::set_dcp_audio_channels (int c) +{ + { + boost::mutex::scoped_lock lm (_state_mutex); + _dcp_audio_channels = c; + } + signal_changed (DCP_AUDIO_CHANNELS); +} + void Film::signal_changed (Property p) { diff --git a/src/lib/film.h b/src/lib/film.h index 08fdc587b..2bf1a0e90 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -139,6 +139,7 @@ public: J2K_BANDWIDTH, DCI_METADATA, DCP_VIDEO_FRAME_RATE, + DCP_AUDIO_CHANNELS }; @@ -221,6 +222,7 @@ public: void set_j2k_bandwidth (int); void set_dci_metadata (DCIMetadata); void set_dcp_video_frame_rate (int); + void set_dcp_audio_channels (int); void set_dci_date_today (); /** Emitted when some property has of the Film has changed */ diff --git a/src/wx/audio_mapping_view.cc b/src/wx/audio_mapping_view.cc index 1e938b357..859c4d548 100644 --- a/src/wx/audio_mapping_view.cc +++ b/src/wx/audio_mapping_view.cc @@ -99,15 +99,7 @@ AudioMappingView::AudioMappingView (wxWindow* parent) _grid->SetCellHighlightPenWidth (0); _grid->SetDefaultRenderer (new NoSelectionStringRenderer); - _grid->SetColLabelValue (0, _("Content channel")); - _grid->SetColLabelValue (1, _("L")); - _grid->SetColLabelValue (2, _("R")); - _grid->SetColLabelValue (3, _("C")); - _grid->SetColLabelValue (4, _("Lfe")); - _grid->SetColLabelValue (5, _("Ls")); - _grid->SetColLabelValue (6, _("Rs")); - - _grid->AutoSize (); + set_column_labels (); _sizer = new wxBoxSizer (wxVERTICAL); _sizer->Add (_grid, 1, wxEXPAND | wxALL); @@ -129,26 +121,28 @@ AudioMappingView::left_click (wxGridEvent& ev) _grid->SetCellValue (ev.GetRow(), ev.GetCol(), wxT("1")); } - AudioMapping mapping; + _map = AudioMapping (); for (int i = 0; i < _grid->GetNumberRows(); ++i) { for (int j = 1; j < _grid->GetNumberCols(); ++j) { if (_grid->GetCellValue (i, j) == wxT ("1")) { - mapping.add (i, static_cast (j - 1)); + _map.add (i, static_cast (j - 1)); } } } - Changed (mapping); + Changed (_map); } void AudioMappingView::set (AudioMapping map) { + _map = map; + if (_grid->GetNumberRows ()) { _grid->DeleteRows (0, _grid->GetNumberRows ()); } - list content_channels = map.content_channels (); + list content_channels = _map.content_channels (); _grid->InsertRows (0, content_channels.size ()); for (size_t r = 0; r < content_channels.size(); ++r) { @@ -161,11 +155,62 @@ AudioMappingView::set (AudioMapping map) for (list::iterator i = content_channels.begin(); i != content_channels.end(); ++i) { _grid->SetCellValue (n, 0, wxString::Format (wxT("%d"), *i + 1)); - list const d = map.content_to_dcp (*i); + list const d = _map.content_to_dcp (*i); for (list::const_iterator j = d.begin(); j != d.end(); ++j) { - _grid->SetCellValue (n, static_cast (*j) + 1, wxT("1")); + int const c = static_cast(*j) + 1; + if (c < _grid->GetNumberCols ()) { + _grid->SetCellValue (n, c, wxT("1")); + } } ++n; } } +void +AudioMappingView::set_channels (int c) +{ + c++; + + if (c < _grid->GetNumberCols ()) { + _grid->DeleteCols (c, _grid->GetNumberCols() - c); + } else if (c > _grid->GetNumberCols ()) { + _grid->InsertCols (_grid->GetNumberCols(), c - _grid->GetNumberCols()); + set_column_labels (); + } + + set (_map); +} + +void +AudioMappingView::set_column_labels () +{ + int const c = _grid->GetNumberCols (); + + _grid->SetColLabelValue (0, _("Content channel")); + + if (c > 0) { + _grid->SetColLabelValue (1, _("L")); + } + + if (c > 1) { + _grid->SetColLabelValue (2, _("R")); + } + + if (c > 2) { + _grid->SetColLabelValue (3, _("C")); + } + + if (c > 3) { + _grid->SetColLabelValue (4, _("Lfe")); + } + + if (c > 4) { + _grid->SetColLabelValue (5, _("Ls")); + } + + if (c > 5) { + _grid->SetColLabelValue (6, _("Rs")); + } + + _grid->AutoSize (); +} diff --git a/src/wx/audio_mapping_view.h b/src/wx/audio_mapping_view.h index e0709c8b7..80534a613 100644 --- a/src/wx/audio_mapping_view.h +++ b/src/wx/audio_mapping_view.h @@ -28,12 +28,15 @@ public: AudioMappingView (wxWindow *); void set (AudioMapping); + void set_channels (int); boost::signals2::signal Changed; private: void left_click (wxGridEvent &); + void set_column_labels (); wxGrid* _grid; wxSizer* _sizer; + AudioMapping _map; }; diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index 8d33b58d6..4794a9d33 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -149,6 +149,11 @@ FilmEditor::make_dcp_panel () } ++r; + add_label_to_grid_bag_sizer (grid, _dcp_panel, _("DCP audio channels"), true, wxGBPosition (r, 0)); + _dcp_audio_channels = new wxSpinCtrl (_dcp_panel, wxID_ANY); + grid->Add (_dcp_audio_channels, wxGBPosition (r, 1)); + ++r; + { add_label_to_grid_bag_sizer (grid, _dcp_panel, _("JPEG2000 bandwidth"), true, wxGBPosition (r, 0)); wxSizer* s = new wxBoxSizer (wxHORIZONTAL); @@ -184,6 +189,7 @@ FilmEditor::make_dcp_panel () _dcp_frame_rate->Append (std_to_wx (boost::lexical_cast (*i))); } + _dcp_audio_channels->SetRange (0, MAX_AUDIO_CHANNELS); _j2k_bandwidth->SetRange (50, 250); } @@ -211,6 +217,7 @@ FilmEditor::connect_to_widgets () _dcp_content_type->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::dcp_content_type_changed), 0, this); _dcp_frame_rate->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::dcp_frame_rate_changed), 0, this); _best_dcp_frame_rate->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::best_dcp_frame_rate_clicked), 0, this); + _dcp_audio_channels->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::dcp_audio_channels_changed), 0, this); _with_subtitles->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::with_subtitles_toggled), 0, this); _subtitle_offset->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::subtitle_offset_changed), 0, this); _subtitle_scale->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::subtitle_scale_changed), 0, this); @@ -581,6 +588,16 @@ FilmEditor::dcp_frame_rate_changed (wxCommandEvent &) ); } +void +FilmEditor::dcp_audio_channels_changed (wxCommandEvent &) +{ + if (!_film) { + return; + } + + _film->set_dcp_audio_channels (_dcp_audio_channels->GetValue ()); +} + /** Called when the metadata stored in the Film object has changed; * so that we can update the GUI. @@ -660,6 +677,10 @@ FilmEditor::film_changed (Film::Property p) _best_dcp_frame_rate->Enable (_film->best_dcp_video_frame_rate () != _film->dcp_video_frame_rate ()); break; } + case Film::DCP_AUDIO_CHANNELS: + _dcp_audio_channels->SetValue (_film->dcp_audio_channels ()); + _audio_mapping->set_channels (_film->dcp_audio_channels ()); + break; } } @@ -868,6 +889,7 @@ FilmEditor::set_film (shared_ptr f) film_changed (Film::J2K_BANDWIDTH); film_changed (Film::DCI_METADATA); film_changed (Film::DCP_VIDEO_FRAME_RATE); + film_changed (Film::DCP_AUDIO_CHANNELS); wxListEvent ev; content_selection_changed (ev); diff --git a/src/wx/film_editor.h b/src/wx/film_editor.h index fdc6e077d..100e47b5b 100644 --- a/src/wx/film_editor.h +++ b/src/wx/film_editor.h @@ -97,6 +97,7 @@ private: void start_changed (); void length_changed (); void ratio_changed (wxCommandEvent &); + void dcp_audio_channels_changed (wxCommandEvent &); /* Handle changes to the model */ void film_changed (Film::Property); @@ -167,6 +168,7 @@ private: wxSpinCtrl* _j2k_bandwidth; wxChoice* _dcp_content_type; wxChoice* _dcp_frame_rate; + wxSpinCtrl* _dcp_audio_channels; wxButton* _best_dcp_frame_rate; wxChoice* _audio_stream; wxStaticText* _audio_description; -- cgit v1.2.3 From 49deab5be257f3a11f5b053224f4a3218fad8da3 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 11 Jul 2013 12:57:53 +0100 Subject: Untested flushing of resamplers. --- src/lib/audio_decoder.cc | 30 ------------------------------ src/lib/player.cc | 12 +++++++++++- src/lib/player.h | 1 + src/lib/resampler.cc | 28 ++++++++++++++++++++++++++++ src/lib/resampler.h | 1 + 5 files changed, 41 insertions(+), 31 deletions(-) (limited to 'src/lib') diff --git a/src/lib/audio_decoder.cc b/src/lib/audio_decoder.cc index dc49a1846..ade11cc32 100644 --- a/src/lib/audio_decoder.cc +++ b/src/lib/audio_decoder.cc @@ -37,36 +37,6 @@ AudioDecoder::AudioDecoder (shared_ptr f) { } -#if 0 -void -AudioDecoder::process_end () -{ - if (_swr_context) { - - shared_ptr film = _film.lock (); - assert (film); - - shared_ptr out (new AudioBuffers (film->audio_mapping().dcp_channels(), 256)); - - while (1) { - int const frames = swr_convert (_swr_context, (uint8_t **) out->data(), 256, 0, 0); - - if (frames < 0) { - throw EncodeError (_("could not run sample-rate converter")); - } - - if (frames == 0) { - break; - } - - out->set_frames (frames); - _writer->write (out); - } - - } -} -#endif - void AudioDecoder::audio (shared_ptr data, AudioContent::Frame frame) { diff --git a/src/lib/player.cc b/src/lib/player.cc index 467f92374..18c42296f 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -261,7 +261,11 @@ Player::process_audio (weak_ptr weak_piece, shared_ptrcontent_audio_frame_rate() != content->output_audio_frame_rate()) { - audio = resampler(content)->run (audio); + shared_ptr r = resampler (content); + audio = r->run (audio); + _last_resampler = r; + } else { + _last_resampler.reset (); } /* Remap channels */ @@ -313,6 +317,12 @@ Player::flush () _audio_buffers.set_frames (0); } + if (_last_resampler) { + shared_ptr resamp = _last_resampler->flush (); + Audio (resamp, _audio_position); + _audio_position += _film->audio_frames_to_time (resamp->frames ()); + } + while (_video_position < _audio_position) { emit_black (); } diff --git a/src/lib/player.h b/src/lib/player.h index 5a4ee97be..b3eadd7c0 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -110,6 +110,7 @@ private: libdcp::Size _video_container_size; boost::shared_ptr _black_frame; std::map, boost::shared_ptr > _resamplers; + boost::shared_ptr _last_resampler; struct { boost::weak_ptr piece; diff --git a/src/lib/resampler.cc b/src/lib/resampler.cc index 1235b9038..ebb507cb1 100644 --- a/src/lib/resampler.cc +++ b/src/lib/resampler.cc @@ -59,3 +59,31 @@ Resampler::run (shared_ptr in) resampled->set_frames (resampled_frames); return resampled; } + +shared_ptr +Resampler::flush () +{ + shared_ptr out (new AudioBuffers (_channels, 0)); + int out_offset = 0; + int64_t const pass_size = 256; + shared_ptr pass (new AudioBuffers (_channels, 256)); + + while (1) { + int const frames = swr_convert (_swr_context, (uint8_t **) pass->data(), pass_size, 0, 0); + + if (frames < 0) { + throw EncodeError (_("could not run sample-rate converter")); + } + + if (frames == 0) { + break; + } + + out->ensure_size (out_offset + frames); + out->copy_from (pass.get(), frames, 0, out_offset); + out_offset += frames; + out->set_frames (out_offset); + } + + return out; +} diff --git a/src/lib/resampler.h b/src/lib/resampler.h index cda718934..21979846e 100644 --- a/src/lib/resampler.h +++ b/src/lib/resampler.h @@ -12,6 +12,7 @@ public: ~Resampler (); boost::shared_ptr run (boost::shared_ptr); + boost::shared_ptr flush (); private: SwrContext* _swr_context; -- cgit v1.2.3 From bb917533ad5beaded24ed56c7c4dc71d50e76263 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 11 Jul 2013 13:12:43 +0100 Subject: Untested audio delay. --- src/lib/audio_decoder.cc | 8 +++++++- src/lib/audio_decoder.h | 5 ++++- src/lib/ffmpeg_decoder.cc | 2 +- src/lib/sndfile_decoder.cc | 2 +- 4 files changed, 13 insertions(+), 4 deletions(-) (limited to 'src/lib') diff --git a/src/lib/audio_decoder.cc b/src/lib/audio_decoder.cc index ade11cc32..2fe347cf2 100644 --- a/src/lib/audio_decoder.cc +++ b/src/lib/audio_decoder.cc @@ -31,15 +31,21 @@ using std::cout; using boost::optional; using boost::shared_ptr; -AudioDecoder::AudioDecoder (shared_ptr f) +AudioDecoder::AudioDecoder (shared_ptr f, shared_ptr c) : Decoder (f) , _audio_position (0) { + _delay_frames = c->audio_delay() * c->content_audio_frame_rate() * f->dcp_audio_frame_rate() / (c->output_audio_frame_rate() * 1000); } void AudioDecoder::audio (shared_ptr data, AudioContent::Frame frame) { + frame += _delay_frames; + Audio (data, frame); _audio_position = frame + data->frames (); + if (_audio_position < 0) { + _audio_position = 0; + } } diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h index ddfb296c9..a7849b9cc 100644 --- a/src/lib/audio_decoder.h +++ b/src/lib/audio_decoder.h @@ -35,7 +35,7 @@ class AudioBuffers; class AudioDecoder : public virtual Decoder { public: - AudioDecoder (boost::shared_ptr); + AudioDecoder (boost::shared_ptr, boost::shared_ptr); /** Emitted when some audio data is ready */ boost::signals2::signal, AudioContent::Frame)> Audio; @@ -44,6 +44,9 @@ protected: void audio (boost::shared_ptr, AudioContent::Frame); AudioContent::Frame _audio_position; + +private: + AudioContent::Frame _delay_frames; }; #endif diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index fddb70294..b2eb1dbde 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -59,7 +59,7 @@ using libdcp::Size; FFmpegDecoder::FFmpegDecoder (shared_ptr f, shared_ptr c, bool video, bool audio) : Decoder (f) , VideoDecoder (f) - , AudioDecoder (f) + , AudioDecoder (f, c) , SubtitleDecoder (f) , FFmpeg (c) , _subtitle_codec_context (0) diff --git a/src/lib/sndfile_decoder.cc b/src/lib/sndfile_decoder.cc index 80a6afd2b..b2ad45125 100644 --- a/src/lib/sndfile_decoder.cc +++ b/src/lib/sndfile_decoder.cc @@ -35,7 +35,7 @@ using boost::shared_ptr; SndfileDecoder::SndfileDecoder (shared_ptr f, shared_ptr c) : Decoder (f) - , AudioDecoder (f) + , AudioDecoder (f, c) , _sndfile_content (c) , _deinterleave_buffer (0) { -- cgit v1.2.3 From f72dc5859fc91e09e85ad16138601fbec7922fb8 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 11 Jul 2013 14:32:56 +0100 Subject: GPL boilerplate. --- src/lib/resampler.cc | 20 ++++++++++++++++++++ src/lib/resampler.h | 19 +++++++++++++++++++ 2 files changed, 39 insertions(+) (limited to 'src/lib') diff --git a/src/lib/resampler.cc b/src/lib/resampler.cc index ebb507cb1..cc5072442 100644 --- a/src/lib/resampler.cc +++ b/src/lib/resampler.cc @@ -1,3 +1,22 @@ +/* + Copyright (C) 2013 Carl Hetherington + + 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. + +*/ + extern "C" { #include "libavutil/channel_layout.h" } @@ -7,6 +26,7 @@ extern "C" { #include "i18n.h" +using std::cout; using boost::shared_ptr; Resampler::Resampler (int in, int out, int channels) diff --git a/src/lib/resampler.h b/src/lib/resampler.h index 21979846e..7c85773c0 100644 --- a/src/lib/resampler.h +++ b/src/lib/resampler.h @@ -1,3 +1,22 @@ +/* + Copyright (C) 2013 Carl Hetherington + + 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 extern "C" { #include -- cgit v1.2.3 From bba1bd9b08eb78bda8cdf7fa1393f3eeb2a504d9 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 11 Jul 2013 14:33:21 +0100 Subject: Missing initialisation of _info.format; fix audio emission into frames rather than Time. --- src/lib/sndfile_decoder.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/lib') diff --git a/src/lib/sndfile_decoder.cc b/src/lib/sndfile_decoder.cc index b2ad45125..8374abbe9 100644 --- a/src/lib/sndfile_decoder.cc +++ b/src/lib/sndfile_decoder.cc @@ -39,6 +39,7 @@ SndfileDecoder::SndfileDecoder (shared_ptr f, shared_ptrfile().string().c_str(), SFM_READ, &_info); if (!_sndfile) { throw DecodeError (_("could not open audio file for reading")); @@ -89,7 +90,7 @@ SndfileDecoder::pass () } data->set_frames (this_time); - audio (data, double(_done) / audio_frame_rate()); + audio (data, _done); _done += this_time; _remaining -= this_time; } -- cgit v1.2.3 From 4122f932b1dc25f7a4592f49f2c9ab19d63b3a4e Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 11 Jul 2013 15:50:18 +0100 Subject: Add test for audio delay, and do it in the player rather than the decoder. --- src/lib/audio_buffers.cc | 12 +++++++ src/lib/audio_buffers.h | 1 + src/lib/audio_decoder.cc | 7 +--- src/lib/audio_decoder.h | 3 -- src/lib/player.cc | 36 +++++++++++++++++--- test/audio_delay_test.cc | 89 ++++++++++++++++++++++++++++++++++++++++++++++++ test/test.cc | 15 +++++--- 7 files changed, 145 insertions(+), 18 deletions(-) create mode 100644 test/audio_delay_test.cc (limited to 'src/lib') diff --git a/src/lib/audio_buffers.cc b/src/lib/audio_buffers.cc index 403babaf7..6d4eb8514 100644 --- a/src/lib/audio_buffers.cc +++ b/src/lib/audio_buffers.cc @@ -144,6 +144,18 @@ AudioBuffers::make_silent (int c) } } +void +AudioBuffers::make_silent (int from, int frames) +{ + assert ((from + frames) <= _allocated_frames); + + for (int c = 0; c < _channels; ++c) { + for (int i = from; i < (from + frames); ++i) { + _data[c][i] = 0; + } + } +} + /** Copy data from another AudioBuffers to this one. All channels are copied. * @param from AudioBuffers to copy from; must have the same number of channels as this. * @param frames_to_copy Number of frames to copy. diff --git a/src/lib/audio_buffers.h b/src/lib/audio_buffers.h index 47b8145a1..b450b83ec 100644 --- a/src/lib/audio_buffers.h +++ b/src/lib/audio_buffers.h @@ -50,6 +50,7 @@ public: void make_silent (); void make_silent (int c); + void make_silent (int from, int frames); void copy_from (AudioBuffers const * from, int frames_to_copy, int read_offset, int write_offset); void move (int from, int to, int frames); diff --git a/src/lib/audio_decoder.cc b/src/lib/audio_decoder.cc index 2fe347cf2..3b97cc16f 100644 --- a/src/lib/audio_decoder.cc +++ b/src/lib/audio_decoder.cc @@ -35,17 +35,12 @@ AudioDecoder::AudioDecoder (shared_ptr f, shared_ptraudio_delay() * c->content_audio_frame_rate() * f->dcp_audio_frame_rate() / (c->output_audio_frame_rate() * 1000); + } void AudioDecoder::audio (shared_ptr data, AudioContent::Frame frame) { - frame += _delay_frames; - Audio (data, frame); _audio_position = frame + data->frames (); - if (_audio_position < 0) { - _audio_position = 0; - } } diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h index a7849b9cc..d3f12ab84 100644 --- a/src/lib/audio_decoder.h +++ b/src/lib/audio_decoder.h @@ -44,9 +44,6 @@ protected: void audio (boost::shared_ptr, AudioContent::Frame); AudioContent::Frame _audio_position; - -private: - AudioContent::Frame _delay_frames; }; #endif diff --git a/src/lib/player.cc b/src/lib/player.cc index 18c42296f..6db7ff693 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -260,6 +260,7 @@ Player::process_audio (weak_ptr weak_piece, shared_ptr content = dynamic_pointer_cast (piece->content); assert (content); + /* Resample */ if (content->content_audio_frame_rate() != content->output_audio_frame_rate()) { shared_ptr r = resampler (content); audio = r->run (audio); @@ -278,15 +279,40 @@ Player::process_audio (weak_ptr weak_piece, shared_ptrstart() + (frame * TIME_HZ / _film->dcp_audio_frame_rate()) + (content->audio_delay() * TIME_HZ / 1000); + + /* We must cut off anything that comes before the start of all time */ + if (time < 0) { + int const frames = - time * _film->dcp_audio_frame_rate() / TIME_HZ; + if (frames >= audio->frames ()) { + return; + } + + shared_ptr trimmed (new AudioBuffers (audio->channels(), audio->frames() - frames)); + trimmed->copy_from (audio.get(), audio->frames() - frames, frames, 0); + + audio = trimmed; + time = 0; + } + /* 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 const time = content->start() + (frame * TIME_HZ / _film->dcp_audio_frame_rate()); - if (time > _audio_position) { /* We can emit some audio from our buffers */ OutputAudioFrame const N = _film->time_to_audio_frames (time - _audio_position); + if (N > _audio_buffers.frames()) { + /* We need some extra silence before whatever is in the buffers */ + _audio_buffers.ensure_size (N); + _audio_buffers.move (0, N - _audio_buffers.frames(), _audio_buffers.frames ()); + _audio_buffers.make_silent (0, _audio_buffers.frames()); + _audio_buffers.set_frames (N); + } + + if (N > _audio_buffers.frames()) { + cout << "N=" << N << ", ab=" << _audio_buffers.frames() << "\n"; + } assert (N <= _audio_buffers.frames()); shared_ptr emit (new AudioBuffers (_audio_buffers.channels(), N)); emit->copy_from (&_audio_buffers, N, 0, 0); @@ -318,9 +344,9 @@ Player::flush () } if (_last_resampler) { - shared_ptr resamp = _last_resampler->flush (); - Audio (resamp, _audio_position); - _audio_position += _film->audio_frames_to_time (resamp->frames ()); +// shared_ptr resamp = _last_resampler->flush (); +// Audio (resamp, _audio_position); +// _audio_position += _film->audio_frames_to_time (resamp->frames ()); } while (_video_position < _audio_position) { diff --git a/test/audio_delay_test.cc b/test/audio_delay_test.cc new file mode 100644 index 000000000..5574bd627 --- /dev/null +++ b/test/audio_delay_test.cc @@ -0,0 +1,89 @@ +/* + Copyright (C) 2013 Carl Hetherington + + 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 +#include +#include +#include +#include "sndfile_content.h" + +using boost::lexical_cast; + +static +void test_audio_delay (int delay_in_ms) +{ + string const film_name = "audio_delay_test_" + lexical_cast (delay_in_ms); + shared_ptr film = new_test_film (film_name); + film->set_dcp_content_type (DCPContentType::from_dci_name ("FTR")); + film->set_container (Ratio::from_id ("185")); + film->set_name (film_name); + + shared_ptr content (new SndfileContent (film, "test/data/staircase.wav")); + content->set_audio_delay (delay_in_ms); + film->examine_and_add_content (content); + wait_for_jobs (); + + film->make_dcp (); + wait_for_jobs (); + + boost::filesystem::path path = "build/test"; + path /= film_name; + path /= film->dcp_name (); + libdcp::DCP check (path.string ()); + check.read (); + + shared_ptr sound_asset = check.cpls().front()->reels().front()->main_sound (); + BOOST_CHECK (sound_asset); + + /* Sample index in the DCP */ + int n = 0; + /* DCP sound asset frame */ + int frame = 0; + /* Delay in frames */ + int const delay_in_frames = delay_in_ms * 48000 / 1000; + bool done = false; + + while (n < sound_asset->intrinsic_duration()) { + shared_ptr sound_frame = sound_asset->get_frame (frame++); + uint8_t const * d = sound_frame->data (); + + for (int i = 0; i < sound_frame->size(); i += (3 * sound_asset->channels())) { + + /* Mono input so it will appear on centre */ + int const sample = d[i + 7] | (d[i + 8] << 8); + + int delayed = n - delay_in_frames; + if (delayed < 0 || delayed >= 4800) { + delayed = 0; + } + + BOOST_CHECK_EQUAL (sample, delayed); + ++n; + } + } +} + + +/* Test audio delay when specified in a piece of audio content */ +BOOST_AUTO_TEST_CASE (audio_delay_test) +{ + test_audio_delay (0); + test_audio_delay (42); + test_audio_delay (-66); +} diff --git a/test/test.cc b/test/test.cc index 0a682383a..dfa38c8f4 100644 --- a/test/test.cc +++ b/test/test.cc @@ -75,7 +75,7 @@ struct TestConfig BOOST_GLOBAL_FIXTURE (TestConfig); -boost::filesystem::path +static boost::filesystem::path test_film_dir (string name) { boost::filesystem::path p; @@ -85,7 +85,7 @@ test_film_dir (string name) return p; } -shared_ptr +static shared_ptr new_test_film (string name) { boost::filesystem::path p = test_film_dir (name); @@ -98,7 +98,7 @@ new_test_film (string name) return f; } -void +static void check_file (string ref, string check) { uintmax_t N = boost::filesystem::file_size (ref); @@ -136,7 +136,7 @@ note (libdcp::NoteType, string n) cout << n << "\n"; } -void +static void check_dcp (string ref, string check) { libdcp::DCP ref_dcp (ref); @@ -154,6 +154,13 @@ check_dcp (string ref, string check) BOOST_CHECK (ref_dcp.equals (check_dcp, options, boost::bind (note, _1, _2))); } +static void +wait_for_jobs () +{ + while (JobManager::instance()->work_to_do ()) {} +} + +#include "audio_delay_test.cc" #include "ffmpeg_pts_offset.cc" #include "ffmpeg_examiner_test.cc" #include "black_fill_test.cc" -- cgit v1.2.3 From 8bdc282a88cbd0446b06866b9436c43200886314 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 11 Jul 2013 15:53:52 +0100 Subject: Remove bad attempt at flushing resamplers. --- src/lib/player.cc | 9 --------- src/lib/resampler.cc | 1 + 2 files changed, 1 insertion(+), 9 deletions(-) (limited to 'src/lib') diff --git a/src/lib/player.cc b/src/lib/player.cc index 6db7ff693..7ab72d9a1 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -264,9 +264,6 @@ Player::process_audio (weak_ptr weak_piece, shared_ptrcontent_audio_frame_rate() != content->output_audio_frame_rate()) { shared_ptr r = resampler (content); audio = r->run (audio); - _last_resampler = r; - } else { - _last_resampler.reset (); } /* Remap channels */ @@ -343,12 +340,6 @@ Player::flush () _audio_buffers.set_frames (0); } - if (_last_resampler) { -// shared_ptr resamp = _last_resampler->flush (); -// Audio (resamp, _audio_position); -// _audio_position += _film->audio_frames_to_time (resamp->frames ()); - } - while (_video_position < _audio_position) { emit_black (); } diff --git a/src/lib/resampler.cc b/src/lib/resampler.cc index cc5072442..565fb69c2 100644 --- a/src/lib/resampler.cc +++ b/src/lib/resampler.cc @@ -80,6 +80,7 @@ Resampler::run (shared_ptr in) return resampled; } +/* XXX: no-one calls this */ shared_ptr Resampler::flush () { -- cgit v1.2.3