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>
52 #include <core/producer/media_info/media_info_repository.h>
53 #include <core/producer/media_info/media_info.h>
55 #include <boost/algorithm/string.hpp>
56 #include <boost/filesystem.hpp>
57 #include <boost/property_tree/ptree.hpp>
58 #include <boost/regex.hpp>
59 #include <boost/thread/future.hpp>
61 #include <tbb/parallel_invoke.h>
67 namespace caspar { namespace ffmpeg {
69 struct seek_out_of_range : virtual user_error {};
71 std::wstring get_relative_or_original(
72 const std::wstring& filename,
73 const boost::filesystem::path& relative_to)
75 boost::filesystem::path file(filename);
76 auto result = file.filename().wstring();
78 boost::filesystem::path current_path = file;
82 current_path = current_path.parent_path();
84 if (boost::filesystem::equivalent(current_path, relative_to))
87 if (current_path.empty())
90 result = current_path.filename().wstring() + L"/" + result;
96 struct ffmpeg_producer : public core::frame_producer_base
98 spl::shared_ptr<core::monitor::subject> monitor_subject_;
99 const std::wstring filename_;
100 const std::wstring path_relative_to_media_ = get_relative_or_original(filename_, env::media_folder());
102 const spl::shared_ptr<diagnostics::graph> graph_;
104 const spl::shared_ptr<core::frame_factory> frame_factory_;
105 const core::video_format_desc format_desc_;
109 const double fps_ = read_fps(input_.context(), format_desc_.fps);
110 const uint32_t start_;
111 const bool thumbnail_mode_;
112 const boost::optional<core::media_info> info_;
114 std::unique_ptr<video_decoder> video_decoder_;
115 std::unique_ptr<audio_decoder> audio_decoder_;
116 std::unique_ptr<frame_muxer> muxer_;
117 core::constraints constraints_;
119 core::draw_frame last_frame_ = core::draw_frame::empty();
121 boost::optional<uint32_t> seek_target_;
124 explicit ffmpeg_producer(
125 const spl::shared_ptr<core::frame_factory>& frame_factory,
126 const core::video_format_desc& format_desc,
127 const std::wstring& channel_layout_spec,
128 const std::wstring& filename,
129 const std::wstring& filter,
134 boost::optional<core::media_info> info)
135 : filename_(filename)
136 , frame_factory_(frame_factory)
137 , format_desc_(format_desc)
138 , input_(graph_, filename_, loop, start, length, thumbnail_mode)
140 , thumbnail_mode_(thumbnail_mode)
143 graph_->set_color("frame-time", diagnostics::color(0.1f, 1.0f, 0.1f));
144 graph_->set_color("underflow", diagnostics::color(0.6f, 0.3f, 0.9f));
145 diagnostics::register_graph(graph_);
150 video_decoder_.reset(new video_decoder(input_, thumbnail_mode));
151 video_decoder_->monitor_output().attach_parent(monitor_subject_);
152 constraints_.width.set(video_decoder_->width());
153 constraints_.height.set(video_decoder_->height());
155 if (is_logging_quiet_for_thread())
156 CASPAR_LOG(debug) << print() << L" " << video_decoder_->print();
158 CASPAR_LOG(info) << print() << L" " << video_decoder_->print();
160 catch(averror_stream_not_found&)
162 CASPAR_LOG(debug) << print() << " No video-stream found. Running without video.";
166 CASPAR_LOG_CURRENT_EXCEPTION();
167 CASPAR_LOG(warning) << print() << "Failed to open video-stream. Running without video.";
170 auto channel_layout = core::audio_channel_layout::invalid();
176 audio_decoder_.reset(new audio_decoder(input_, format_desc_, channel_layout_spec));
177 audio_decoder_->monitor_output().attach_parent(monitor_subject_);
179 channel_layout = audio_decoder_->channel_layout();
181 CASPAR_LOG(info) << print() << L" " << audio_decoder_->print();
183 catch (averror_stream_not_found&)
185 CASPAR_LOG(debug) << print() << " No audio-stream found. Running without audio.";
189 CASPAR_LOG_CURRENT_EXCEPTION();
190 CASPAR_LOG(warning) << print() << " Failed to open audio-stream. Running without audio.";
194 if (start_ > file_nb_frames())
195 CASPAR_THROW_EXCEPTION(seek_out_of_range() << msg_info("SEEK out of range"));
197 muxer_.reset(new frame_muxer(fps_, frame_factory, format_desc_, channel_layout, filter));
201 if (is_logging_quiet_for_thread())
202 CASPAR_LOG(debug) << print() << L" Initialized";
204 CASPAR_LOG(info) << print() << L" Initialized";
209 core::draw_frame receive_impl() override
211 auto frame = core::draw_frame::late();
213 caspar::timer frame_timer;
221 last_frame_ = frame = std::move(muxer_->front());
224 else if (!input_.eof())
225 graph_->set_tag(diagnostics::tag_severity::WARNING, "underflow");
227 graph_->set_value("frame-time", frame_timer.elapsed()*format_desc_.fps*0.5);
229 << core::monitor::message("/profiler/time") % frame_timer.elapsed() % (1.0/format_desc_.fps);
231 << core::monitor::message("/file/frame") % static_cast<int32_t>(file_frame_number())
232 % static_cast<int32_t>(file_nb_frames())
233 << core::monitor::message("/file/fps") % fps_
234 << core::monitor::message("/file/path") % path_relative_to_media_
235 << core::monitor::message("/loop") % input_.loop();
240 core::draw_frame render_specific_frame(uint32_t file_position)
243 input_.seek(file_position);
249 CASPAR_LOG(trace) << print() << " Giving up finding frame at " << file_position;
251 return core::draw_frame::empty();
254 auto frame = muxer_->front();
260 core::draw_frame create_thumbnail_frame() override
262 auto quiet_logging = temporary_enable_quiet_logging_for_thread(true);
264 auto total_frames = nb_frames();
265 auto grid = env::properties().get(L"configuration.thumbnails.video-grid", 2);
269 CASPAR_LOG(error) << L"configuration/thumbnails/video-grid cannot be less than 1";
270 BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("configuration/thumbnails/video-grid cannot be less than 1"));
275 return render_specific_frame(total_frames / 2);
278 auto num_snapshots = grid * grid;
280 std::vector<core::draw_frame> frames;
282 for (int i = 0; i < num_snapshots; ++i)
289 desired_frame = 0; // first
290 else if (i == num_snapshots - 1)
291 desired_frame = total_frames - 1; // last
293 // evenly distributed across the file.
294 desired_frame = total_frames * i / (num_snapshots - 1);
296 auto frame = render_specific_frame(desired_frame);
297 frame.transform().image_transform.fill_scale[0] = 1.0 / static_cast<double>(grid);
298 frame.transform().image_transform.fill_scale[1] = 1.0 / static_cast<double>(grid);
299 frame.transform().image_transform.fill_translation[0] = 1.0 / static_cast<double>(grid) * x;
300 frame.transform().image_transform.fill_translation[1] = 1.0 / static_cast<double>(grid) * y;
302 frames.push_back(frame);
305 return core::draw_frame(frames);
308 core::draw_frame last_frame() override
311 return core::draw_frame::still(last_frame_);
314 core::constraints& pixel_constraints() override
319 uint32_t nb_frames() const override
322 return std::numeric_limits<uint32_t>::max();
324 uint32_t nb_frames = file_nb_frames();
326 nb_frames = std::min(input_.length(), nb_frames);
327 nb_frames = muxer_->calc_nb_frames(nb_frames);
329 return nb_frames > start_ ? nb_frames - start_ : 0;
332 uint32_t file_nb_frames() const
334 uint32_t file_nb_frames = 0;
337 file_nb_frames = static_cast<uint32_t>(info_->duration);
339 file_nb_frames = std::max(file_nb_frames, video_decoder_ ? video_decoder_->nb_frames() : 0);
340 file_nb_frames = std::max(file_nb_frames, audio_decoder_ ? audio_decoder_->nb_frames() : 0);
341 return file_nb_frames;
344 uint32_t file_frame_number() const
346 return video_decoder_ ? video_decoder_->file_frame_number() : 0;
349 std::future<std::wstring> call(const std::vector<std::wstring>& params) override
351 static const boost::wregex loop_exp(LR"(LOOP\s*(?<VALUE>\d?)?)", boost::regex::icase);
352 static const boost::wregex seek_exp(LR"(SEEK\s+(?<VALUE>\d+))", boost::regex::icase);
353 static const boost::wregex length_exp(LR"(LENGTH\s+(?<VALUE>\d+)?)", boost::regex::icase);
354 static const boost::wregex start_exp(LR"(START\\s+(?<VALUE>\\d+)?)", boost::regex::icase);
356 auto param = boost::algorithm::join(params, L" ");
361 if(boost::regex_match(param, what, loop_exp))
363 auto value = what["VALUE"].str();
365 input_.loop(boost::lexical_cast<bool>(value));
366 result = boost::lexical_cast<std::wstring>(loop());
368 else if(boost::regex_match(param, what, seek_exp))
370 auto value = what["VALUE"].str();
371 seek(boost::lexical_cast<uint32_t>(value));
373 else if(boost::regex_match(param, what, length_exp))
375 auto value = what["VALUE"].str();
377 length(boost::lexical_cast<uint32_t>(value));
378 result = boost::lexical_cast<std::wstring>(length());
380 else if(boost::regex_match(param, what, start_exp))
382 auto value = what["VALUE"].str();
384 start(boost::lexical_cast<uint32_t>(value));
385 result = boost::lexical_cast<std::wstring>(start());
388 CASPAR_THROW_EXCEPTION(invalid_argument());
390 return make_ready_future(std::move(result));
393 std::wstring print() const override
395 return L"ffmpeg[" + boost::filesystem::path(filename_).filename().wstring() + L"|"
396 + print_mode() + L"|"
397 + boost::lexical_cast<std::wstring>(file_frame_number()) + L"/" + boost::lexical_cast<std::wstring>(file_nb_frames()) + L"]";
400 std::wstring name() const override
405 boost::property_tree::wptree info() const override
407 boost::property_tree::wptree info;
408 info.add(L"type", L"ffmpeg");
409 info.add(L"filename", filename_);
410 info.add(L"width", video_decoder_ ? video_decoder_->width() : 0);
411 info.add(L"height", video_decoder_ ? video_decoder_->height() : 0);
412 info.add(L"progressive", video_decoder_ ? video_decoder_->is_progressive() : 0);
413 info.add(L"fps", fps_);
414 info.add(L"loop", input_.loop());
415 info.add(L"frame-number", frame_number());
416 auto nb_frames2 = nb_frames();
417 info.add(L"nb-frames", nb_frames2 == std::numeric_limits<int64_t>::max() ? -1 : nb_frames2);
418 info.add(L"file-frame-number", file_frame_number());
419 info.add(L"file-nb-frames", file_nb_frames());
423 core::monitor::subject& monitor_output()
425 return *monitor_subject_;
432 for(int n = 0; n < 8 && (last_frame_ == core::draw_frame::empty() || (seek_target_ && file_frame_number() != *seek_target_+2)); ++n)
437 last_frame_ = muxer_->front();
438 seek_target_.reset();
443 void loop(bool value)
450 return input_.loop();
453 void length(uint32_t value)
455 input_.length(value);
460 return input_.length();
463 void start(uint32_t value)
470 return input_.start();
473 void seek(uint32_t target)
475 if (target > file_nb_frames())
476 CASPAR_THROW_EXCEPTION(seek_out_of_range() << msg_info("SEEK out of range"));
478 seek_target_ = target;
480 input_.seek(*seek_target_);
484 std::wstring print_mode() const
486 return ffmpeg::print_mode(video_decoder_ ? video_decoder_->width() : 0,
487 video_decoder_ ? video_decoder_->height() : 0,
489 video_decoder_ ? !video_decoder_->is_progressive() : false);
492 void decode_next_frame()
494 for(int n = 0; n < 32 && muxer_->empty(); ++n)
496 std::shared_ptr<AVFrame> video;
497 std::shared_ptr<AVFrame> audio;
498 bool needs_video = !muxer_->video_ready();
499 bool needs_audio = !muxer_->audio_ready();
501 tbb::parallel_invoke(
505 video = video_decoder_ ? (*video_decoder_)() : create_frame();
510 audio = audio_decoder_ ? (*audio_decoder_)() : create_frame();
513 muxer_->push_video(video);
514 muxer_->push_audio(audio);
517 graph_->set_text(print());
521 void describe_producer(core::help_sink& sink, const core::help_repository& repo)
523 sink.short_description(L"A producer for playing media files supported by FFmpeg.");
524 sink.syntax(L"[clip:string] {[loop:LOOP]} {START,SEEK [start:int]} {LENGTH [start:int]} {FILTER [filter:string]} {CHANNEL_LAYOUT [channel_layout:string]}");
526 ->text(L"The FFmpeg Producer can play all media that FFmpeg can play, which includes many ")
527 ->text(L"QuickTime video codec such as Animation, PNG, PhotoJPEG, MotionJPEG, as well as ")
528 ->text(L"H.264, FLV, WMV and several audio codecs as well as uncompressed audio.");
530 ->item(L"clip", L"The file without the file extension to play. It should reside under the media folder.")
531 ->item(L"loop", L"Will cause the media file to loop between start and start + length")
532 ->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.")
533 ->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.")
534 ->item(L"filter", L"If specified, will be used as an FFmpeg video filter.")
535 ->item(L"channel_layout",
536 L"Optionally override the automatically deduced audio channel layout. "
537 L"Either a named layout as specified in casparcg.config or in the format [type:string]:[channel_order:string] for a custom layout.");
538 sink.para()->text(L"Examples:");
539 sink.example(L">> PLAY 1-10 folder/clip", L"to play all frames in a clip and stop at the last frame.");
540 sink.example(L">> PLAY 1-10 folder/clip LOOP", L"to loop a clip between the first frame and the last frame.");
541 sink.example(L">> PLAY 1-10 folder/clip LOOP START 10", L"to loop a clip between frame 10 and the last frame.");
542 sink.example(L">> PLAY 1-10 folder/clip LOOP START 10 LENGTH 50", L"to loop a clip between frame 10 and frame 60.");
543 sink.example(L">> PLAY 1-10 folder/clip START 10 LENGTH 50", L"to play frames 10-60 in a clip and stop.");
544 sink.example(L">> PLAY 1-10 folder/clip FILTER yadif=1,-1", L"to deinterlace the video.");
545 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.");
546 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.");
547 sink.para()->text(L"The FFmpeg producer also supports changing some of the settings via CALL:");
548 sink.example(L">> CALL 1-10 LOOP 1");
549 sink.example(L">> CALL 1-10 START 10");
550 sink.example(L">> CALL 1-10 LENGTH 50");
553 spl::shared_ptr<core::frame_producer> create_producer(
554 const core::frame_producer_dependencies& dependencies,
555 const std::vector<std::wstring>& params,
556 const spl::shared_ptr<core::media_info_repository>& info_repo)
558 auto filename = probe_stem(env::media_folder() + L"/" + params.at(0), false);
561 return core::frame_producer::empty();
563 bool loop = contains_param(L"LOOP", params);
564 auto start = get_param(L"START", params, get_param(L"SEEK", params, static_cast<uint32_t>(0)));
565 auto length = get_param(L"LENGTH", params, std::numeric_limits<uint32_t>::max());
566 auto filter_str = get_param(L"FILTER", params, L"");
567 auto channel_layout = get_param(L"CHANNEL_LAYOUT", params, L"");
568 bool thumbnail_mode = false;
569 auto info = info_repo->get(filename);
571 return create_destroy_proxy(spl::make_shared_ptr(std::make_shared<ffmpeg_producer>(
572 dependencies.frame_factory,
573 dependencies.format_desc,
584 spl::shared_ptr<core::frame_producer> create_thumbnail_producer(
585 const core::frame_producer_dependencies& dependencies,
586 const std::vector<std::wstring>& params,
587 const spl::shared_ptr<core::media_info_repository>& info_repo)
589 auto quiet_logging = temporary_enable_quiet_logging_for_thread(true);
590 auto filename = probe_stem(env::media_folder() + L"/" + params.at(0), true);
593 return core::frame_producer::empty();
597 auto length = std::numeric_limits<uint32_t>::max();
598 auto filter_str = L"";
599 auto channel_layout = L"";
600 bool thumbnail_mode = true;
601 auto info = info_repo->get(filename);
603 return spl::make_shared_ptr(std::make_shared<ffmpeg_producer>(
604 dependencies.frame_factory,
605 dependencies.format_desc,