]> git.sesse.net Git - casparcg/blob - modules/ffmpeg/producer/ffmpeg_producer.cpp
* Ported thread local disabling of ffmpeg producer logging from 2.0 and move some...
[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_disabled_for_thread())
149                                 CASPAR_LOG(info) << print() << L" " << video_decoder_->print();
150                 }
151                 catch(averror_stream_not_found&)
152                 {
153                         //CASPAR_LOG(warning) << print() << " No video-stream found. Running without video.";   
154                 }
155                 catch(...)
156                 {
157                         CASPAR_LOG_CURRENT_EXCEPTION();
158                         CASPAR_LOG(warning) << print() << "Failed to open video-stream. Running without video.";        
159                 }
160
161                 auto channel_layout = core::audio_channel_layout::invalid();
162
163                 try
164                 {
165                         audio_decoder_ .reset(new audio_decoder(input_, format_desc_, channel_layout_spec));
166                         audio_decoder_->monitor_output().attach_parent(monitor_subject_);
167
168                         channel_layout = audio_decoder_->channel_layout();
169                         
170                         CASPAR_LOG(info) << print() << L" " << audio_decoder_->print();
171                 }
172                 catch(averror_stream_not_found&)
173                 {
174                         //CASPAR_LOG(warning) << print() << " No audio-stream found. Running without audio.";   
175                 }
176                 catch(...)
177                 {
178                         CASPAR_LOG_CURRENT_EXCEPTION();
179                         CASPAR_LOG(warning) << print() << " Failed to open audio-stream. Running without audio.";               
180                 }
181
182                 if (start_ > file_nb_frames())
183                         CASPAR_THROW_EXCEPTION(seek_out_of_range() << msg_info("SEEK out of range"));
184
185                 muxer_.reset(new frame_muxer(fps_, frame_factory, format_desc_, channel_layout, filter));
186                 
187                 decode_next_frame();
188
189                 if (!is_logging_disabled_for_thread())
190                         CASPAR_LOG(info) << print() << L" Initialized";
191         }
192
193         // frame_producer
194         
195         core::draw_frame receive_impl() override
196         {                               
197                 auto frame = core::draw_frame::late();          
198                 
199                 caspar::timer frame_timer;
200                 
201                 end_seek();
202                                 
203                 decode_next_frame();
204                 
205                 if(!muxer_->empty())
206                 {
207                         last_frame_ = frame = std::move(muxer_->front());
208                         muxer_->pop();
209                 }
210                 else if (!input_.eof())
211                         graph_->set_tag(diagnostics::tag_severity::WARNING, "underflow");
212
213                 graph_->set_value("frame-time", frame_timer.elapsed()*format_desc_.fps*0.5);
214                 *monitor_subject_
215                                 << core::monitor::message("/profiler/time")     % frame_timer.elapsed() % (1.0/format_desc_.fps);                       
216                 *monitor_subject_
217                                 << core::monitor::message("/file/frame")        % static_cast<int32_t>(file_frame_number())
218                                                                                                                         % static_cast<int32_t>(file_nb_frames())
219                                 << core::monitor::message("/file/fps")          % fps_
220                                 << core::monitor::message("/file/path")         % path_relative_to_media_
221                                 << core::monitor::message("/loop")                      % input_.loop();
222                                                 
223                 return frame;
224         }
225
226         core::draw_frame last_frame() override
227         {
228                 end_seek();
229                 return core::draw_frame::still(last_frame_);
230         }
231
232         core::constraints& pixel_constraints() override
233         {
234                 return constraints_;
235         }
236
237         uint32_t nb_frames() const override
238         {
239                 if(input_.loop())
240                         return std::numeric_limits<uint32_t>::max();
241
242                 uint32_t nb_frames = file_nb_frames();
243
244                 nb_frames = std::min(input_.length(), nb_frames);
245                 nb_frames = muxer_->calc_nb_frames(nb_frames);
246                 
247                 return nb_frames > start_ ? nb_frames - start_ : 0;
248         }
249
250         uint32_t file_nb_frames() const
251         {
252                 uint32_t file_nb_frames = 0;
253                 file_nb_frames = std::max(file_nb_frames, video_decoder_ ? video_decoder_->nb_frames() : 0);
254                 file_nb_frames = std::max(file_nb_frames, audio_decoder_ ? audio_decoder_->nb_frames() : 0);
255                 return file_nb_frames;
256         }
257
258         uint32_t file_frame_number() const
259         {
260                 return video_decoder_ ? video_decoder_->file_frame_number() : 0;
261         }
262                 
263         std::future<std::wstring> call(const std::vector<std::wstring>& params) override
264         {
265                 static const boost::wregex loop_exp(LR"(LOOP\s*(?<VALUE>\d?)?)", boost::regex::icase);
266                 static const boost::wregex seek_exp(LR"(SEEK\s+(?<VALUE>\d+))", boost::regex::icase);
267                 static const boost::wregex length_exp(LR"(LENGTH\s+(?<VALUE>\d+)?)", boost::regex::icase);
268                 static const boost::wregex start_exp(LR"(START\\s+(?<VALUE>\\d+)?)", boost::regex::icase);
269
270                 auto param = boost::algorithm::join(params, L" ");
271                 
272                 std::wstring result;
273                         
274                 boost::wsmatch what;
275                 if(boost::regex_match(param, what, loop_exp))
276                 {
277                         auto value = what["VALUE"].str();
278                         if(!value.empty())
279                                 input_.loop(boost::lexical_cast<bool>(value));
280                         result = boost::lexical_cast<std::wstring>(loop());
281                 }
282                 else if(boost::regex_match(param, what, seek_exp))
283                 {
284                         auto value = what["VALUE"].str();
285                         seek(boost::lexical_cast<uint32_t>(value));
286                 }
287                 else if(boost::regex_match(param, what, length_exp))
288                 {
289                         auto value = what["VALUE"].str();
290                         if(!value.empty())
291                                 length(boost::lexical_cast<uint32_t>(value));                   
292                         result = boost::lexical_cast<std::wstring>(length());
293                 }
294                 else if(boost::regex_match(param, what, start_exp))
295                 {
296                         auto value = what["VALUE"].str();
297                         if(!value.empty())
298                                 start(boost::lexical_cast<uint32_t>(value));
299                         result = boost::lexical_cast<std::wstring>(start());
300                 }
301                 else
302                         CASPAR_THROW_EXCEPTION(invalid_argument());
303
304                 return make_ready_future(std::move(result));
305         }
306                                 
307         std::wstring print() const override
308         {
309                 return L"ffmpeg[" + boost::filesystem::path(filename_).filename().wstring() + L"|" 
310                                                   + print_mode() + L"|" 
311                                                   + boost::lexical_cast<std::wstring>(file_frame_number()) + L"/" + boost::lexical_cast<std::wstring>(file_nb_frames()) + L"]";
312         }
313
314         std::wstring name() const override
315         {
316                 return L"ffmpeg";
317         }
318
319         boost::property_tree::wptree info() const override
320         {
321                 boost::property_tree::wptree info;
322                 info.add(L"type",                               L"ffmpeg");
323                 info.add(L"filename",                   filename_);
324                 info.add(L"width",                              video_decoder_ ? video_decoder_->width() : 0);
325                 info.add(L"height",                             video_decoder_ ? video_decoder_->height() : 0);
326                 info.add(L"progressive",                video_decoder_ ? video_decoder_->is_progressive() : 0);
327                 info.add(L"fps",                                fps_);
328                 info.add(L"loop",                               input_.loop());
329                 info.add(L"frame-number",               frame_number());
330                 auto nb_frames2 = nb_frames();
331                 info.add(L"nb-frames",                  nb_frames2 == std::numeric_limits<int64_t>::max() ? -1 : nb_frames2);
332                 info.add(L"file-frame-number",  file_frame_number());
333                 info.add(L"file-nb-frames",             file_nb_frames());
334                 return info;
335         }
336         
337         core::monitor::subject& monitor_output()
338         {
339                 return *monitor_subject_;
340         }
341
342         // ffmpeg_producer
343         
344         void end_seek()
345         {
346                 for(int n = 0; n < 8 && (last_frame_ == core::draw_frame::empty() || (seek_target_ && file_frame_number() != *seek_target_+2)); ++n)
347                 {
348                         decode_next_frame();
349                         if(!muxer_->empty())
350                         {
351                                 last_frame_ = muxer_->front();
352                                 seek_target_.reset();
353                         }
354                 }
355         }
356
357         void loop(bool value)
358         {
359                 input_.loop(value);
360         }
361
362         bool loop() const
363         {
364                 return input_.loop();
365         }
366
367         void length(uint32_t value)
368         {
369                 input_.length(value);
370         }
371
372         uint32_t length()
373         {
374                 return input_.length();
375         }
376         
377         void start(uint32_t value)
378         {
379                 input_.start(value);
380         }
381
382         uint32_t start()
383         {
384                 return input_.start();
385         }
386
387         void seek(uint32_t target)
388         {               
389                 if (target > file_nb_frames())
390                         CASPAR_THROW_EXCEPTION(seek_out_of_range() << msg_info("SEEK out of range"));
391
392                 seek_target_ = target;
393
394                 input_.seek(*seek_target_);
395                 muxer_->clear();
396         }
397
398         std::wstring print_mode() const
399         {
400                 return ffmpeg::print_mode(video_decoder_ ? video_decoder_->width() : 0, 
401                         video_decoder_ ? video_decoder_->height() : 0, 
402                         fps_, 
403                         video_decoder_ ? !video_decoder_->is_progressive() : false);
404         }
405                         
406         void decode_next_frame()
407         {
408                 for(int n = 0; n < 32 && muxer_->empty(); ++n)
409                 {
410                         if(!muxer_->video_ready())
411                                 muxer_->push_video(video_decoder_ ? (*video_decoder_)() : create_frame());
412                         if(!muxer_->audio_ready())
413                                 muxer_->push_audio(audio_decoder_ ? (*audio_decoder_)() : create_frame());
414                 }
415
416                 graph_->set_text(print());
417         }
418 };
419
420 void describe_producer(core::help_sink& sink, const core::help_repository& repo)
421 {
422         sink.short_description(L"A producer for playing media files supported by FFmpeg.");
423         sink.syntax(L"[clip:string] {[loop:LOOP]} {START,SEEK [start:int]} {LENGTH [start:int]} {FILTER [filter:string]} {CHANNEL_LAYOUT [channel_layout:string]}");
424         sink.para()
425                 ->text(L"The FFmpeg Producer can play all media that FFmpeg can play, which includes many ")
426                 ->text(L"QuickTime video codec such as Animation, PNG, PhotoJPEG, MotionJPEG, as well as ")
427                 ->text(L"H.264, FLV, WMV and several audio codecs as well as uncompressed audio.");
428         sink.definitions()
429                 ->item(L"clip", L"The file without the file extension to play. It should reside under the media folder.")
430                 ->item(L"loop", L"Will cause the media file to loop between start and start + length")
431                 ->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.")
432                 ->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.")
433                 ->item(L"filter", L"If specified, will be used as an FFmpeg video filter.")
434                 ->item(L"channel_layout",
435                                 L"Optionally override the automatically deduced audio channel layout. "
436                                 L"Either a named layout as specified in casparcg.config or in the format [type:string]:[channel_order:string] for a custom layout.");
437         sink.para()->text(L"Examples:");
438         sink.example(L">> PLAY 1-10 folder/clip", L"to play all frames in a clip and stop at the last frame.");
439         sink.example(L">> PLAY 1-10 folder/clip LOOP", L"to loop a clip between the first frame and the last frame.");
440         sink.example(L">> PLAY 1-10 folder/clip LOOP START 10", L"to loop a clip between frame 10 and the last frame.");
441         sink.example(L">> PLAY 1-10 folder/clip LOOP START 10 LENGTH 50", L"to loop a clip between frame 10 and frame 60.");
442         sink.example(L">> PLAY 1-10 folder/clip START 10 LENGTH 50", L"to play frames 10-60 in a clip and stop.");
443         sink.example(L">> PLAY 1-10 folder/clip FILTER yadif=1,-1", L"to deinterlace the video.");
444         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.");
445         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.");
446         sink.para()->text(L"The FFmpeg producer also supports changing some of the settings via CALL:");
447         sink.example(L">> CALL 1-10 LOOP 1");
448         sink.example(L">> CALL 1-10 START 10");
449         sink.example(L">> CALL 1-10 LENGTH 50");
450 }
451
452 spl::shared_ptr<core::frame_producer> create_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params)
453 {               
454         auto filename = probe_stem(env::media_folder() + L"/" + params.at(0));
455
456         if(filename.empty())
457                 return core::frame_producer::empty();
458         
459         bool loop                       = contains_param(L"LOOP", params);
460         auto start                      = get_param(L"START", params, get_param(L"SEEK", params, static_cast<uint32_t>(0)));
461         auto length                     = get_param(L"LENGTH", params, std::numeric_limits<uint32_t>::max());
462         auto filter_str         = get_param(L"FILTER", params, L"");
463         auto channel_layout     = get_param(L"CHANNEL_LAYOUT", params, L"");
464
465         return create_destroy_proxy(spl::make_shared_ptr(std::make_shared<ffmpeg_producer>(
466                         dependencies.frame_factory,
467                         dependencies.format_desc,
468                         channel_layout,
469                         filename,
470                         filter_str,
471                         loop,
472                         start,
473                         length)));
474 }
475
476 }}