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/frame_factory.h>
45 #include <core/frame/draw_frame.h>
46 #include <core/frame/frame_transform.h>
47 #include <core/monitor/monitor.h>
48 #include <core/help/help_repository.h>
49 #include <core/help/help_sink.h>
51 #include <boost/algorithm/string.hpp>
52 #include <boost/filesystem.hpp>
53 #include <boost/property_tree/ptree.hpp>
54 #include <boost/regex.hpp>
55 #include <boost/thread/future.hpp>
57 #include <tbb/parallel_invoke.h>
63 namespace caspar { namespace ffmpeg {
65 std::wstring get_relative_or_original(
66 const std::wstring& filename,
67 const boost::filesystem::path& relative_to)
69 boost::filesystem::path file(filename);
70 auto result = file.filename().wstring();
72 boost::filesystem::path current_path = file;
76 current_path = current_path.parent_path();
78 if (boost::filesystem::equivalent(current_path, relative_to))
81 if (current_path.empty())
84 result = current_path.filename().wstring() + L"/" + result;
90 struct ffmpeg_producer : public core::frame_producer_base
92 spl::shared_ptr<core::monitor::subject> monitor_subject_;
93 const std::wstring filename_;
94 const std::wstring path_relative_to_media_ = get_relative_or_original(filename_, env::media_folder());
96 const spl::shared_ptr<diagnostics::graph> graph_;
98 const spl::shared_ptr<core::frame_factory> frame_factory_;
99 const core::video_format_desc format_desc_;
103 const double fps_ = read_fps(input_.context(), format_desc_.fps);
104 const uint32_t start_;
106 std::unique_ptr<video_decoder> video_decoder_;
107 std::unique_ptr<audio_decoder> audio_decoder_;
109 core::constraints constraints_;
111 core::draw_frame last_frame_ = core::draw_frame::empty();
113 boost::optional<uint32_t> seek_target_;
116 explicit ffmpeg_producer(const spl::shared_ptr<core::frame_factory>& frame_factory,
117 const core::video_format_desc& format_desc,
118 const std::wstring& filename,
119 const std::wstring& filter,
123 : filename_(filename)
124 , frame_factory_(frame_factory)
125 , format_desc_(format_desc)
126 , input_(graph_, filename_, loop, start, length)
127 , fps_(read_fps(input_.context(), format_desc_.fps))
128 , muxer_(fps_, frame_factory, format_desc_, filter)
131 graph_->set_color("frame-time", diagnostics::color(0.1f, 1.0f, 0.1f));
132 graph_->set_color("underflow", diagnostics::color(0.6f, 0.3f, 0.9f));
133 diagnostics::register_graph(graph_);
138 video_decoder_.reset(new video_decoder(input_));
139 video_decoder_->monitor_output().attach_parent(monitor_subject_);
140 constraints_.width.set(video_decoder_->width());
141 constraints_.height.set(video_decoder_->height());
143 CASPAR_LOG(info) << print() << L" " << video_decoder_->print();
145 catch(averror_stream_not_found&)
147 //CASPAR_LOG(warning) << print() << " No video-stream found. Running without video.";
151 CASPAR_LOG_CURRENT_EXCEPTION();
152 CASPAR_LOG(warning) << print() << "Failed to open video-stream. Running without video.";
157 audio_decoder_ .reset(new audio_decoder(input_, format_desc_));
158 audio_decoder_->monitor_output().attach_parent(monitor_subject_);
160 CASPAR_LOG(info) << print() << L" " << audio_decoder_->print();
162 catch(averror_stream_not_found&)
164 //CASPAR_LOG(warning) << print() << " No audio-stream found. Running without audio.";
168 CASPAR_LOG_CURRENT_EXCEPTION();
169 CASPAR_LOG(warning) << print() << " Failed to open audio-stream. Running without audio.";
174 CASPAR_LOG(info) << print() << L" Initialized";
179 core::draw_frame receive_impl() override
181 auto frame = core::draw_frame::late();
183 caspar::timer frame_timer;
191 last_frame_ = frame = std::move(muxer_.front());
195 graph_->set_tag("underflow");
197 graph_->set_value("frame-time", frame_timer.elapsed()*format_desc_.fps*0.5);
199 << core::monitor::message("/profiler/time") % frame_timer.elapsed() % (1.0/format_desc_.fps);
201 << core::monitor::message("/file/time") % (file_frame_number()/fps_)
202 % (file_nb_frames()/fps_)
203 << core::monitor::message("/file/frame") % static_cast<int32_t>(file_frame_number())
204 % static_cast<int32_t>(file_nb_frames())
205 << core::monitor::message("/file/fps") % fps_
206 << core::monitor::message("/file/path") % path_relative_to_media_
207 << core::monitor::message("/loop") % input_.loop();
212 core::draw_frame last_frame() override
215 return core::draw_frame::still(last_frame_);
218 core::constraints& pixel_constraints() override
223 uint32_t nb_frames() const override
226 return std::numeric_limits<uint32_t>::max();
228 uint32_t nb_frames = file_nb_frames();
230 nb_frames = std::min(input_.length(), nb_frames);
231 nb_frames = muxer_.calc_nb_frames(nb_frames);
233 return nb_frames > start_ ? nb_frames - start_ : 0;
236 uint32_t file_nb_frames() const
238 uint32_t file_nb_frames = 0;
239 file_nb_frames = std::max(file_nb_frames, video_decoder_ ? video_decoder_->nb_frames() : 0);
240 file_nb_frames = std::max(file_nb_frames, audio_decoder_ ? audio_decoder_->nb_frames() : 0);
241 return file_nb_frames;
244 uint32_t file_frame_number() const
246 return video_decoder_ ? video_decoder_->file_frame_number() : 0;
249 std::future<std::wstring> call(const std::vector<std::wstring>& params) override
251 static const boost::wregex loop_exp(LR"(LOOP\s*(?<VALUE>\d?)?)", boost::regex::icase);
252 static const boost::wregex seek_exp(LR"(SEEK\s+(?<VALUE>\d+))", boost::regex::icase);
253 static const boost::wregex length_exp(LR"(LENGTH\s+(?<VALUE>\d+)?)", boost::regex::icase);
254 static const boost::wregex start_exp(LR"(START\\s+(?<VALUE>\\d+)?)", boost::regex::icase);
256 auto param = boost::algorithm::join(params, L" ");
261 if(boost::regex_match(param, what, loop_exp))
263 auto value = what["VALUE"].str();
265 input_.loop(boost::lexical_cast<bool>(value));
266 result = boost::lexical_cast<std::wstring>(loop());
268 else if(boost::regex_match(param, what, seek_exp))
270 auto value = what["VALUE"].str();
271 seek(boost::lexical_cast<uint32_t>(value));
273 else if(boost::regex_match(param, what, length_exp))
275 auto value = what["VALUE"].str();
277 length(boost::lexical_cast<uint32_t>(value));
278 result = boost::lexical_cast<std::wstring>(length());
280 else if(boost::regex_match(param, what, start_exp))
282 auto value = what["VALUE"].str();
284 start(boost::lexical_cast<uint32_t>(value));
285 result = boost::lexical_cast<std::wstring>(start());
288 CASPAR_THROW_EXCEPTION(invalid_argument());
290 return make_ready_future(std::move(result));
293 std::wstring print() const override
295 return L"ffmpeg[" + boost::filesystem::path(filename_).filename().wstring() + L"|"
296 + print_mode() + L"|"
297 + boost::lexical_cast<std::wstring>(file_frame_number()) + L"/" + boost::lexical_cast<std::wstring>(file_nb_frames()) + L"]";
300 std::wstring name() const override
305 boost::property_tree::wptree info() const override
307 boost::property_tree::wptree info;
308 info.add(L"type", L"ffmpeg");
309 info.add(L"filename", filename_);
310 info.add(L"width", video_decoder_ ? video_decoder_->width() : 0);
311 info.add(L"height", video_decoder_ ? video_decoder_->height() : 0);
312 info.add(L"progressive", video_decoder_ ? video_decoder_->is_progressive() : 0);
313 info.add(L"fps", fps_);
314 info.add(L"loop", input_.loop());
315 info.add(L"frame-number", frame_number());
316 auto nb_frames2 = nb_frames();
317 info.add(L"nb-frames", nb_frames2 == std::numeric_limits<int64_t>::max() ? -1 : nb_frames2);
318 info.add(L"file-frame-number", file_frame_number());
319 info.add(L"file-nb-frames", file_nb_frames());
323 core::monitor::subject& monitor_output()
325 return *monitor_subject_;
332 for(int n = 0; n < 8 && (last_frame_ == core::draw_frame::empty() || (seek_target_ && file_frame_number() != *seek_target_+2)); ++n)
337 last_frame_ = muxer_.front();
338 seek_target_.reset();
343 void loop(bool value)
350 return input_.loop();
353 void length(uint32_t value)
355 input_.length(value);
360 return input_.length();
363 void start(uint32_t value)
370 return input_.start();
373 void seek(uint32_t target)
375 seek_target_ = std::min(target, file_nb_frames());
377 input_.seek(*seek_target_);
381 std::wstring print_mode() const
383 return ffmpeg::print_mode(video_decoder_ ? video_decoder_->width() : 0,
384 video_decoder_ ? video_decoder_->height() : 0,
386 video_decoder_ ? !video_decoder_->is_progressive() : false);
389 void decode_next_frame()
391 for(int n = 0; n < 8 && muxer_.empty(); ++n)
393 if(!muxer_.video_ready())
394 muxer_.push_video(video_decoder_ ? (*video_decoder_)() : create_frame());
395 if(!muxer_.audio_ready())
396 muxer_.push_audio(audio_decoder_ ? (*audio_decoder_)() : create_frame());
398 graph_->set_text(print());
402 void describe_producer(core::help_sink& sink, const core::help_repository& repo)
404 sink.short_description(L"A producer for playing media files supported by FFmpeg.");
405 sink.syntax(L"[clip:string] {[loop:LOOP]} {START,SEEK [start:int]} {LENGTH [start:int]} {FILTER [filter:string]}");
407 ->text(L"The FFmpeg Producer can play all media that FFmpeg can play, which includes many ")
408 ->text(L"QuickTime video codec such as Animation, PNG, PhotoJPEG, MotionJPEG, as well as ")
409 ->text(L"H.264, FLV, WMV and several audio codecs as well as uncompressed audio.");
411 ->item(L"clip", L"The file without the file extension to play. It should reside under the media folder.")
412 ->item(L"loop", L"Will cause the media file to loop between start and start + length")
413 ->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.")
414 ->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.")
415 ->item(L"filter", L"If specified, will be used as an FFmpeg video filter.");
416 sink.para()->text(L"Examples:");
417 sink.example(L">> PLAY 1-10 folder/clip", L"to play all frames in a clip and stop at the last frame.");
418 sink.example(L">> PLAY 1-10 folder/clip LOOP", L"to loop a clip between the first frame and the last frame.");
419 sink.example(L">> PLAY 1-10 folder/clip LOOP START 10", L"to loop a clip between frame 10 and the last frame.");
420 sink.example(L">> PLAY 1-10 folder/clip LOOP START 10 LENGTH 50", L"to loop a clip between frame 10 and frame 60.");
421 sink.example(L">> PLAY 1-10 folder/clip START 10 LENGTH 50", L"to play frames 10-60 in a clip and stop.");
422 sink.example(L">> PLAY 1-10 folder/clip FILTER yadif=1,-1", L"to deinterlace the video.");
423 sink.para()->text(L"The FFmpeg producer also supports changing some of the settings via CALL:");
424 sink.example(L">> CALL 1-10 LOOP 1");
425 sink.example(L">> CALL 1-10 START 10");
426 sink.example(L">> CALL 1-10 LENGTH 50");
429 spl::shared_ptr<core::frame_producer> create_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params)
431 auto filename = probe_stem(env::media_folder() + L"/" + params.at(0));
434 return core::frame_producer::empty();
436 bool loop = contains_param(L"LOOP", params);
437 auto start = get_param(L"START", params, get_param(L"SEEK", params, static_cast<uint32_t>(0)));
438 auto length = get_param(L"LENGTH", params, std::numeric_limits<uint32_t>::max());
439 auto filter_str = get_param(L"FILTER", params, L"");
441 return create_destroy_proxy(spl::make_shared_ptr(std::make_shared<ffmpeg_producer>(dependencies.frame_factory, dependencies.format_desc, filename, filter_str, loop, start, length)));