]> git.sesse.net Git - casparcg/blob - modules/ffmpeg/producer/ffmpeg_producer.cpp
Instead of disabling ffmpeg logging just truncate log level to debug so trace and...
[casparcg] / modules / ffmpeg / producer / ffmpeg_producer.cpp
1 /*
2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
3 *
4 * This file is part of CasparCG (www.casparcg.com).
5 *
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.
10 *
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.
15 *
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/>.
18 *
19 * Author: Robert Nagy, ronag89@gmail.com
20 */
21
22 #include "../StdAfx.h"
23
24 #include "ffmpeg_producer.h"
25
26 #include "../ffmpeg_error.h"
27 #include "../ffmpeg.h"
28
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"
34
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>
42
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
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>
58
59 #include <tbb/parallel_invoke.h>
60
61 #include <limits>
62 #include <memory>
63 #include <queue>
64
65 namespace caspar { namespace ffmpeg {
66
67 struct seek_out_of_range : virtual user_error {};
68
69 std::wstring get_relative_or_original(
70                 const std::wstring& filename,
71                 const boost::filesystem::path& relative_to)
72 {
73         boost::filesystem::path file(filename);
74         auto result = file.filename().wstring();
75
76         boost::filesystem::path current_path = file;
77
78         while (true)
79         {
80                 current_path = current_path.parent_path();
81
82                 if (boost::filesystem::equivalent(current_path, relative_to))
83                         break;
84
85                 if (current_path.empty())
86                         return filename;
87
88                 result = current_path.filename().wstring() + L"/" + result;
89         }
90
91         return result;
92 }
93
94 struct ffmpeg_producer : public core::frame_producer_base
95 {
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());
99         
100         const spl::shared_ptr<diagnostics::graph>               graph_;
101                                         
102         const spl::shared_ptr<core::frame_factory>              frame_factory_;
103         const core::video_format_desc                                   format_desc_;
104
105         input                                                                                   input_; 
106
107         const double                                                                    fps_                                    = read_fps(input_.context(), format_desc_.fps);
108         const uint32_t                                                                  start_;
109                 
110         std::unique_ptr<video_decoder>                                  video_decoder_;
111         std::unique_ptr<audio_decoder>                                  audio_decoder_; 
112         std::unique_ptr<frame_muxer>                                    muxer_;
113         core::constraints                                                               constraints_;
114         
115         core::draw_frame                                                                last_frame_                             = core::draw_frame::empty();
116
117         boost::optional<uint32_t>                                               seek_target_;
118         
119 public:
120         explicit ffmpeg_producer(
121                         const spl::shared_ptr<core::frame_factory>& frame_factory, 
122                         const core::video_format_desc& format_desc,
123                         const std::wstring& channel_layout_spec,
124                         const std::wstring& filename,
125                         const std::wstring& filter,
126                         bool loop,
127                         uint32_t start,
128                         uint32_t length)
129                 : filename_(filename)
130                 , frame_factory_(frame_factory)         
131                 , format_desc_(format_desc)
132                 , input_(graph_, filename_, loop, start, length)
133                 , fps_(read_fps(input_.context(), format_desc_.fps))
134                 , start_(start)
135         {
136                 graph_->set_color("frame-time", diagnostics::color(0.1f, 1.0f, 0.1f));
137                 graph_->set_color("underflow", diagnostics::color(0.6f, 0.3f, 0.9f));   
138                 diagnostics::register_graph(graph_);
139                 
140
141                 try
142                 {
143                         video_decoder_.reset(new video_decoder(input_));
144                         video_decoder_->monitor_output().attach_parent(monitor_subject_);
145                         constraints_.width.set(video_decoder_->width());
146                         constraints_.height.set(video_decoder_->height());
147                         
148                         if (is_logging_quiet_for_thread())
149                                 CASPAR_LOG(debug) << print() << L" " << video_decoder_->print();
150                         else
151                                 CASPAR_LOG(info) << print() << L" " << video_decoder_->print();
152                 }
153                 catch(averror_stream_not_found&)
154                 {
155                         CASPAR_LOG(debug) << print() << " No video-stream found. Running without video.";       
156                 }
157                 catch(...)
158                 {
159                         CASPAR_LOG_CURRENT_EXCEPTION();
160                         CASPAR_LOG(warning) << print() << "Failed to open video-stream. Running without video.";        
161                 }
162
163                 auto channel_layout = core::audio_channel_layout::invalid();
164
165                 try
166                 {
167                         audio_decoder_ .reset(new audio_decoder(input_, format_desc_, channel_layout_spec));
168                         audio_decoder_->monitor_output().attach_parent(monitor_subject_);
169
170                         channel_layout = audio_decoder_->channel_layout();
171                         
172                         CASPAR_LOG(info) << print() << L" " << audio_decoder_->print();
173                 }
174                 catch(averror_stream_not_found&)
175                 {
176                         //CASPAR_LOG(warning) << print() << " No audio-stream found. Running without audio.";   
177                 }
178                 catch(...)
179                 {
180                         CASPAR_LOG_CURRENT_EXCEPTION();
181                         CASPAR_LOG(warning) << print() << " Failed to open audio-stream. Running without audio.";               
182                 }
183
184                 if (start_ > file_nb_frames())
185                         CASPAR_THROW_EXCEPTION(seek_out_of_range() << msg_info("SEEK out of range"));
186
187                 muxer_.reset(new frame_muxer(fps_, frame_factory, format_desc_, channel_layout, filter));
188                 
189                 decode_next_frame();
190
191                 if (is_logging_quiet_for_thread())
192                         CASPAR_LOG(debug) << print() << L" Initialized";
193                 else
194                         CASPAR_LOG(info) << print() << L" Initialized";
195         }
196
197         // frame_producer
198         
199         core::draw_frame receive_impl() override
200         {                               
201                 auto frame = core::draw_frame::late();          
202                 
203                 caspar::timer frame_timer;
204                 
205                 end_seek();
206                                 
207                 decode_next_frame();
208                 
209                 if(!muxer_->empty())
210                 {
211                         last_frame_ = frame = std::move(muxer_->front());
212                         muxer_->pop();
213                 }
214                 else if (!input_.eof())
215                         graph_->set_tag(diagnostics::tag_severity::WARNING, "underflow");
216
217                 graph_->set_value("frame-time", frame_timer.elapsed()*format_desc_.fps*0.5);
218                 *monitor_subject_
219                                 << core::monitor::message("/profiler/time")     % frame_timer.elapsed() % (1.0/format_desc_.fps);                       
220                 *monitor_subject_
221                                 << core::monitor::message("/file/frame")        % static_cast<int32_t>(file_frame_number())
222                                                                                                                         % static_cast<int32_t>(file_nb_frames())
223                                 << core::monitor::message("/file/fps")          % fps_
224                                 << core::monitor::message("/file/path")         % path_relative_to_media_
225                                 << core::monitor::message("/loop")                      % input_.loop();
226                                                 
227                 return frame;
228         }
229
230         core::draw_frame last_frame() override
231         {
232                 end_seek();
233                 return core::draw_frame::still(last_frame_);
234         }
235
236         core::constraints& pixel_constraints() override
237         {
238                 return constraints_;
239         }
240
241         uint32_t nb_frames() const override
242         {
243                 if(input_.loop())
244                         return std::numeric_limits<uint32_t>::max();
245
246                 uint32_t nb_frames = file_nb_frames();
247
248                 nb_frames = std::min(input_.length(), nb_frames);
249                 nb_frames = muxer_->calc_nb_frames(nb_frames);
250                 
251                 return nb_frames > start_ ? nb_frames - start_ : 0;
252         }
253
254         uint32_t file_nb_frames() const
255         {
256                 uint32_t file_nb_frames = 0;
257                 file_nb_frames = std::max(file_nb_frames, video_decoder_ ? video_decoder_->nb_frames() : 0);
258                 file_nb_frames = std::max(file_nb_frames, audio_decoder_ ? audio_decoder_->nb_frames() : 0);
259                 return file_nb_frames;
260         }
261
262         uint32_t file_frame_number() const
263         {
264                 return video_decoder_ ? video_decoder_->file_frame_number() : 0;
265         }
266                 
267         std::future<std::wstring> call(const std::vector<std::wstring>& params) override
268         {
269                 static const boost::wregex loop_exp(LR"(LOOP\s*(?<VALUE>\d?)?)", boost::regex::icase);
270                 static const boost::wregex seek_exp(LR"(SEEK\s+(?<VALUE>\d+))", boost::regex::icase);
271                 static const boost::wregex length_exp(LR"(LENGTH\s+(?<VALUE>\d+)?)", boost::regex::icase);
272                 static const boost::wregex start_exp(LR"(START\\s+(?<VALUE>\\d+)?)", boost::regex::icase);
273
274                 auto param = boost::algorithm::join(params, L" ");
275                 
276                 std::wstring result;
277                         
278                 boost::wsmatch what;
279                 if(boost::regex_match(param, what, loop_exp))
280                 {
281                         auto value = what["VALUE"].str();
282                         if(!value.empty())
283                                 input_.loop(boost::lexical_cast<bool>(value));
284                         result = boost::lexical_cast<std::wstring>(loop());
285                 }
286                 else if(boost::regex_match(param, what, seek_exp))
287                 {
288                         auto value = what["VALUE"].str();
289                         seek(boost::lexical_cast<uint32_t>(value));
290                 }
291                 else if(boost::regex_match(param, what, length_exp))
292                 {
293                         auto value = what["VALUE"].str();
294                         if(!value.empty())
295                                 length(boost::lexical_cast<uint32_t>(value));                   
296                         result = boost::lexical_cast<std::wstring>(length());
297                 }
298                 else if(boost::regex_match(param, what, start_exp))
299                 {
300                         auto value = what["VALUE"].str();
301                         if(!value.empty())
302                                 start(boost::lexical_cast<uint32_t>(value));
303                         result = boost::lexical_cast<std::wstring>(start());
304                 }
305                 else
306                         CASPAR_THROW_EXCEPTION(invalid_argument());
307
308                 return make_ready_future(std::move(result));
309         }
310                                 
311         std::wstring print() const override
312         {
313                 return L"ffmpeg[" + boost::filesystem::path(filename_).filename().wstring() + L"|" 
314                                                   + print_mode() + L"|" 
315                                                   + boost::lexical_cast<std::wstring>(file_frame_number()) + L"/" + boost::lexical_cast<std::wstring>(file_nb_frames()) + L"]";
316         }
317
318         std::wstring name() const override
319         {
320                 return L"ffmpeg";
321         }
322
323         boost::property_tree::wptree info() const override
324         {
325                 boost::property_tree::wptree info;
326                 info.add(L"type",                               L"ffmpeg");
327                 info.add(L"filename",                   filename_);
328                 info.add(L"width",                              video_decoder_ ? video_decoder_->width() : 0);
329                 info.add(L"height",                             video_decoder_ ? video_decoder_->height() : 0);
330                 info.add(L"progressive",                video_decoder_ ? video_decoder_->is_progressive() : 0);
331                 info.add(L"fps",                                fps_);
332                 info.add(L"loop",                               input_.loop());
333                 info.add(L"frame-number",               frame_number());
334                 auto nb_frames2 = nb_frames();
335                 info.add(L"nb-frames",                  nb_frames2 == std::numeric_limits<int64_t>::max() ? -1 : nb_frames2);
336                 info.add(L"file-frame-number",  file_frame_number());
337                 info.add(L"file-nb-frames",             file_nb_frames());
338                 return info;
339         }
340         
341         core::monitor::subject& monitor_output()
342         {
343                 return *monitor_subject_;
344         }
345
346         // ffmpeg_producer
347         
348         void end_seek()
349         {
350                 for(int n = 0; n < 8 && (last_frame_ == core::draw_frame::empty() || (seek_target_ && file_frame_number() != *seek_target_+2)); ++n)
351                 {
352                         decode_next_frame();
353                         if(!muxer_->empty())
354                         {
355                                 last_frame_ = muxer_->front();
356                                 seek_target_.reset();
357                         }
358                 }
359         }
360
361         void loop(bool value)
362         {
363                 input_.loop(value);
364         }
365
366         bool loop() const
367         {
368                 return input_.loop();
369         }
370
371         void length(uint32_t value)
372         {
373                 input_.length(value);
374         }
375
376         uint32_t length()
377         {
378                 return input_.length();
379         }
380         
381         void start(uint32_t value)
382         {
383                 input_.start(value);
384         }
385
386         uint32_t start()
387         {
388                 return input_.start();
389         }
390
391         void seek(uint32_t target)
392         {               
393                 if (target > file_nb_frames())
394                         CASPAR_THROW_EXCEPTION(seek_out_of_range() << msg_info("SEEK out of range"));
395
396                 seek_target_ = target;
397
398                 input_.seek(*seek_target_);
399                 muxer_->clear();
400         }
401
402         std::wstring print_mode() const
403         {
404                 return ffmpeg::print_mode(video_decoder_ ? video_decoder_->width() : 0, 
405                         video_decoder_ ? video_decoder_->height() : 0, 
406                         fps_, 
407                         video_decoder_ ? !video_decoder_->is_progressive() : false);
408         }
409                         
410         void decode_next_frame()
411         {
412                 for(int n = 0; n < 32 && muxer_->empty(); ++n)
413                 {
414                         if(!muxer_->video_ready())
415                                 muxer_->push_video(video_decoder_ ? (*video_decoder_)() : create_frame());
416                         if(!muxer_->audio_ready())
417                                 muxer_->push_audio(audio_decoder_ ? (*audio_decoder_)() : create_frame());
418                 }
419
420                 graph_->set_text(print());
421         }
422 };
423
424 void describe_producer(core::help_sink& sink, const core::help_repository& repo)
425 {
426         sink.short_description(L"A producer for playing media files supported by FFmpeg.");
427         sink.syntax(L"[clip:string] {[loop:LOOP]} {START,SEEK [start:int]} {LENGTH [start:int]} {FILTER [filter:string]} {CHANNEL_LAYOUT [channel_layout:string]}");
428         sink.para()
429                 ->text(L"The FFmpeg Producer can play all media that FFmpeg can play, which includes many ")
430                 ->text(L"QuickTime video codec such as Animation, PNG, PhotoJPEG, MotionJPEG, as well as ")
431                 ->text(L"H.264, FLV, WMV and several audio codecs as well as uncompressed audio.");
432         sink.definitions()
433                 ->item(L"clip", L"The file without the file extension to play. It should reside under the media folder.")
434                 ->item(L"loop", L"Will cause the media file to loop between start and start + length")
435                 ->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.")
436                 ->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.")
437                 ->item(L"filter", L"If specified, will be used as an FFmpeg video filter.")
438                 ->item(L"channel_layout",
439                                 L"Optionally override the automatically deduced audio channel layout. "
440                                 L"Either a named layout as specified in casparcg.config or in the format [type:string]:[channel_order:string] for a custom layout.");
441         sink.para()->text(L"Examples:");
442         sink.example(L">> PLAY 1-10 folder/clip", L"to play all frames in a clip and stop at the last frame.");
443         sink.example(L">> PLAY 1-10 folder/clip LOOP", L"to loop a clip between the first frame and the last frame.");
444         sink.example(L">> PLAY 1-10 folder/clip LOOP START 10", L"to loop a clip between frame 10 and the last frame.");
445         sink.example(L">> PLAY 1-10 folder/clip LOOP START 10 LENGTH 50", L"to loop a clip between frame 10 and frame 60.");
446         sink.example(L">> PLAY 1-10 folder/clip START 10 LENGTH 50", L"to play frames 10-60 in a clip and stop.");
447         sink.example(L">> PLAY 1-10 folder/clip FILTER yadif=1,-1", L"to deinterlace the video.");
448         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.");
449         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.");
450         sink.para()->text(L"The FFmpeg producer also supports changing some of the settings via CALL:");
451         sink.example(L">> CALL 1-10 LOOP 1");
452         sink.example(L">> CALL 1-10 START 10");
453         sink.example(L">> CALL 1-10 LENGTH 50");
454 }
455
456 spl::shared_ptr<core::frame_producer> create_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params)
457 {               
458         auto filename = probe_stem(env::media_folder() + L"/" + params.at(0));
459
460         if(filename.empty())
461                 return core::frame_producer::empty();
462         
463         bool loop                       = contains_param(L"LOOP", params);
464         auto start                      = get_param(L"START", params, get_param(L"SEEK", params, static_cast<uint32_t>(0)));
465         auto length                     = get_param(L"LENGTH", params, std::numeric_limits<uint32_t>::max());
466         auto filter_str         = get_param(L"FILTER", params, L"");
467         auto channel_layout     = get_param(L"CHANNEL_LAYOUT", params, L"");
468
469         return create_destroy_proxy(spl::make_shared_ptr(std::make_shared<ffmpeg_producer>(
470                         dependencies.frame_factory,
471                         dependencies.format_desc,
472                         channel_layout,
473                         filename,
474                         filter_str,
475                         loop,
476                         start,
477                         length)));
478 }
479
480 }}