Partial work on using a no-video FFmpeg file.
authorCarl Hetherington <cth@carlh.net>
Tue, 10 May 2016 12:50:47 +0000 (13:50 +0100)
committerCarl Hetherington <cth@carlh.net>
Wed, 18 May 2016 10:50:29 +0000 (11:50 +0100)
src/lib/ffmpeg.cc
src/lib/ffmpeg_content.cc
src/lib/ffmpeg_decoder.cc
src/lib/ffmpeg_examiner.cc
src/lib/ffmpeg_examiner.h
test/ffmpeg_audio_only_test.cc [new file with mode: 0644]
test/wscript

index 7b1eae2b102cdf1f0dfe3925c2fc0f1404871313..bfa3d4e7f7dd8401976d5f08e9af8f03af8f72b2 100644 (file)
@@ -161,10 +161,6 @@ FFmpeg::setup_general ()
                _video_stream = video_stream_undefined_frame_rate.get();
        }
 
-       if (!_video_stream) {
-               throw DecodeError (N_("could not find video stream"));
-       }
-
        /* Hack: if the AVStreams have duplicate IDs, replace them with our
           own.  We use the IDs so that we can cope with VOBs, in which streams
           move about in index but remain with the same ID in different
index a0bf88c2513a077870d9c7e84b42b29940f7b253..bb9795f25d0909a138b2fb46c58deab3d3cf01c5 100644 (file)
@@ -64,11 +64,7 @@ int const FFmpegContentProperty::FILTERS = 102;
 FFmpegContent::FFmpegContent (shared_ptr<const Film> film, boost::filesystem::path p)
        : Content (film, p)
 {
-       video.reset (new VideoContent (this, film));
-       audio.reset (new AudioContent (this, film));
-       subtitle.reset (new SubtitleContent (this, film));
 
-       set_default_colour_conversion ();
 }
 
 FFmpegContent::FFmpegContent (shared_ptr<const Film> film, cxml::ConstNodePtr node, int version, list<string>& notes)
@@ -210,35 +206,44 @@ FFmpegContent::examine (shared_ptr<Job> job)
        Content::examine (job);
 
        shared_ptr<FFmpegExaminer> examiner (new FFmpegExaminer (shared_from_this (), job));
-       video->take_from_examiner (examiner);
-       set_default_colour_conversion ();
+
+       if (examiner->has_video ()) {
+               video.reset (new VideoContent (this, film ()));
+               video->take_from_examiner (examiner);
+               set_default_colour_conversion ();
+       }
 
        {
                boost::mutex::scoped_lock lm (_mutex);
 
-               _subtitle_streams = examiner->subtitle_streams ();
-               if (!_subtitle_streams.empty ()) {
-                       _subtitle_stream = _subtitle_streams.front ();
+               if (examiner->has_video ()) {
+                       _first_video = examiner->first_video ();
+                       _color_range = examiner->color_range ();
+                       _color_primaries = examiner->color_primaries ();
+                       _color_trc = examiner->color_trc ();
+                       _colorspace = examiner->colorspace ();
+                       _bits_per_pixel = examiner->bits_per_pixel ();
                }
 
-               BOOST_FOREACH (shared_ptr<FFmpegAudioStream> i, examiner->audio_streams ()) {
-                       audio->add_stream (i);
-               }
+               if (!examiner->audio_streams().empty ()) {
+                       audio.reset (new AudioContent (this, film ()));
+
+                       BOOST_FOREACH (shared_ptr<FFmpegAudioStream> i, examiner->audio_streams ()) {
+                               audio->add_stream (i);
+                       }
 
-               if (!audio->streams().empty ()) {
                        AudioStreamPtr as = audio->streams().front();
                        AudioMapping m = as->mapping ();
                        film()->make_audio_mapping_default (m);
                        as->set_mapping (m);
                }
 
-               _first_video = examiner->first_video ();
+               _subtitle_streams = examiner->subtitle_streams ();
+               if (!_subtitle_streams.empty ()) {
+                       subtitle.reset (new SubtitleContent (this, film ()));
+                       _subtitle_stream = _subtitle_streams.front ();
+               }
 
-               _color_range = examiner->color_range ();
-               _color_primaries = examiner->color_primaries ();
-               _color_trc = examiner->color_trc ();
-               _colorspace = examiner->colorspace ();
-               _bits_per_pixel = examiner->bits_per_pixel ();
        }
 
        signal_changed (FFmpegContentProperty::SUBTITLE_STREAMS);
index 72df69126857bde91d0b86ba27a9e48ea4f4c6d6..d84bb2a52e67d1aead102d5af1242cb474e1a433 100644 (file)
@@ -77,8 +77,12 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr<const FFmpegContent> c, shared_ptr<Log>
        , SubtitleDecoder (c->subtitle)
        , FFmpeg (c)
        , _log (log)
-       , _pts_offset (pts_offset (c->ffmpeg_audio_streams(), c->first_video(), c->active_video_frame_rate()))
 {
+       if (c->video) {
+               _pts_offset = pts_offset (c->ffmpeg_audio_streams(), c->first_video(), c->active_video_frame_rate());
+       } else {
+               _pts_offset = ContentTime ();
+       }
 }
 
 void
index eeb0cfc389c5df32f335fd324633231ac6b25b55..44d6a87dfdd6b262b4eaafd5d54ab678d7c809d8 100644 (file)
@@ -72,10 +72,12 @@ FFmpegExaminer::FFmpegExaminer (shared_ptr<const FFmpegContent> c, shared_ptr<Jo
                }
        }
 
-       /* See if the header has duration information in it */
-       _need_video_length = _format_context->duration == AV_NOPTS_VALUE;
-       if (!_need_video_length) {
-               _video_length = (double (_format_context->duration) / AV_TIME_BASE) * video_frame_rate().get ();
+       if (has_video ()) {
+               /* See if the header has duration information in it */
+               _need_video_length = _format_context->duration == AV_NOPTS_VALUE;
+               if (!_need_video_length) {
+                       _video_length = (double (_format_context->duration) / AV_TIME_BASE) * video_frame_rate().get ();
+               }
        }
 
        if (job) {
@@ -169,7 +171,7 @@ FFmpegExaminer::FFmpegExaminer (shared_ptr<const FFmpegContent> c, shared_ptr<Jo
           this is because we might not know the PTS offset when the first subtitle is seen.
           Now we know the PTS offset so we can apply it to those subtitles.
        */
-       if (video_frame_rate()) {
+       if (has_video() && video_frame_rate()) {
                BOOST_FOREACH (shared_ptr<FFmpegSubtitleStream> i, _subtitle_streams) {
                        i->add_offset (pts_offset (_audio_streams, _first_video, video_frame_rate().get()));
                }
@@ -477,3 +479,9 @@ FFmpegExaminer::yuv () const
                return false;
        }
 }
+
+bool
+FFmpegExaminer::has_video () const
+{
+       return static_cast<bool> (_video_stream);
+}
index b9ca04e4c6ce958bf6ae78247e6b71fe177c821f..258c2ea5359d9d8ad0a1885cc93ffe31e75a1a0d 100644 (file)
@@ -32,6 +32,8 @@ class FFmpegExaminer : public FFmpeg, public VideoExaminer
 public:
        FFmpegExaminer (boost::shared_ptr<const FFmpegContent>, boost::shared_ptr<Job> job = boost::shared_ptr<Job> ());
 
+       bool has_video () const;
+
        boost::optional<double> video_frame_rate () const;
        dcp::Size video_size () const;
        Frame video_length () const;
diff --git a/test/ffmpeg_audio_only_test.cc b/test/ffmpeg_audio_only_test.cc
new file mode 100644 (file)
index 0000000..a0c39b9
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+    Copyright (C) 2016 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/ffmpeg_content.h"
+#include "test.h"
+#include <boost/test/unit_test.hpp>
+
+using boost::shared_ptr;
+
+/** Test the FFmpeg code with audio-only content */
+BOOST_AUTO_TEST_CASE (ffmpeg_audio_only_test)
+{
+       shared_ptr<Film> film = new_test_film ("ffmpeg_audio_only_test");
+       film->set_name ("test_film");
+       shared_ptr<FFmpegContent> c (new FFmpegContent (film, "test/data/sine_440.mp3"));
+       film->examine_and_add_content (c);
+       wait_for_jobs ();
+       film->write_metadata ();
+}
+
index 7efe6e61c9f692f594e631ab0ec97ca107ff6967..a93eac6611afe37aa0b4458315a87938d0922da1 100644 (file)
@@ -51,6 +51,7 @@ def build(bld):
                  dcp_subtitle_test.cc
                  dcpomatic_time_test.cc
                  ffmpeg_audio_test.cc
+                 ffmpeg_audio_only_test.cc
                  ffmpeg_dcp_test.cc
                  ffmpeg_decoder_seek_test.cc
                  ffmpeg_decoder_sequential_test.cc