+int
+FFmpegDecoder::bytes_per_audio_sample () const
+{
+ return av_get_bytes_per_sample (audio_sample_format ());
+}
+
+void
+FFmpegDecoder::set_audio_stream (shared_ptr<AudioStream> s)
+{
+ AudioDecoder::set_audio_stream (s);
+ setup_audio ();
+}
+
+void
+FFmpegDecoder::set_subtitle_stream (shared_ptr<SubtitleStream> s)
+{
+ VideoDecoder::set_subtitle_stream (s);
+ setup_subtitle ();
+}
+
+void
+FFmpegDecoder::filter_and_emit_video (AVFrame* frame)
+{
+ shared_ptr<FilterGraph> graph;
+
+ list<shared_ptr<FilterGraph> >::iterator i = _filter_graphs.begin();
+ while (i != _filter_graphs.end() && !(*i)->can_process (Size (frame->width, frame->height), (AVPixelFormat) frame->format)) {
+ ++i;
+ }
+
+ if (i == _filter_graphs.end ()) {
+ graph.reset (new FilterGraph (_film, this, _opt->apply_crop, Size (frame->width, frame->height), (AVPixelFormat) frame->format));
+ _filter_graphs.push_back (graph);
+ _film->log()->log (String::compose ("New graph for %1x%2, pixel format %3", frame->width, frame->height, frame->format));
+ } else {
+ graph = *i;
+ }
+
+ list<shared_ptr<Image> > images = graph->process (frame);
+
+ for (list<shared_ptr<Image> >::iterator i = images.begin(); i != images.end(); ++i) {
+ emit_video (*i);
+ }
+}
+
+shared_ptr<FFmpegAudioStream>
+FFmpegAudioStream::create (string t, optional<int> v)
+{
+ if (!v) {
+ /* version < 1; no type in the string, and there's only FFmpeg streams anyway */
+ return shared_ptr<FFmpegAudioStream> (new FFmpegAudioStream (t, v));
+ }
+
+ stringstream s (t);
+ string type;
+ s >> type;
+ if (type != "ffmpeg") {
+ return shared_ptr<FFmpegAudioStream> ();
+ }
+
+ return shared_ptr<FFmpegAudioStream> (new FFmpegAudioStream (t, v));
+}
+
+FFmpegAudioStream::FFmpegAudioStream (string t, optional<int> version)
+{
+ stringstream n (t);
+
+ int name_index = 4;
+ if (!version) {
+ name_index = 2;
+ int channels;
+ n >> _id >> channels;
+ _channel_layout = av_get_default_channel_layout (channels);
+ _sample_rate = 0;
+ } else {
+ string type;
+ /* Current (marked version 1) */
+ n >> type >> _id >> _sample_rate >> _channel_layout;
+ assert (type == "ffmpeg");
+ }
+
+ for (int i = 0; i < name_index; ++i) {
+ size_t const s = t.find (' ');
+ if (s != string::npos) {
+ t = t.substr (s + 1);
+ }
+ }
+
+ _name = t;
+}
+
+string
+FFmpegAudioStream::to_string () const
+{
+ return String::compose ("ffmpeg %1 %2 %3 %4", _id, _sample_rate, _channel_layout, _name);
+}
+
+/** @return Length (in video frames) according to our content's header */
+SourceFrame
+FFmpegDecoder::length () const
+{
+ return (double(_format_context->duration) / AV_TIME_BASE) * frames_per_second();
+}