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"
28 #include "muxer/frame_muxer.h"
29 #include "input/input.h"
30 #include "util/util.h"
31 #include "audio/audio_decoder.h"
32 #include "video/video_decoder.h"
34 #include <common/env.h>
35 #include <common/log.h>
36 #include <common/param.h>
37 #include <common/diagnostics/graph.h>
38 #include <common/future.h>
39 #include <common/timer.h>
40 #include <common/assert.h>
42 #include <core/video_format.h>
43 #include <core/producer/frame_producer.h>
44 #include <core/frame/audio_channel_layout.h>
45 #include <core/frame/frame_factory.h>
46 #include <core/frame/draw_frame.h>
47 #include <core/frame/frame_transform.h>
48 #include <core/monitor/monitor.h>
49 #include <core/help/help_repository.h>
50 #include <core/help/help_sink.h>
52 #include <boost/algorithm/string.hpp>
53 #include <boost/filesystem.hpp>
54 #include <boost/property_tree/ptree.hpp>
55 #include <boost/regex.hpp>
56 #include <boost/thread/future.hpp>
58 #include <tbb/parallel_invoke.h>
64 namespace caspar { namespace ffmpeg {
66 struct seek_out_of_range : virtual user_error {};
68 std::wstring get_relative_or_original(
69 const std::wstring& filename,
70 const boost::filesystem::path& relative_to)
72 boost::filesystem::path file(filename);
73 auto result = file.filename().wstring();
75 boost::filesystem::path current_path = file;
79 current_path = current_path.parent_path();
81 if (boost::filesystem::equivalent(current_path, relative_to))
84 if (current_path.empty())
87 result = current_path.filename().wstring() + L"/" + result;
93 struct ffmpeg_producer : public core::frame_producer_base
95 spl::shared_ptr<core::monitor::subject> monitor_subject_;
96 const std::wstring filename_;
97 const std::wstring path_relative_to_media_ = get_relative_or_original(filename_, env::media_folder());
99 const spl::shared_ptr<diagnostics::graph> graph_;
101 const spl::shared_ptr<core::frame_factory> frame_factory_;
102 const core::video_format_desc format_desc_;
106 const double fps_ = read_fps(input_.context(), format_desc_.fps);
107 const uint32_t start_;
109 std::unique_ptr<video_decoder> video_decoder_;
110 std::unique_ptr<audio_decoder> audio_decoder_;
111 std::unique_ptr<frame_muxer> muxer_;
112 core::constraints constraints_;
114 core::draw_frame last_frame_ = core::draw_frame::empty();
116 boost::optional<uint32_t> seek_target_;
119 explicit ffmpeg_producer(
120 const spl::shared_ptr<core::frame_factory>& frame_factory,
121 const core::video_format_desc& format_desc,
122 const std::wstring& channel_layout_spec,
123 const std::wstring& filename,
124 const std::wstring& filter,
128 : filename_(filename)
129 , frame_factory_(frame_factory)
130 , format_desc_(format_desc)
131 , input_(graph_, filename_, loop, start, length)
132 , fps_(read_fps(input_.context(), format_desc_.fps))
135 graph_->set_color("frame-time", diagnostics::color(0.1f, 1.0f, 0.1f));
136 graph_->set_color("underflow", diagnostics::color(0.6f, 0.3f, 0.9f));
137 diagnostics::register_graph(graph_);
142 video_decoder_.reset(new video_decoder(input_));
143 video_decoder_->monitor_output().attach_parent(monitor_subject_);
144 constraints_.width.set(video_decoder_->width());
145 constraints_.height.set(video_decoder_->height());
147 CASPAR_LOG(info) << print() << L" " << video_decoder_->print();
149 catch(averror_stream_not_found&)
151 //CASPAR_LOG(warning) << print() << " No video-stream found. Running without video.";
155 CASPAR_LOG_CURRENT_EXCEPTION();
156 CASPAR_LOG(warning) << print() << "Failed to open video-stream. Running without video.";
159 auto channel_layout = core::audio_channel_layout::invalid();
163 audio_decoder_ .reset(new audio_decoder(input_, format_desc_, channel_layout_spec));
164 audio_decoder_->monitor_output().attach_parent(monitor_subject_);
166 channel_layout = audio_decoder_->channel_layout();
168 CASPAR_LOG(info) << print() << L" " << audio_decoder_->print();
170 catch(averror_stream_not_found&)
172 //CASPAR_LOG(warning) << print() << " No audio-stream found. Running without audio.";
176 CASPAR_LOG_CURRENT_EXCEPTION();
177 CASPAR_LOG(warning) << print() << " Failed to open audio-stream. Running without audio.";
180 if (start_ > file_nb_frames())
181 CASPAR_THROW_EXCEPTION(seek_out_of_range() << msg_info("SEEK out of range"));
183 muxer_.reset(new frame_muxer(fps_, frame_factory, format_desc_, channel_layout, filter));
187 CASPAR_LOG(info) << print() << L" Initialized";
192 core::draw_frame receive_impl() override
194 auto frame = core::draw_frame::late();
196 caspar::timer frame_timer;
204 last_frame_ = frame = std::move(muxer_->front());
207 else if (!input_.eof())
208 graph_->set_tag(diagnostics::tag_severity::WARNING, "underflow");
210 graph_->set_value("frame-time", frame_timer.elapsed()*format_desc_.fps*0.5);
212 << core::monitor::message("/profiler/time") % frame_timer.elapsed() % (1.0/format_desc_.fps);
214 << core::monitor::message("/file/frame") % static_cast<int32_t>(file_frame_number())
215 % static_cast<int32_t>(file_nb_frames())
216 << core::monitor::message("/file/fps") % fps_
217 << core::monitor::message("/file/path") % path_relative_to_media_
218 << core::monitor::message("/loop") % input_.loop();
223 core::draw_frame last_frame() override
226 return core::draw_frame::still(last_frame_);
229 core::constraints& pixel_constraints() override
234 uint32_t nb_frames() const override
237 return std::numeric_limits<uint32_t>::max();
239 uint32_t nb_frames = file_nb_frames();
241 nb_frames = std::min(input_.length(), nb_frames);
242 nb_frames = muxer_->calc_nb_frames(nb_frames);
244 return nb_frames > start_ ? nb_frames - start_ : 0;
247 uint32_t file_nb_frames() const
249 uint32_t file_nb_frames = 0;
250 file_nb_frames = std::max(file_nb_frames, video_decoder_ ? video_decoder_->nb_frames() : 0);
251 file_nb_frames = std::max(file_nb_frames, audio_decoder_ ? audio_decoder_->nb_frames() : 0);
252 return file_nb_frames;
255 uint32_t file_frame_number() const
257 return video_decoder_ ? video_decoder_->file_frame_number() : 0;
260 std::future<std::wstring> call(const std::vector<std::wstring>& params) override
262 static const boost::wregex loop_exp(LR"(LOOP\s*(?<VALUE>\d?)?)", boost::regex::icase);
263 static const boost::wregex seek_exp(LR"(SEEK\s+(?<VALUE>\d+))", boost::regex::icase);
264 static const boost::wregex length_exp(LR"(LENGTH\s+(?<VALUE>\d+)?)", boost::regex::icase);
265 static const boost::wregex start_exp(LR"(START\\s+(?<VALUE>\\d+)?)", boost::regex::icase);
267 auto param = boost::algorithm::join(params, L" ");
272 if(boost::regex_match(param, what, loop_exp))
274 auto value = what["VALUE"].str();
276 input_.loop(boost::lexical_cast<bool>(value));
277 result = boost::lexical_cast<std::wstring>(loop());
279 else if(boost::regex_match(param, what, seek_exp))
281 auto value = what["VALUE"].str();
282 seek(boost::lexical_cast<uint32_t>(value));
284 else if(boost::regex_match(param, what, length_exp))
286 auto value = what["VALUE"].str();
288 length(boost::lexical_cast<uint32_t>(value));
289 result = boost::lexical_cast<std::wstring>(length());
291 else if(boost::regex_match(param, what, start_exp))
293 auto value = what["VALUE"].str();
295 start(boost::lexical_cast<uint32_t>(value));
296 result = boost::lexical_cast<std::wstring>(start());
299 CASPAR_THROW_EXCEPTION(invalid_argument());
301 return make_ready_future(std::move(result));
304 std::wstring print() const override
306 return L"ffmpeg[" + boost::filesystem::path(filename_).filename().wstring() + L"|"
307 + print_mode() + L"|"
308 + boost::lexical_cast<std::wstring>(file_frame_number()) + L"/" + boost::lexical_cast<std::wstring>(file_nb_frames()) + L"]";
311 std::wstring name() const override
316 boost::property_tree::wptree info() const override
318 boost::property_tree::wptree info;
319 info.add(L"type", L"ffmpeg");
320 info.add(L"filename", filename_);
321 info.add(L"width", video_decoder_ ? video_decoder_->width() : 0);
322 info.add(L"height", video_decoder_ ? video_decoder_->height() : 0);
323 info.add(L"progressive", video_decoder_ ? video_decoder_->is_progressive() : 0);
324 info.add(L"fps", fps_);
325 info.add(L"loop", input_.loop());
326 info.add(L"frame-number", frame_number());
327 auto nb_frames2 = nb_frames();
328 info.add(L"nb-frames", nb_frames2 == std::numeric_limits<int64_t>::max() ? -1 : nb_frames2);
329 info.add(L"file-frame-number", file_frame_number());
330 info.add(L"file-nb-frames", file_nb_frames());
334 core::monitor::subject& monitor_output()
336 return *monitor_subject_;
343 for(int n = 0; n < 8 && (last_frame_ == core::draw_frame::empty() || (seek_target_ && file_frame_number() != *seek_target_+2)); ++n)
348 last_frame_ = muxer_->front();
349 seek_target_.reset();
354 void loop(bool value)
361 return input_.loop();
364 void length(uint32_t value)
366 input_.length(value);
371 return input_.length();
374 void start(uint32_t value)
381 return input_.start();
384 void seek(uint32_t target)
386 if (target > file_nb_frames())
387 CASPAR_THROW_EXCEPTION(seek_out_of_range() << msg_info("SEEK out of range"));
389 seek_target_ = target;
391 input_.seek(*seek_target_);
395 std::wstring print_mode() const
397 return ffmpeg::print_mode(video_decoder_ ? video_decoder_->width() : 0,
398 video_decoder_ ? video_decoder_->height() : 0,
400 video_decoder_ ? !video_decoder_->is_progressive() : false);
403 void decode_next_frame()
405 for(int n = 0; n < 32 && muxer_->empty(); ++n)
407 if(!muxer_->video_ready())
408 muxer_->push_video(video_decoder_ ? (*video_decoder_)() : create_frame());
409 if(!muxer_->audio_ready())
410 muxer_->push_audio(audio_decoder_ ? (*audio_decoder_)() : create_frame());
413 graph_->set_text(print());
417 void describe_producer(core::help_sink& sink, const core::help_repository& repo)
419 sink.short_description(L"A producer for playing media files supported by FFmpeg.");
420 sink.syntax(L"[clip:string] {[loop:LOOP]} {START,SEEK [start:int]} {LENGTH [start:int]} {FILTER [filter:string]} {CHANNEL_LAYOUT [channel_layout:string]}");
422 ->text(L"The FFmpeg Producer can play all media that FFmpeg can play, which includes many ")
423 ->text(L"QuickTime video codec such as Animation, PNG, PhotoJPEG, MotionJPEG, as well as ")
424 ->text(L"H.264, FLV, WMV and several audio codecs as well as uncompressed audio.");
426 ->item(L"clip", L"The file without the file extension to play. It should reside under the media folder.")
427 ->item(L"loop", L"Will cause the media file to loop between start and start + length")
428 ->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.")
429 ->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.")
430 ->item(L"filter", L"If specified, will be used as an FFmpeg video filter.")
431 ->item(L"channel_layout",
432 L"Optionally override the automatically deduced audio channel layout. "
433 L"Either a named layout as specified in casparcg.config or in the format [type:string]:[channel_order:string] for a custom layout.");
434 sink.para()->text(L"Examples:");
435 sink.example(L">> PLAY 1-10 folder/clip", L"to play all frames in a clip and stop at the last frame.");
436 sink.example(L">> PLAY 1-10 folder/clip LOOP", L"to loop a clip between the first frame and the last frame.");
437 sink.example(L">> PLAY 1-10 folder/clip LOOP START 10", L"to loop a clip between frame 10 and the last frame.");
438 sink.example(L">> PLAY 1-10 folder/clip LOOP START 10 LENGTH 50", L"to loop a clip between frame 10 and frame 60.");
439 sink.example(L">> PLAY 1-10 folder/clip START 10 LENGTH 50", L"to play frames 10-60 in a clip and stop.");
440 sink.example(L">> PLAY 1-10 folder/clip FILTER yadif=1,-1", L"to deinterlace the video.");
441 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.");
442 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.");
443 sink.para()->text(L"The FFmpeg producer also supports changing some of the settings via CALL:");
444 sink.example(L">> CALL 1-10 LOOP 1");
445 sink.example(L">> CALL 1-10 START 10");
446 sink.example(L">> CALL 1-10 LENGTH 50");
449 spl::shared_ptr<core::frame_producer> create_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params)
451 auto filename = probe_stem(env::media_folder() + L"/" + params.at(0));
454 return core::frame_producer::empty();
456 bool loop = contains_param(L"LOOP", params);
457 auto start = get_param(L"START", params, get_param(L"SEEK", params, static_cast<uint32_t>(0)));
458 auto length = get_param(L"LENGTH", params, std::numeric_limits<uint32_t>::max());
459 auto filter_str = get_param(L"FILTER", params, L"");
460 auto channel_layout = get_param(L"CHANNEL_LAYOUT", params, L"");
462 return create_destroy_proxy(spl::make_shared_ptr(std::make_shared<ffmpeg_producer>(
463 dependencies.frame_factory,
464 dependencies.format_desc,