]> git.sesse.net Git - casparcg/blob - modules/ffmpeg/producer/ffmpeg_producer.cpp
aed7a41dc3d9748ea8bcc16d31e3c4b2c9be3257
[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 #include <core/producer/media_info/media_info_repository.h>
53 #include <core/producer/media_info/media_info.h>
54
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>
60
61 #include <tbb/parallel_invoke.h>
62
63 #include <limits>
64 #include <memory>
65 #include <queue>
66
67 namespace caspar { namespace ffmpeg {
68
69 struct seek_out_of_range : virtual user_error {};
70
71 std::wstring get_relative_or_original(
72                 const std::wstring& filename,
73                 const boost::filesystem::path& relative_to)
74 {
75         boost::filesystem::path file(filename);
76         auto result = file.filename().wstring();
77
78         boost::filesystem::path current_path = file;
79
80         while (true)
81         {
82                 current_path = current_path.parent_path();
83
84                 if (boost::filesystem::equivalent(current_path, relative_to))
85                         break;
86
87                 if (current_path.empty())
88                         return filename;
89
90                 result = current_path.filename().wstring() + L"/" + result;
91         }
92
93         return result;
94 }
95
96 struct ffmpeg_producer : public core::frame_producer_base
97 {
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());
101         
102         const spl::shared_ptr<diagnostics::graph>               graph_;
103                                         
104         const spl::shared_ptr<core::frame_factory>              frame_factory_;
105         const core::video_format_desc                                   format_desc_;
106
107         input                                                                                   input_; 
108
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_;
113                 
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_;
118         
119         core::draw_frame                                                                last_frame_                             = core::draw_frame::empty();
120
121         boost::optional<uint32_t>                                               seek_target_;
122         
123 public:
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,
130                         bool loop,
131                         uint32_t start,
132                         uint32_t length,
133                         bool thumbnail_mode,
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)
139                 , start_(start)
140                 , thumbnail_mode_(thumbnail_mode)
141                 , info_(info)
142         {
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_);
146                 
147
148                 try
149                 {
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());
154                         
155                         if (is_logging_quiet_for_thread())
156                                 CASPAR_LOG(debug) << print() << L" " << video_decoder_->print();
157                         else
158                                 CASPAR_LOG(info) << print() << L" " << video_decoder_->print();
159                 }
160                 catch(averror_stream_not_found&)
161                 {
162                         CASPAR_LOG(debug) << print() << " No video-stream found. Running without video.";       
163                 }
164                 catch(...)
165                 {
166                         CASPAR_LOG_CURRENT_EXCEPTION();
167                         CASPAR_LOG(warning) << print() << "Failed to open video-stream. Running without video.";        
168                 }
169
170                 auto channel_layout = core::audio_channel_layout::invalid();
171
172                 if (!thumbnail_mode)
173                 {
174                         try
175                         {
176                                 audio_decoder_.reset(new audio_decoder(input_, format_desc_, channel_layout_spec));
177                                 audio_decoder_->monitor_output().attach_parent(monitor_subject_);
178
179                                 channel_layout = audio_decoder_->channel_layout();
180
181                                 CASPAR_LOG(info) << print() << L" " << audio_decoder_->print();
182                         }
183                         catch (averror_stream_not_found&)
184                         {
185                                 CASPAR_LOG(debug) << print() << " No audio-stream found. Running without audio.";       
186                         }
187                         catch (...)
188                         {
189                                 CASPAR_LOG_CURRENT_EXCEPTION();
190                                 CASPAR_LOG(warning) << print() << " Failed to open audio-stream. Running without audio.";
191                         }
192                 }
193
194                 if (start_ > file_nb_frames())
195                         CASPAR_THROW_EXCEPTION(seek_out_of_range() << msg_info("SEEK out of range"));
196
197                 muxer_.reset(new frame_muxer(fps_, frame_factory, format_desc_, channel_layout, filter));
198                 
199                 decode_next_frame();
200
201                 if (is_logging_quiet_for_thread())
202                         CASPAR_LOG(debug) << print() << L" Initialized";
203                 else
204                         CASPAR_LOG(info) << print() << L" Initialized";
205         }
206
207         // frame_producer
208         
209         core::draw_frame receive_impl() override
210         {                               
211                 auto frame = core::draw_frame::late();          
212                 
213                 caspar::timer frame_timer;
214                 
215                 end_seek();
216                                 
217                 decode_next_frame();
218                 
219                 if(!muxer_->empty())
220                 {
221                         last_frame_ = frame = std::move(muxer_->front());
222                         muxer_->pop();
223                 }
224                 else if (!input_.eof())
225                         graph_->set_tag(diagnostics::tag_severity::WARNING, "underflow");
226
227                 graph_->set_value("frame-time", frame_timer.elapsed()*format_desc_.fps*0.5);
228                 *monitor_subject_
229                                 << core::monitor::message("/profiler/time")     % frame_timer.elapsed() % (1.0/format_desc_.fps);                       
230                 *monitor_subject_
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();
236                                                 
237                 return frame;
238         }
239
240         core::draw_frame render_specific_frame(uint32_t file_position)
241         {
242                 muxer_->clear();
243                 input_.seek(file_position);
244
245                 decode_next_frame();
246
247                 if (muxer_->empty())
248                 {
249                         CASPAR_LOG(trace) << print() << " Giving up finding frame at " << file_position;
250
251                         return core::draw_frame::empty();
252                 }
253
254                 auto frame = muxer_->front();
255                 muxer_->pop();
256
257                 return frame;
258         }
259
260         core::draw_frame create_thumbnail_frame() override
261         {
262                 auto quiet_logging = temporary_enable_quiet_logging_for_thread(true);
263
264                 auto total_frames = nb_frames();
265                 auto grid = env::properties().get(L"configuration.thumbnails.video-grid", 2);
266
267                 if (grid < 1)
268                 {
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"));
271                 }
272
273                 if (grid == 1)
274                 {
275                         return render_specific_frame(total_frames / 2);
276                 }
277
278                 auto num_snapshots = grid * grid;
279
280                 std::vector<core::draw_frame> frames;
281
282                 for (int i = 0; i < num_snapshots; ++i)
283                 {
284                         int x = i % grid;
285                         int y = i / grid;
286                         int desired_frame;
287
288                         if (i == 0)
289                                 desired_frame = 0; // first
290                         else if (i == num_snapshots - 1)
291                                 desired_frame = total_frames - 1; // last
292                         else
293                                 // evenly distributed across the file.
294                                 desired_frame = total_frames * i / (num_snapshots - 1);
295
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;
301
302                         frames.push_back(frame);
303                 }
304
305                 return core::draw_frame(frames);
306         }
307
308         core::draw_frame last_frame() override
309         {
310                 end_seek();
311                 return core::draw_frame::still(last_frame_);
312         }
313
314         core::constraints& pixel_constraints() override
315         {
316                 return constraints_;
317         }
318
319         uint32_t nb_frames() const override
320         {
321                 if(input_.loop())
322                         return std::numeric_limits<uint32_t>::max();
323
324                 uint32_t nb_frames = file_nb_frames();
325
326                 nb_frames = std::min(input_.length(), nb_frames);
327                 nb_frames = muxer_->calc_nb_frames(nb_frames);
328                 
329                 return nb_frames > start_ ? nb_frames - start_ : 0;
330         }
331
332         uint32_t file_nb_frames() const
333         {
334                 uint32_t file_nb_frames = 0;
335
336                 if (info_)
337                         file_nb_frames = static_cast<uint32_t>(info_->duration);
338
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;
342         }
343
344         uint32_t file_frame_number() const
345         {
346                 return video_decoder_ ? video_decoder_->file_frame_number() : 0;
347         }
348                 
349         std::future<std::wstring> call(const std::vector<std::wstring>& params) override
350         {
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);
355
356                 auto param = boost::algorithm::join(params, L" ");
357                 
358                 std::wstring result;
359                         
360                 boost::wsmatch what;
361                 if(boost::regex_match(param, what, loop_exp))
362                 {
363                         auto value = what["VALUE"].str();
364                         if(!value.empty())
365                                 input_.loop(boost::lexical_cast<bool>(value));
366                         result = boost::lexical_cast<std::wstring>(loop());
367                 }
368                 else if(boost::regex_match(param, what, seek_exp))
369                 {
370                         auto value = what["VALUE"].str();
371                         seek(boost::lexical_cast<uint32_t>(value));
372                 }
373                 else if(boost::regex_match(param, what, length_exp))
374                 {
375                         auto value = what["VALUE"].str();
376                         if(!value.empty())
377                                 length(boost::lexical_cast<uint32_t>(value));                   
378                         result = boost::lexical_cast<std::wstring>(length());
379                 }
380                 else if(boost::regex_match(param, what, start_exp))
381                 {
382                         auto value = what["VALUE"].str();
383                         if(!value.empty())
384                                 start(boost::lexical_cast<uint32_t>(value));
385                         result = boost::lexical_cast<std::wstring>(start());
386                 }
387                 else
388                         CASPAR_THROW_EXCEPTION(invalid_argument());
389
390                 return make_ready_future(std::move(result));
391         }
392                                 
393         std::wstring print() const override
394         {
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"]";
398         }
399
400         std::wstring name() const override
401         {
402                 return L"ffmpeg";
403         }
404
405         boost::property_tree::wptree info() const override
406         {
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());
420                 return info;
421         }
422         
423         core::monitor::subject& monitor_output()
424         {
425                 return *monitor_subject_;
426         }
427
428         // ffmpeg_producer
429         
430         void end_seek()
431         {
432                 for(int n = 0; n < 8 && (last_frame_ == core::draw_frame::empty() || (seek_target_ && file_frame_number() != *seek_target_+2)); ++n)
433                 {
434                         decode_next_frame();
435                         if(!muxer_->empty())
436                         {
437                                 last_frame_ = muxer_->front();
438                                 seek_target_.reset();
439                         }
440                 }
441         }
442
443         void loop(bool value)
444         {
445                 input_.loop(value);
446         }
447
448         bool loop() const
449         {
450                 return input_.loop();
451         }
452
453         void length(uint32_t value)
454         {
455                 input_.length(value);
456         }
457
458         uint32_t length()
459         {
460                 return input_.length();
461         }
462         
463         void start(uint32_t value)
464         {
465                 input_.start(value);
466         }
467
468         uint32_t start()
469         {
470                 return input_.start();
471         }
472
473         void seek(uint32_t target)
474         {               
475                 if (target > file_nb_frames())
476                         CASPAR_THROW_EXCEPTION(seek_out_of_range() << msg_info("SEEK out of range"));
477
478                 seek_target_ = target;
479
480                 input_.seek(*seek_target_);
481                 muxer_->clear();
482         }
483
484         std::wstring print_mode() const
485         {
486                 return ffmpeg::print_mode(video_decoder_ ? video_decoder_->width() : 0, 
487                         video_decoder_ ? video_decoder_->height() : 0, 
488                         fps_, 
489                         video_decoder_ ? !video_decoder_->is_progressive() : false);
490         }
491                         
492         void decode_next_frame()
493         {
494                 for(int n = 0; n < 32 && muxer_->empty(); ++n)
495                 {
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();
500
501                         tbb::parallel_invoke(
502                                         [&]
503                                         {
504                                                 if (needs_video)
505                                                         video = video_decoder_ ? (*video_decoder_)() : create_frame();
506                                         },
507                                         [&]
508                                         {
509                                                 if (needs_audio)
510                                                         audio = audio_decoder_ ? (*audio_decoder_)() : create_frame();
511                                         });
512
513                         muxer_->push_video(video);
514                         muxer_->push_audio(audio);
515                 }
516
517                 graph_->set_text(print());
518         }
519 };
520
521 void describe_producer(core::help_sink& sink, const core::help_repository& repo)
522 {
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]}");
525         sink.para()
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.");
529         sink.definitions()
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");
551 }
552
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)
557 {
558         auto filename = probe_stem(env::media_folder() + L"/" + params.at(0), false);
559
560         if(filename.empty())
561                 return core::frame_producer::empty();
562         
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);
570
571         return create_destroy_proxy(spl::make_shared_ptr(std::make_shared<ffmpeg_producer>(
572                         dependencies.frame_factory,
573                         dependencies.format_desc,
574                         channel_layout,
575                         filename,
576                         filter_str,
577                         loop,
578                         start,
579                         length,
580                         thumbnail_mode,
581                         info)));
582 }
583
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)
588 {
589         auto quiet_logging = temporary_enable_quiet_logging_for_thread(true);
590         auto filename = probe_stem(env::media_folder() + L"/" + params.at(0), true);
591
592         if(filename.empty())
593                 return core::frame_producer::empty();
594         
595         bool loop                       = false;
596         auto start                      = 0;
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);
602
603         return spl::make_shared_ptr(std::make_shared<ffmpeg_producer>(
604                         dependencies.frame_factory,
605                         dependencies.format_desc,
606                         channel_layout,
607                         filename,
608                         filter_str,
609                         loop,
610                         start,
611                         length,
612                         thumbnail_mode,
613                         info));
614 }
615
616 }}