2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
4 * This file is part of CasparCG (www.casparcg.com).
6 * CasparCG is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * CasparCG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
19 * Author: Robert Nagy, ronag89@gmail.com
22 #include "../StdAfx.h"
24 #include "ffmpeg_producer.h"
26 #include "../ffmpeg_error.h"
27 #include "../ffmpeg.h"
29 #include "muxer/frame_muxer.h"
30 #include "input/input.h"
31 #include "util/util.h"
32 #include "audio/audio_decoder.h"
33 #include "video/video_decoder.h"
35 #include <common/env.h>
36 #include <common/log.h>
37 #include <common/param.h>
38 #include <common/diagnostics/graph.h>
39 #include <common/future.h>
40 #include <common/timer.h>
41 #include <common/assert.h>
43 #include <core/video_format.h>
44 #include <core/producer/frame_producer.h>
45 #include <core/frame/audio_channel_layout.h>
46 #include <core/frame/frame_factory.h>
47 #include <core/frame/draw_frame.h>
48 #include <core/frame/frame_transform.h>
49 #include <core/monitor/monitor.h>
50 #include <core/help/help_repository.h>
51 #include <core/help/help_sink.h>
53 #include <boost/algorithm/string.hpp>
54 #include <boost/filesystem.hpp>
55 #include <boost/property_tree/ptree.hpp>
56 #include <boost/regex.hpp>
57 #include <boost/thread/future.hpp>
59 #include <tbb/parallel_invoke.h>
65 namespace caspar { namespace ffmpeg {
67 struct seek_out_of_range : virtual user_error {};
69 std::wstring get_relative_or_original(
70 const std::wstring& filename,
71 const boost::filesystem::path& relative_to)
73 boost::filesystem::path file(filename);
74 auto result = file.filename().wstring();
76 boost::filesystem::path current_path = file;
80 current_path = current_path.parent_path();
82 if (boost::filesystem::equivalent(current_path, relative_to))
85 if (current_path.empty())
88 result = current_path.filename().wstring() + L"/" + result;
94 struct ffmpeg_producer : public core::frame_producer_base
96 spl::shared_ptr<core::monitor::subject> monitor_subject_;
97 const std::wstring filename_;
98 const std::wstring path_relative_to_media_ = get_relative_or_original(filename_, env::media_folder());
100 const spl::shared_ptr<diagnostics::graph> graph_;
102 const spl::shared_ptr<core::frame_factory> frame_factory_;
103 const core::video_format_desc format_desc_;
107 const double fps_ = read_fps(input_.context(), format_desc_.fps);
108 const uint32_t start_;
109 const bool thumbnail_mode_;
111 std::unique_ptr<video_decoder> video_decoder_;
112 std::unique_ptr<audio_decoder> audio_decoder_;
113 std::unique_ptr<frame_muxer> muxer_;
114 core::constraints constraints_;
116 core::draw_frame last_frame_ = core::draw_frame::empty();
118 boost::optional<uint32_t> seek_target_;
121 explicit ffmpeg_producer(
122 const spl::shared_ptr<core::frame_factory>& frame_factory,
123 const core::video_format_desc& format_desc,
124 const std::wstring& channel_layout_spec,
125 const std::wstring& filename,
126 const std::wstring& filter,
131 : filename_(filename)
132 , frame_factory_(frame_factory)
133 , format_desc_(format_desc)
134 , input_(graph_, filename_, loop, start, length, thumbnail_mode)
135 , fps_(read_fps(input_.context(), format_desc_.fps))
137 , thumbnail_mode_(thumbnail_mode)
139 graph_->set_color("frame-time", diagnostics::color(0.1f, 1.0f, 0.1f));
140 graph_->set_color("underflow", diagnostics::color(0.6f, 0.3f, 0.9f));
141 diagnostics::register_graph(graph_);
146 video_decoder_.reset(new video_decoder(input_, thumbnail_mode));
147 video_decoder_->monitor_output().attach_parent(monitor_subject_);
148 constraints_.width.set(video_decoder_->width());
149 constraints_.height.set(video_decoder_->height());
151 if (is_logging_quiet_for_thread())
152 CASPAR_LOG(debug) << print() << L" " << video_decoder_->print();
154 CASPAR_LOG(info) << print() << L" " << video_decoder_->print();
156 catch(averror_stream_not_found&)
158 CASPAR_LOG(debug) << print() << " No video-stream found. Running without video.";
162 CASPAR_LOG_CURRENT_EXCEPTION();
163 CASPAR_LOG(warning) << print() << "Failed to open video-stream. Running without video.";
166 auto channel_layout = core::audio_channel_layout::invalid();
172 audio_decoder_.reset(new audio_decoder(input_, format_desc_, channel_layout_spec));
173 audio_decoder_->monitor_output().attach_parent(monitor_subject_);
175 channel_layout = audio_decoder_->channel_layout();
177 CASPAR_LOG(info) << print() << L" " << audio_decoder_->print();
179 catch (averror_stream_not_found&)
181 CASPAR_LOG(debug) << print() << " No audio-stream found. Running without audio.";
185 CASPAR_LOG_CURRENT_EXCEPTION();
186 CASPAR_LOG(warning) << print() << " Failed to open audio-stream. Running without audio.";
190 if (start_ > file_nb_frames())
191 CASPAR_THROW_EXCEPTION(seek_out_of_range() << msg_info("SEEK out of range"));
193 muxer_.reset(new frame_muxer(fps_, frame_factory, format_desc_, channel_layout, filter));
197 if (is_logging_quiet_for_thread())
198 CASPAR_LOG(debug) << print() << L" Initialized";
200 CASPAR_LOG(info) << print() << L" Initialized";
205 core::draw_frame receive_impl() override
207 auto frame = core::draw_frame::late();
209 caspar::timer frame_timer;
217 last_frame_ = frame = std::move(muxer_->front());
220 else if (!input_.eof())
221 graph_->set_tag(diagnostics::tag_severity::WARNING, "underflow");
223 graph_->set_value("frame-time", frame_timer.elapsed()*format_desc_.fps*0.5);
225 << core::monitor::message("/profiler/time") % frame_timer.elapsed() % (1.0/format_desc_.fps);
227 << core::monitor::message("/file/frame") % static_cast<int32_t>(file_frame_number())
228 % static_cast<int32_t>(file_nb_frames())
229 << core::monitor::message("/file/fps") % fps_
230 << core::monitor::message("/file/path") % path_relative_to_media_
231 << core::monitor::message("/loop") % input_.loop();
236 core::draw_frame render_specific_frame(uint32_t file_position)
239 input_.seek(file_position);
245 CASPAR_LOG(trace) << print() << " Giving up finding frame at " << file_position;
247 return core::draw_frame::empty();
250 auto frame = muxer_->front();
256 core::draw_frame create_thumbnail_frame() override
258 auto quiet_logging = temporary_enable_quiet_logging_for_thread(true);
260 auto total_frames = nb_frames();
261 auto grid = env::properties().get(L"configuration.thumbnails.video-grid", 2);
265 CASPAR_LOG(error) << L"configuration/thumbnails/video-grid cannot be less than 1";
266 BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("configuration/thumbnails/video-grid cannot be less than 1"));
271 return render_specific_frame(total_frames / 2);
274 auto num_snapshots = grid * grid;
276 std::vector<core::draw_frame> frames;
278 for (int i = 0; i < num_snapshots; ++i)
285 desired_frame = 0; // first
286 else if (i == num_snapshots - 1)
287 desired_frame = total_frames - 1; // last
289 // evenly distributed across the file.
290 desired_frame = total_frames * i / (num_snapshots - 1);
292 auto frame = render_specific_frame(desired_frame);
293 frame.transform().image_transform.fill_scale[0] = 1.0 / static_cast<double>(grid);
294 frame.transform().image_transform.fill_scale[1] = 1.0 / static_cast<double>(grid);
295 frame.transform().image_transform.fill_translation[0] = 1.0 / static_cast<double>(grid) * x;
296 frame.transform().image_transform.fill_translation[1] = 1.0 / static_cast<double>(grid) * y;
298 frames.push_back(frame);
301 return core::draw_frame(frames);
304 core::draw_frame last_frame() override
307 return core::draw_frame::still(last_frame_);
310 core::constraints& pixel_constraints() override
315 uint32_t nb_frames() const override
318 return std::numeric_limits<uint32_t>::max();
320 uint32_t nb_frames = file_nb_frames();
322 nb_frames = std::min(input_.length(), nb_frames);
323 nb_frames = muxer_->calc_nb_frames(nb_frames);
325 return nb_frames > start_ ? nb_frames - start_ : 0;
328 uint32_t file_nb_frames() const
330 uint32_t file_nb_frames = 0;
331 file_nb_frames = std::max(file_nb_frames, video_decoder_ ? video_decoder_->nb_frames() : 0);
332 file_nb_frames = std::max(file_nb_frames, audio_decoder_ ? audio_decoder_->nb_frames() : 0);
333 return file_nb_frames;
336 uint32_t file_frame_number() const
338 return video_decoder_ ? video_decoder_->file_frame_number() : 0;
341 std::future<std::wstring> call(const std::vector<std::wstring>& params) override
343 static const boost::wregex loop_exp(LR"(LOOP\s*(?<VALUE>\d?)?)", boost::regex::icase);
344 static const boost::wregex seek_exp(LR"(SEEK\s+(?<VALUE>\d+))", boost::regex::icase);
345 static const boost::wregex length_exp(LR"(LENGTH\s+(?<VALUE>\d+)?)", boost::regex::icase);
346 static const boost::wregex start_exp(LR"(START\\s+(?<VALUE>\\d+)?)", boost::regex::icase);
348 auto param = boost::algorithm::join(params, L" ");
353 if(boost::regex_match(param, what, loop_exp))
355 auto value = what["VALUE"].str();
357 input_.loop(boost::lexical_cast<bool>(value));
358 result = boost::lexical_cast<std::wstring>(loop());
360 else if(boost::regex_match(param, what, seek_exp))
362 auto value = what["VALUE"].str();
363 seek(boost::lexical_cast<uint32_t>(value));
365 else if(boost::regex_match(param, what, length_exp))
367 auto value = what["VALUE"].str();
369 length(boost::lexical_cast<uint32_t>(value));
370 result = boost::lexical_cast<std::wstring>(length());
372 else if(boost::regex_match(param, what, start_exp))
374 auto value = what["VALUE"].str();
376 start(boost::lexical_cast<uint32_t>(value));
377 result = boost::lexical_cast<std::wstring>(start());
380 CASPAR_THROW_EXCEPTION(invalid_argument());
382 return make_ready_future(std::move(result));
385 std::wstring print() const override
387 return L"ffmpeg[" + boost::filesystem::path(filename_).filename().wstring() + L"|"
388 + print_mode() + L"|"
389 + boost::lexical_cast<std::wstring>(file_frame_number()) + L"/" + boost::lexical_cast<std::wstring>(file_nb_frames()) + L"]";
392 std::wstring name() const override
397 boost::property_tree::wptree info() const override
399 boost::property_tree::wptree info;
400 info.add(L"type", L"ffmpeg");
401 info.add(L"filename", filename_);
402 info.add(L"width", video_decoder_ ? video_decoder_->width() : 0);
403 info.add(L"height", video_decoder_ ? video_decoder_->height() : 0);
404 info.add(L"progressive", video_decoder_ ? video_decoder_->is_progressive() : 0);
405 info.add(L"fps", fps_);
406 info.add(L"loop", input_.loop());
407 info.add(L"frame-number", frame_number());
408 auto nb_frames2 = nb_frames();
409 info.add(L"nb-frames", nb_frames2 == std::numeric_limits<int64_t>::max() ? -1 : nb_frames2);
410 info.add(L"file-frame-number", file_frame_number());
411 info.add(L"file-nb-frames", file_nb_frames());
415 core::monitor::subject& monitor_output()
417 return *monitor_subject_;
424 for(int n = 0; n < 8 && (last_frame_ == core::draw_frame::empty() || (seek_target_ && file_frame_number() != *seek_target_+2)); ++n)
429 last_frame_ = muxer_->front();
430 seek_target_.reset();
435 void loop(bool value)
442 return input_.loop();
445 void length(uint32_t value)
447 input_.length(value);
452 return input_.length();
455 void start(uint32_t value)
462 return input_.start();
465 void seek(uint32_t target)
467 if (target > file_nb_frames())
468 CASPAR_THROW_EXCEPTION(seek_out_of_range() << msg_info("SEEK out of range"));
470 seek_target_ = target;
472 input_.seek(*seek_target_);
476 std::wstring print_mode() const
478 return ffmpeg::print_mode(video_decoder_ ? video_decoder_->width() : 0,
479 video_decoder_ ? video_decoder_->height() : 0,
481 video_decoder_ ? !video_decoder_->is_progressive() : false);
484 void decode_next_frame()
486 for(int n = 0; n < 32 && muxer_->empty(); ++n)
488 std::shared_ptr<AVFrame> video;
489 std::shared_ptr<AVFrame> audio;
490 bool needs_video = !muxer_->video_ready();
491 bool needs_audio = !muxer_->audio_ready();
493 tbb::parallel_invoke(
497 video = video_decoder_ ? (*video_decoder_)() : create_frame();
502 audio = audio_decoder_ ? (*audio_decoder_)() : create_frame();
505 muxer_->push_video(video);
506 muxer_->push_audio(audio);
509 graph_->set_text(print());
513 void describe_producer(core::help_sink& sink, const core::help_repository& repo)
515 sink.short_description(L"A producer for playing media files supported by FFmpeg.");
516 sink.syntax(L"[clip:string] {[loop:LOOP]} {START,SEEK [start:int]} {LENGTH [start:int]} {FILTER [filter:string]} {CHANNEL_LAYOUT [channel_layout:string]}");
518 ->text(L"The FFmpeg Producer can play all media that FFmpeg can play, which includes many ")
519 ->text(L"QuickTime video codec such as Animation, PNG, PhotoJPEG, MotionJPEG, as well as ")
520 ->text(L"H.264, FLV, WMV and several audio codecs as well as uncompressed audio.");
522 ->item(L"clip", L"The file without the file extension to play. It should reside under the media folder.")
523 ->item(L"loop", L"Will cause the media file to loop between start and start + length")
524 ->item(L"start", L"Optionally sets the start frame. 0 by default. If loop is specified this will be the frame where it starts over again.")
525 ->item(L"length", L"Optionally sets the length of the clip. If not specified the clip will be played to the end. If loop is specified the file will jump to start position once this number of frames has been played.")
526 ->item(L"filter", L"If specified, will be used as an FFmpeg video filter.")
527 ->item(L"channel_layout",
528 L"Optionally override the automatically deduced audio channel layout. "
529 L"Either a named layout as specified in casparcg.config or in the format [type:string]:[channel_order:string] for a custom layout.");
530 sink.para()->text(L"Examples:");
531 sink.example(L">> PLAY 1-10 folder/clip", L"to play all frames in a clip and stop at the last frame.");
532 sink.example(L">> PLAY 1-10 folder/clip LOOP", L"to loop a clip between the first frame and the last frame.");
533 sink.example(L">> PLAY 1-10 folder/clip LOOP START 10", L"to loop a clip between frame 10 and the last frame.");
534 sink.example(L">> PLAY 1-10 folder/clip LOOP START 10 LENGTH 50", L"to loop a clip between frame 10 and frame 60.");
535 sink.example(L">> PLAY 1-10 folder/clip START 10 LENGTH 50", L"to play frames 10-60 in a clip and stop.");
536 sink.example(L">> PLAY 1-10 folder/clip FILTER yadif=1,-1", L"to deinterlace the video.");
537 sink.example(L">> PLAY 1-10 folder/clip CHANNEL_LAYOUT film", L"given the defaults in casparcg.config this will specifies that the clip has 6 audio channels of the type 5.1 and that they are in the order FL FC FR BL BR LFE regardless of what ffmpeg says.");
538 sink.example(L">> PLAY 1-10 folder/clip CHANNEL_LAYOUT \"5.1:LFE FL FC FR BL BR\"", L"specifies that the clip has 6 audio channels of the type 5.1 and that they are in the specified order regardless of what ffmpeg says.");
539 sink.para()->text(L"The FFmpeg producer also supports changing some of the settings via CALL:");
540 sink.example(L">> CALL 1-10 LOOP 1");
541 sink.example(L">> CALL 1-10 START 10");
542 sink.example(L">> CALL 1-10 LENGTH 50");
545 spl::shared_ptr<core::frame_producer> create_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params)
547 auto filename = probe_stem(env::media_folder() + L"/" + params.at(0), false);
550 return core::frame_producer::empty();
552 bool loop = contains_param(L"LOOP", params);
553 auto start = get_param(L"START", params, get_param(L"SEEK", params, static_cast<uint32_t>(0)));
554 auto length = get_param(L"LENGTH", params, std::numeric_limits<uint32_t>::max());
555 auto filter_str = get_param(L"FILTER", params, L"");
556 auto channel_layout = get_param(L"CHANNEL_LAYOUT", params, L"");
557 bool thumbnail_mode = false;
559 return create_destroy_proxy(spl::make_shared_ptr(std::make_shared<ffmpeg_producer>(
560 dependencies.frame_factory,
561 dependencies.format_desc,
571 spl::shared_ptr<core::frame_producer> create_thumbnail_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params)
573 auto quiet_logging = temporary_enable_quiet_logging_for_thread(true);
574 auto filename = probe_stem(env::media_folder() + L"/" + params.at(0), true);
577 return core::frame_producer::empty();
581 auto length = std::numeric_limits<uint32_t>::max();
582 auto filter_str = L"";
583 auto channel_layout = L"";
584 bool thumbnail_mode = true;
586 return spl::make_shared_ptr(std::make_shared<ffmpeg_producer>(
587 dependencies.frame_factory,
588 dependencies.format_desc,