+
+FFmpegStream::FFmpegStream (shared_ptr<const cxml::Node> node, int version)
+ : _legacy_id (false)
+{
+ name = node->string_child ("Name");
+ id = node->number_child<int> ("Id");
+ if (version == 4 || node->optional_bool_child ("LegacyId")) {
+ _legacy_id = true;
+ }
+}
+
+void
+FFmpegStream::as_xml (xmlpp::Node* root) const
+{
+ root->add_child("Name")->add_child_text (name);
+ root->add_child("Id")->add_child_text (lexical_cast<string> (id));
+ if (_legacy_id) {
+ /* Write this so that version > 4 files are read in correctly
+ if the Id came originally from a version <= 4 file.
+ */
+ root->add_child("LegacyId")->add_child_text ("1");
+ }
+}
+
+FFmpegAudioStream::FFmpegAudioStream (shared_ptr<const cxml::Node> node, int version)
+ : FFmpegStream (node, version)
+ , mapping (node->node_child ("Mapping"))
+{
+ frame_rate = node->number_child<int> ("FrameRate");
+ channels = node->number_child<int64_t> ("Channels");
+ first_audio = node->optional_number_child<double> ("FirstAudio");
+}
+
+void
+FFmpegAudioStream::as_xml (xmlpp::Node* root) const
+{
+ FFmpegStream::as_xml (root);
+ root->add_child("FrameRate")->add_child_text (lexical_cast<string> (frame_rate));
+ root->add_child("Channels")->add_child_text (lexical_cast<string> (channels));
+ if (first_audio) {
+ root->add_child("FirstAudio")->add_child_text (lexical_cast<string> (first_audio.get ()));
+ }
+ mapping.as_xml (root->add_child("Mapping"));
+}
+
+int
+FFmpegStream::index (AVFormatContext const * fc) const
+{
+ if (_legacy_id) {
+ return id;
+ }
+
+ size_t i = 0;
+ while (i < fc->nb_streams) {
+ if (fc->streams[i]->id == id) {
+ return i;
+ }
+ ++i;
+ }
+
+ assert (false);
+}
+
+AVStream *
+FFmpegStream::stream (AVFormatContext const * fc) const
+{
+ if (_legacy_id) {
+ return fc->streams[id];
+ }
+
+ size_t i = 0;
+ while (i < fc->nb_streams) {
+ if (fc->streams[i]->id == id) {
+ return fc->streams[i];
+ }
+ ++i;
+ }
+
+ assert (false);
+ return 0;
+}
+
+/** Construct a SubtitleStream from a value returned from to_string().
+ * @param t String returned from to_string().
+ * @param v State file version.
+ */
+FFmpegSubtitleStream::FFmpegSubtitleStream (shared_ptr<const cxml::Node> node, int version)
+ : FFmpegStream (node, version)
+{
+
+}
+
+void
+FFmpegSubtitleStream::as_xml (xmlpp::Node* root) const
+{
+ FFmpegStream::as_xml (root);
+}
+
+DCPTime
+FFmpegContent::full_length () const
+{
+ shared_ptr<const Film> film = _film.lock ();
+ assert (film);
+
+ FrameRateChange frc (video_frame_rate (), film->video_frame_rate ());
+ return video_length() * frc.factor() * TIME_HZ / film->video_frame_rate ();
+}
+
+AudioMapping
+FFmpegContent::audio_mapping () const
+{
+ boost::mutex::scoped_lock lm (_mutex);
+
+ if (!_audio_stream) {
+ return AudioMapping ();
+ }
+
+ return _audio_stream->mapping;
+}
+
+void
+FFmpegContent::set_filters (vector<Filter const *> const & filters)
+{
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _filters = filters;
+ }
+
+ signal_changed (FFmpegContentProperty::FILTERS);
+}
+
+void
+FFmpegContent::set_audio_mapping (AudioMapping m)
+{
+ audio_stream()->mapping = m;
+ signal_changed (AudioContentProperty::AUDIO_MAPPING);
+}
+
+string
+FFmpegContent::identifier () const
+{
+ stringstream s;
+
+ s << VideoContent::identifier();
+
+ boost::mutex::scoped_lock lm (_mutex);
+
+ if (_subtitle_stream) {
+ s << "_" << _subtitle_stream->id;
+ }
+
+ for (vector<Filter const *>::const_iterator i = _filters.begin(); i != _filters.end(); ++i) {
+ s << "_" << (*i)->id ();
+ }
+
+ return s.str ();
+}
+