diff options
| author | Carl Hetherington <cth@carlh.net> | 2012-10-17 13:47:50 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2012-10-17 13:47:50 +0100 |
| commit | 4dfce74792c3ea55ecf2479568f76d7e54b826e0 (patch) | |
| tree | d21aa7e386be12027239c4a1f5a25e6f42d04b8b /src/lib | |
| parent | 91e8c79235abccac95c63952192fd63840727f99 (diff) | |
Basic support for selection of audio / subtitle streams.
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/decoder.h | 12 | ||||
| -rw-r--r-- | src/lib/ffmpeg_decoder.cc | 61 | ||||
| -rw-r--r-- | src/lib/ffmpeg_decoder.h | 12 | ||||
| -rw-r--r-- | src/lib/film.cc | 6 | ||||
| -rw-r--r-- | src/lib/film.h | 18 | ||||
| -rw-r--r-- | src/lib/film_state.cc | 60 | ||||
| -rw-r--r-- | src/lib/film_state.h | 7 | ||||
| -rw-r--r-- | src/lib/stream.cc | 41 | ||||
| -rw-r--r-- | src/lib/stream.h | 39 | ||||
| -rw-r--r-- | src/lib/wscript | 1 |
10 files changed, 234 insertions, 23 deletions
diff --git a/src/lib/decoder.h b/src/lib/decoder.h index 8a04ec9f2..312cbbe8e 100644 --- a/src/lib/decoder.h +++ b/src/lib/decoder.h @@ -30,6 +30,7 @@ #include <boost/shared_ptr.hpp> #include <sigc++/sigc++.h> #include "util.h" +#include "stream.h" class Job; class FilmState; @@ -79,6 +80,17 @@ public: int last_video_frame () const { return _video_frame; } + + virtual std::vector<Stream> audio_streams () const { + return std::vector<Stream> (); + } + + virtual std::vector<Stream> subtitle_streams () const { + return std::vector<Stream> (); + } + + virtual void set_audio_stream (Stream s) {} + virtual void set_subtitle_stream (Stream s) {} /** Emitted when a video frame is ready. * First parameter is the frame. diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index e85439f6e..4cec7ef35 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -110,9 +110,15 @@ FFmpegDecoder::setup_general () if (_format_context->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { _video_stream = i; } else if (_format_context->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) { - _audio_stream = i; + if (_audio_stream == -1) { + _audio_stream = i; + } + _audio_streams.push_back (Stream (stream_name (_format_context->streams[i]), i)); } else if (_format_context->streams[i]->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) { - _subtitle_stream = i; + if (_subtitle_stream == -1) { + _subtitle_stream = i; + } + _subtitle_streams.push_back (Stream (stream_name (_format_context->streams[i]), i)); } } @@ -356,3 +362,54 @@ FFmpegDecoder::has_subtitles () const { return (_subtitle_stream != -1); } + +vector<Stream> +FFmpegDecoder::audio_streams () const +{ + return _audio_streams; +} + +vector<Stream> +FFmpegDecoder::subtitle_streams () const +{ + return _subtitle_streams; +} + +void +FFmpegDecoder::set_audio_stream (int s) +{ + _audio_stream = s; + setup_audio (); +} + +void +FFmpegDecoder::set_subtitle_stream (int s) +{ + _subtitle_stream = s; + setup_subtitle (); +} + +string +FFmpegDecoder::stream_name (AVStream* s) const +{ + stringstream n; + + AVDictionaryEntry const * lang = av_dict_get (s->metadata, "language", 0, 0); + if (lang) { + n << lang->value; + } + + AVDictionaryEntry const * title = av_dict_get (s->metadata, "title", 0, 0); + if (title) { + if (!n.str().empty()) { + n << " "; + } + n << title->value; + } + + if (n.str().empty()) { + n << "unknown"; + } + + return n.str (); +} diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h index ec822bf79..9abc7f49a 100644 --- a/src/lib/ffmpeg_decoder.h +++ b/src/lib/ffmpeg_decoder.h @@ -39,6 +39,7 @@ struct AVFormatContext; struct AVFrame; struct AVBufferContext; struct AVCodec; +struct AVStream; class Job; class FilmState; class Options; @@ -65,6 +66,12 @@ public: int64_t audio_channel_layout () const; bool has_subtitles () const; + std::vector<Stream> audio_streams () const; + std::vector<Stream> subtitle_streams () const; + + void set_audio_stream (int id); + void set_subtitle_stream (int id); + private: bool do_pass (); @@ -81,11 +88,16 @@ private: void maybe_add_subtitle (); + std::string stream_name (AVStream* s) const; + AVFormatContext* _format_context; int _video_stream; int _audio_stream; ///< may be < 0 if there is no audio int _subtitle_stream; ///< may be < 0 if there is no subtitle AVFrame* _frame; + + std::vector<Stream> _audio_streams; + std::vector<Stream> _subtitle_streams; AVCodecContext* _video_codec_context; AVCodec* _video_codec; diff --git a/src/lib/film.cc b/src/lib/film.cc index ce83b1324..9e1640d58 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -201,6 +201,10 @@ Film::set_content (string c) _state.audio_sample_rate = d->audio_sample_rate (); _state.audio_sample_format = d->audio_sample_format (); _state.has_subtitles = d->has_subtitles (); + _state.audio_streams = d->audio_streams (); + _state.subtitle_streams = d->subtitle_streams (); + _state.audio_stream = _state.audio_streams.empty() ? -1 : _state.audio_streams.front().id; + _state.subtitle_stream = _state.subtitle_streams.empty() ? -1 : _state.subtitle_streams.front().id; _state.content_digest = md5_digest (s->content_path ()); _state.content = c; @@ -211,6 +215,8 @@ Film::set_content (string c) signal_changed (AUDIO_CHANNELS); signal_changed (AUDIO_SAMPLE_RATE); signal_changed (CONTENT); + signal_changed (AUDIO_STREAM); + signal_changed (SUBTITLE_STREAM); } /** Set the format that this Film should be shown in */ diff --git a/src/lib/film.h b/src/lib/film.h index ae0ad7ad1..deff4b8a8 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -162,6 +162,22 @@ public: return _state.dcp_content_type; } + std::vector<Stream> audio_streams () const { + return _state.audio_streams; + } + + int audio_stream () const { + return _state.audio_stream; + } + + std::vector<Stream> subtitle_streams () const { + return _state.subtitle_streams; + } + + int subtitle_stream () const { + return _state.subtitle_stream; + } + void set_dcp_frames (int); void set_dcp_trim_action (TrimAction); void set_dcp_ab (bool); @@ -287,6 +303,7 @@ public: DCP_FRAMES, DCP_TRIM_ACTION, DCP_AB, + AUDIO_STREAM, AUDIO_GAIN, AUDIO_DELAY, THUMBS, @@ -296,6 +313,7 @@ public: AUDIO_CHANNELS, AUDIO_SAMPLE_RATE, STILL_DURATION, + SUBTITLE_STREAM, WITH_SUBTITLES, SUBTITLE_OFFSET, SUBTITLE_SCALE, diff --git a/src/lib/film_state.cc b/src/lib/film_state.cc index aa8bb5563..0d0bd6313 100644 --- a/src/lib/film_state.cc +++ b/src/lib/film_state.cc @@ -79,12 +79,20 @@ FilmState::write_metadata (ofstream& f) const } f << "dcp_ab " << (dcp_ab ? "1" : "0") << "\n"; + f << "selected_audio_stream " << audio_stream << "\n"; f << "audio_gain " << audio_gain << "\n"; f << "audio_delay " << audio_delay << "\n"; f << "still_duration " << still_duration << "\n"; f << "with_subtitles " << with_subtitles << "\n"; f << "subtitle_offset " << subtitle_offset << "\n"; f << "subtitle_scale " << subtitle_scale << "\n"; + f << "audio_language " << audio_language << "\n"; + f << "subtitle_language " << subtitle_language << "\n"; + f << "territory " << territory << "\n"; + f << "rating " << rating << "\n"; + f << "studio " << studio << "\n"; + f << "facility " << facility << "\n"; + f << "package_type " << package_type << "\n"; /* Cached stuff; this is information about our content; we could look it up each time, but that's slow. @@ -99,14 +107,16 @@ FilmState::write_metadata (ofstream& f) const f << "audio_sample_rate " << audio_sample_rate << "\n"; f << "audio_sample_format " << audio_sample_format_to_string (audio_sample_format) << "\n"; f << "content_digest " << content_digest << "\n"; + f << "selected_subtitle_stream " << subtitle_stream << "\n"; f << "has_subtitles " << has_subtitles << "\n"; - f << "audio_language " << audio_language << "\n"; - f << "subtitle_language " << subtitle_language << "\n"; - f << "territory " << territory << "\n"; - f << "rating " << rating << "\n"; - f << "studio " << studio << "\n"; - f << "facility " << facility << "\n"; - f << "package_type " << package_type << "\n"; + + for (vector<Stream>::const_iterator i = audio_streams.begin(); i != audio_streams.end(); ++i) { + f << "audio_stream " << i->to_string () << "\n"; + } + + for (vector<Stream>::const_iterator i = subtitle_streams.begin(); i != subtitle_streams.end(); ++i) { + f << "subtitle_stream " << i->to_string () << "\n"; + } } /** Read state from a key / value pair. @@ -151,6 +161,8 @@ FilmState::read_metadata (string k, string v) } } else if (k == "dcp_ab") { dcp_ab = (v == "1"); + } else if (k == "selected_audio_stream") { + audio_stream = atoi (v.c_str ()); } else if (k == "audio_gain") { audio_gain = atof (v.c_str ()); } else if (k == "audio_delay") { @@ -163,6 +175,22 @@ FilmState::read_metadata (string k, string v) subtitle_offset = atoi (v.c_str ()); } else if (k == "subtitle_scale") { subtitle_scale = atof (v.c_str ()); + } else if (k == "selected_subtitle_stream") { + subtitle_stream = atoi (v.c_str ()); + } else if (k == "audio_language") { + audio_language = v; + } else if (k == "subtitle_language") { + subtitle_language = v; + } else if (k == "territory") { + territory = v; + } else if (k == "rating") { + rating = v; + } else if (k == "studio") { + studio = v; + } else if (k == "facility") { + facility = v; + } else if (k == "package_type") { + package_type = v; } /* Cached stuff */ @@ -188,20 +216,10 @@ FilmState::read_metadata (string k, string v) content_digest = v; } else if (k == "has_subtitles") { has_subtitles = (v == "1"); - } else if (k == "audio_language") { - audio_language = v; - } else if (k == "subtitle_language") { - subtitle_language = v; - } else if (k == "territory") { - territory = v; - } else if (k == "rating") { - rating = v; - } else if (k == "studio") { - studio = v; - } else if (k == "facility") { - facility = v; - } else if (k == "package_type") { - package_type = v; + } else if (k == "audio_stream") { + audio_streams.push_back (Stream (v)); + } else if (k == "subtitle_stream") { + subtitle_streams.push_back (Stream (v)); } } diff --git a/src/lib/film_state.h b/src/lib/film_state.h index ea287fb3b..38176f224 100644 --- a/src/lib/film_state.h +++ b/src/lib/film_state.h @@ -34,6 +34,7 @@ extern "C" { #include "scaler.h" #include "util.h" #include "trim_action.h" +#include "stream.h" class Format; class DCPContentType; @@ -60,9 +61,11 @@ public: , dcp_frames (0) , dcp_trim_action (CUT) , dcp_ab (false) + , audio_stream (-1) , audio_gain (0) , audio_delay (0) , still_duration (10) + , subtitle_stream (-1) , with_subtitles (false) , subtitle_offset (0) , subtitle_scale (1) @@ -130,12 +133,14 @@ public: has the specified filters and post-processing. */ bool dcp_ab; + int audio_stream; /** Gain to apply to audio in dB */ float audio_gain; /** Delay to apply to audio (positive moves audio later) in milliseconds */ int audio_delay; /** Duration to make still-sourced films (in seconds) */ int still_duration; + int subtitle_stream; /** True if subtitles should be shown for this film */ bool with_subtitles; /** y offset for placing subtitles, in source pixels; +ve is further down @@ -172,6 +177,8 @@ public: std::string content_digest; /** true if the source has subtitles */ bool has_subtitles; + std::vector<Stream> audio_streams; + std::vector<Stream> subtitle_streams; private: std::string thumb_file_for_frame (int) const; diff --git a/src/lib/stream.cc b/src/lib/stream.cc new file mode 100644 index 000000000..e40738990 --- /dev/null +++ b/src/lib/stream.cc @@ -0,0 +1,41 @@ +/* + Copyright (C) 2012 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 <sstream> +#include "compose.hpp" +#include "stream.h" + +using namespace std; + +Stream::Stream (string t) +{ + stringstream n (t); + n >> id; + + size_t const s = t.find (' '); + if (s != string::npos) { + name = t.substr (s + 1); + } +} + +string +Stream::to_string () const +{ + return String::compose ("%1 %2", id, name); +} diff --git a/src/lib/stream.h b/src/lib/stream.h new file mode 100644 index 000000000..764c03d79 --- /dev/null +++ b/src/lib/stream.h @@ -0,0 +1,39 @@ +/* + Copyright (C) 2012 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. + +*/ + +#ifndef DVDOMATIC_STREAM_H +#define DVDOMATIC_STREAM_H + +struct Stream +{ +public: + Stream (std::string t); + + Stream (std::string n, int i) + : name (n) + , id (i) + {} + + std::string to_string () const; + + std::string name; + int id; +}; + +#endif diff --git a/src/lib/wscript b/src/lib/wscript index 63847224c..6ce216d81 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -43,6 +43,7 @@ def build(bld): screen.cc server.cc sound_processor.cc + stream.cc subtitle.cc thumbs_job.cc tiff_decoder.cc |
