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 std::wstring get_relative_or_original(
67 const std::wstring& filename,
68 const boost::filesystem::path& relative_to)
70 boost::filesystem::path file(filename);
71 auto result = file.filename().wstring();
73 boost::filesystem::path current_path = file;
77 current_path = current_path.parent_path();
79 if (boost::filesystem::equivalent(current_path, relative_to))
82 if (current_path.empty())
85 result = current_path.filename().wstring() + L"/" + result;
91 struct ffmpeg_producer : public core::frame_producer_base
93 spl::shared_ptr<core::monitor::subject> monitor_subject_;
94 const std::wstring filename_;
95 const std::wstring path_relative_to_media_ = get_relative_or_original(filename_, env::media_folder());
97 const spl::shared_ptr<diagnostics::graph> graph_;
99 const spl::shared_ptr<core::frame_factory> frame_factory_;
100 const core::video_format_desc format_desc_;
104 const double fps_ = read_fps(input_.context(), format_desc_.fps);
105 const uint32_t start_;
107 std::unique_ptr<video_decoder> video_decoder_;
108 std::unique_ptr<audio_decoder> audio_decoder_;
109 std::unique_ptr<frame_muxer> muxer_;
110 core::constraints constraints_;
112 core::draw_frame last_frame_ = core::draw_frame::empty();
114 boost::optional<uint32_t> seek_target_;
117 explicit ffmpeg_producer(
118 const spl::shared_ptr<core::frame_factory>& frame_factory,
119 const core::video_format_desc& format_desc,
120 const std::wstring& channel_layout_spec,
121 const std::wstring& filename,
122 const std::wstring& filter,
126 : filename_(filename)
127 , frame_factory_(frame_factory)
128 , format_desc_(format_desc)
129 , input_(graph_, filename_, loop, start, length)
130 , fps_(read_fps(input_.context(), format_desc_.fps))
133 graph_->set_color("frame-time", diagnostics::color(0.1f, 1.0f, 0.1f));
134 graph_->set_color("underflow", diagnostics::color(0.6f, 0.3f, 0.9f));
135 diagnostics::register_graph(graph_);
140 video_decoder_.reset(new video_decoder(input_));
141 video_decoder_->monitor_output().attach_parent(monitor_subject_);
142 constraints_.width.set(video_decoder_->width());
143 constraints_.height.set(video_decoder_->height());
145 CASPAR_LOG(info) << print() << L" " << video_decoder_->print();
147 catch(averror_stream_not_found&)
149 //CASPAR_LOG(warning) << print() << " No video-stream found. Running without video.";
153 CASPAR_LOG_CURRENT_EXCEPTION();
154 CASPAR_LOG(warning) << print() << "Failed to open video-stream. Running without video.";
157 auto channel_layout = core::audio_channel_layout::invalid();
161 audio_decoder_ .reset(new audio_decoder(input_, format_desc_, channel_layout_spec));
162 audio_decoder_->monitor_output().attach_parent(monitor_subject_);
164 channel_layout = audio_decoder_->channel_layout();
166 CASPAR_LOG(info) << print() << L" " << audio_decoder_->print();
168 catch(averror_stream_not_found&)
170 //CASPAR_LOG(warning) << print() << " No audio-stream found. Running without audio.";
174 CASPAR_LOG_CURRENT_EXCEPTION();
175 CASPAR_LOG(warning) << print() << " Failed to open audio-stream. Running without audio.";
178 muxer_.reset(new frame_muxer(fps_, frame_factory, format_desc_, channel_layout, filter));
182 CASPAR_LOG(info) << print() << L" Initialized";
187 core::draw_frame receive_impl() override
189 auto frame = core::draw_frame::late();
191 caspar::timer frame_timer;
199 last_frame_ = frame = std::move(muxer_->front());
203 graph_->set_tag("underflow");
205 graph_->set_value("frame-time", frame_timer.elapsed()*format_desc_.fps*0.5);
207 << core::monitor::message("/profiler/time") % frame_timer.elapsed() % (1.0/format_desc_.fps);
209 << core::monitor::message("/file/frame") % static_cast<int32_t>(file_frame_number())
210 % static_cast<int32_t>(file_nb_frames())
211 << core::monitor::message("/file/fps") % fps_
212 << core::monitor::message("/file/path") % path_relative_to_media_
213 << core::monitor::message("/loop") % input_.loop();
218 core::draw_frame last_frame() override
221 return core::draw_frame::still(last_frame_);
224 core::constraints& pixel_constraints() override
229 uint32_t nb_frames() const override
232 return std::numeric_limits<uint32_t>::max();
234 uint32_t nb_frames = file_nb_frames();
236 nb_frames = std::min(input_.length(), nb_frames);
237 nb_frames = muxer_->calc_nb_frames(nb_frames);
239 return nb_frames > start_ ? nb_frames - start_ : 0;
242 uint32_t file_nb_frames() const
244 uint32_t file_nb_frames = 0;
245 file_nb_frames = std::max(file_nb_frames, video_decoder_ ? video_decoder_->nb_frames() : 0);
246 file_nb_frames = std::max(file_nb_frames, audio_decoder_ ? audio_decoder_->nb_frames() : 0);
247 return file_nb_frames;
250 uint32_t file_frame_number() const
252 return video_decoder_ ? video_decoder_->file_frame_number() : 0;
255 std::future<std::wstring> call(const std::vector<std::wstring>& params) override
257 static const boost::wregex loop_exp(LR"(LOOP\s*(?<VALUE>\d?)?)", boost::regex::icase);
258 static const boost::wregex seek_exp(LR"(SEEK\s+(?<VALUE>\d+))", boost::regex::icase);
259 static const boost::wregex length_exp(LR"(LENGTH\s+(?<VALUE>\d+)?)", boost::regex::icase);
260 static const boost::wregex start_exp(LR"(START\\s+(?<VALUE>\\d+)?)", boost::regex::icase);
262 auto param = boost::algorithm::join(params, L" ");
267 if(boost::regex_match(param, what, loop_exp))
269 auto value = what["VALUE"].str();
271 input_.loop(boost::lexical_cast<bool>(value));
272 result = boost::lexical_cast<std::wstring>(loop());
274 else if(boost::regex_match(param, what, seek_exp))
276 auto value = what["VALUE"].str();
277 seek(boost::lexical_cast<uint32_t>(value));
279 else if(boost::regex_match(param, what, length_exp))
281 auto value = what["VALUE"].str();
283 length(boost::lexical_cast<uint32_t>(value));
284 result = boost::lexical_cast<std::wstring>(length());
286 else if(boost::regex_match(param, what, start_exp))
288 auto value = what["VALUE"].str();
290 start(boost::lexical_cast<uint32_t>(value));
291 result = boost::lexical_cast<std::wstring>(start());
294 CASPAR_THROW_EXCEPTION(invalid_argument());
296 return make_ready_future(std::move(result));
299 std::wstring print() const override
301 return L"ffmpeg[" + boost::filesystem::path(filename_).filename().wstring() + L"|"
302 + print_mode() + L"|"
303 + boost::lexical_cast<std::wstring>(file_frame_number()) + L"/" + boost::lexical_cast<std::wstring>(file_nb_frames()) + L"]";
306 std::wstring name() const override
311 boost::property_tree::wptree info() const override
313 boost::property_tree::wptree info;
314 info.add(L"type", L"ffmpeg");
315 info.add(L"filename", filename_);
316 info.add(L"width", video_decoder_ ? video_decoder_->width() : 0);
317 info.add(L"height", video_decoder_ ? video_decoder_->height() : 0);
318 info.add(L"progressive", video_decoder_ ? video_decoder_->is_progressive() : 0);
319 info.add(L"fps", fps_);
320 info.add(L"loop", input_.loop());
321 info.add(L"frame-number", frame_number());
322 auto nb_frames2 = nb_frames();
323 info.add(L"nb-frames", nb_frames2 == std::numeric_limits<int64_t>::max() ? -1 : nb_frames2);
324 info.add(L"file-frame-number", file_frame_number());
325 info.add(L"file-nb-frames", file_nb_frames());
329 core::monitor::subject& monitor_output()
331 return *monitor_subject_;
338 for(int n = 0; n < 8 && (last_frame_ == core::draw_frame::empty() || (seek_target_ && file_frame_number() != *seek_target_+2)); ++n)
343 last_frame_ = muxer_->front();
344 seek_target_.reset();
349 void loop(bool value)
356 return input_.loop();
359 void length(uint32_t value)
361 input_.length(value);
366 return input_.length();
369 void start(uint32_t value)
376 return input_.start();
379 void seek(uint32_t target)
381 seek_target_ = std::min(target, file_nb_frames());
383 input_.seek(*seek_target_);
387 std::wstring print_mode() const
389 return ffmpeg::print_mode(video_decoder_ ? video_decoder_->width() : 0,
390 video_decoder_ ? video_decoder_->height() : 0,
392 video_decoder_ ? !video_decoder_->is_progressive() : false);
395 void decode_next_frame()
397 for(int n = 0; n < 32 && muxer_->empty(); ++n)
399 if(!muxer_->video_ready())
400 muxer_->push_video(video_decoder_ ? (*video_decoder_)() : create_frame());
401 if(!muxer_->audio_ready())
402 muxer_->push_audio(audio_decoder_ ? (*audio_decoder_)() : create_frame());
405 graph_->set_text(print());
409 void describe_producer(core::help_sink& sink, const core::help_repository& repo)
411 sink.short_description(L"A producer for playing media files supported by FFmpeg.");
412 sink.syntax(L"[clip:string] {[loop:LOOP]} {START,SEEK [start:int]} {LENGTH [start:int]} {FILTER [filter:string]} {CHANNEL_LAYOUT [channel_layout:string]}");
414 ->text(L"The FFmpeg Producer can play all media that FFmpeg can play, which includes many ")
415 ->text(L"QuickTime video codec such as Animation, PNG, PhotoJPEG, MotionJPEG, as well as ")
416 ->text(L"H.264, FLV, WMV and several audio codecs as well as uncompressed audio.");
418 ->item(L"clip", L"The file without the file extension to play. It should reside under the media folder.")
419 ->item(L"loop", L"Will cause the media file to loop between start and start + length")
420 ->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.")
421 ->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.")
422 ->item(L"filter", L"If specified, will be used as an FFmpeg video filter.")
423 ->item(L"channel_layout",
424 L"Optionally override the automatically deduced audio channel layout. "
425 L"Either a named layout as specified in casparcg.config or in the format [type:string]:[channel_order:string] for a custom layout.");
426 sink.para()->text(L"Examples:");
427 sink.example(L">> PLAY 1-10 folder/clip", L"to play all frames in a clip and stop at the last frame.");
428 sink.example(L">> PLAY 1-10 folder/clip LOOP", L"to loop a clip between the first frame and the last frame.");
429 sink.example(L">> PLAY 1-10 folder/clip LOOP START 10", L"to loop a clip between frame 10 and the last frame.");
430 sink.example(L">> PLAY 1-10 folder/clip LOOP START 10 LENGTH 50", L"to loop a clip between frame 10 and frame 60.");
431 sink.example(L">> PLAY 1-10 folder/clip START 10 LENGTH 50", L"to play frames 10-60 in a clip and stop.");
432 sink.example(L">> PLAY 1-10 folder/clip FILTER yadif=1,-1", L"to deinterlace the video.");
433 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.");
434 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.");
435 sink.para()->text(L"The FFmpeg producer also supports changing some of the settings via CALL:");
436 sink.example(L">> CALL 1-10 LOOP 1");
437 sink.example(L">> CALL 1-10 START 10");
438 sink.example(L">> CALL 1-10 LENGTH 50");
441 spl::shared_ptr<core::frame_producer> create_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params)
443 auto filename = probe_stem(env::media_folder() + L"/" + params.at(0));
446 return core::frame_producer::empty();
448 bool loop = contains_param(L"LOOP", params);
449 auto start = get_param(L"START", params, get_param(L"SEEK", params, static_cast<uint32_t>(0)));
450 auto length = get_param(L"LENGTH", params, std::numeric_limits<uint32_t>::max());
451 auto filter_str = get_param(L"FILTER", params, L"");
452 auto channel_layout = get_param(L"CHANNEL_LAYOUT", params, L"");
454 return create_destroy_proxy(spl::make_shared_ptr(std::make_shared<ffmpeg_producer>(
455 dependencies.frame_factory,
456 dependencies.format_desc,