]> git.sesse.net Git - casparcg/blob - modules/ffmpeg/producer/ffmpeg_producer.cpp
Decode audio and video in parallel just like in 2.0
[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         const bool                                                                              thumbnail_mode_;
110                 
111         std::unique_ptr<video_decoder>                                  video_decoder_;
112         std::unique_ptr<audio_decoder>                                  audio_decoder_; 
113         std::unique_ptr<frame_muxer>                                    muxer_;
114         core::constraints                                                               constraints_;
115         
116         core::draw_frame                                                                last_frame_                             = core::draw_frame::empty();
117
118         boost::optional<uint32_t>                                               seek_target_;
119         
120 public:
121         explicit ffmpeg_producer(
122                         const spl::shared_ptr<core::frame_factory>& frame_factory, 
123                         const core::video_format_desc& format_desc,
124                         const std::wstring& channel_layout_spec,
125                         const std::wstring& filename,
126                         const std::wstring& filter,
127                         bool loop,
128                         uint32_t start,
129                         uint32_t length,
130                         bool thumbnail_mode)
131                 : filename_(filename)
132                 , frame_factory_(frame_factory)         
133                 , format_desc_(format_desc)
134                 , input_(graph_, filename_, loop, start, length, thumbnail_mode)
135                 , fps_(read_fps(input_.context(), format_desc_.fps))
136                 , start_(start)
137                 , thumbnail_mode_(thumbnail_mode)
138         {
139                 graph_->set_color("frame-time", diagnostics::color(0.1f, 1.0f, 0.1f));
140                 graph_->set_color("underflow", diagnostics::color(0.6f, 0.3f, 0.9f));   
141                 diagnostics::register_graph(graph_);
142                 
143
144                 try
145                 {
146                         video_decoder_.reset(new video_decoder(input_, thumbnail_mode));
147                         video_decoder_->monitor_output().attach_parent(monitor_subject_);
148                         constraints_.width.set(video_decoder_->width());
149                         constraints_.height.set(video_decoder_->height());
150                         
151                         if (is_logging_quiet_for_thread())
152                                 CASPAR_LOG(debug) << print() << L" " << video_decoder_->print();
153                         else
154                                 CASPAR_LOG(info) << print() << L" " << video_decoder_->print();
155                 }
156                 catch(averror_stream_not_found&)
157                 {
158                         CASPAR_LOG(debug) << print() << " No video-stream found. Running without video.";       
159                 }
160                 catch(...)
161                 {
162                         CASPAR_LOG_CURRENT_EXCEPTION();
163                         CASPAR_LOG(warning) << print() << "Failed to open video-stream. Running without video.";        
164                 }
165
166                 auto channel_layout = core::audio_channel_layout::invalid();
167
168                 if (!thumbnail_mode)
169                 {
170                         try
171                         {
172                                 audio_decoder_.reset(new audio_decoder(input_, format_desc_, channel_layout_spec));
173                                 audio_decoder_->monitor_output().attach_parent(monitor_subject_);
174
175                                 channel_layout = audio_decoder_->channel_layout();
176
177                                 CASPAR_LOG(info) << print() << L" " << audio_decoder_->print();
178                         }
179                         catch (averror_stream_not_found&)
180                         {
181                                 CASPAR_LOG(debug) << print() << " No audio-stream found. Running without audio.";       
182                         }
183                         catch (...)
184                         {
185                                 CASPAR_LOG_CURRENT_EXCEPTION();
186                                 CASPAR_LOG(warning) << print() << " Failed to open audio-stream. Running without audio.";
187                         }
188                 }
189
190                 if (start_ > file_nb_frames())
191                         CASPAR_THROW_EXCEPTION(seek_out_of_range() << msg_info("SEEK out of range"));
192
193                 muxer_.reset(new frame_muxer(fps_, frame_factory, format_desc_, channel_layout, filter));
194                 
195                 decode_next_frame();
196
197                 if (is_logging_quiet_for_thread())
198                         CASPAR_LOG(debug) << print() << L" Initialized";
199                 else
200                         CASPAR_LOG(info) << print() << L" Initialized";
201         }
202
203         // frame_producer
204         
205         core::draw_frame receive_impl() override
206         {                               
207                 auto frame = core::draw_frame::late();          
208                 
209                 caspar::timer frame_timer;
210                 
211                 end_seek();
212                                 
213                 decode_next_frame();
214                 
215                 if(!muxer_->empty())
216                 {
217                         last_frame_ = frame = std::move(muxer_->front());
218                         muxer_->pop();
219                 }
220                 else if (!input_.eof())
221                         graph_->set_tag(diagnostics::tag_severity::WARNING, "underflow");
222
223                 graph_->set_value("frame-time", frame_timer.elapsed()*format_desc_.fps*0.5);
224                 *monitor_subject_
225                                 << core::monitor::message("/profiler/time")     % frame_timer.elapsed() % (1.0/format_desc_.fps);                       
226                 *monitor_subject_
227                                 << core::monitor::message("/file/frame")        % static_cast<int32_t>(file_frame_number())
228                                                                                                                         % static_cast<int32_t>(file_nb_frames())
229                                 << core::monitor::message("/file/fps")          % fps_
230                                 << core::monitor::message("/file/path")         % path_relative_to_media_
231                                 << core::monitor::message("/loop")                      % input_.loop();
232                                                 
233                 return frame;
234         }
235
236         core::draw_frame render_specific_frame(uint32_t file_position)
237         {
238                 muxer_->clear();
239                 input_.seek(file_position);
240
241                 decode_next_frame();
242
243                 if (muxer_->empty())
244                 {
245                         CASPAR_LOG(trace) << print() << " Giving up finding frame at " << file_position;
246
247                         return core::draw_frame::empty();
248                 }
249
250                 auto frame = muxer_->front();
251                 muxer_->pop();
252
253                 return frame;
254         }
255
256         core::draw_frame create_thumbnail_frame() override
257         {
258                 auto quiet_logging = temporary_enable_quiet_logging_for_thread(true);
259
260                 auto total_frames = nb_frames();
261                 auto grid = env::properties().get(L"configuration.thumbnails.video-grid", 2);
262
263                 if (grid < 1)
264                 {
265                         CASPAR_LOG(error) << L"configuration/thumbnails/video-grid cannot be less than 1";
266                         BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("configuration/thumbnails/video-grid cannot be less than 1"));
267                 }
268
269                 if (grid == 1)
270                 {
271                         return render_specific_frame(total_frames / 2);
272                 }
273
274                 auto num_snapshots = grid * grid;
275
276                 std::vector<core::draw_frame> frames;
277
278                 for (int i = 0; i < num_snapshots; ++i)
279                 {
280                         int x = i % grid;
281                         int y = i / grid;
282                         int desired_frame;
283
284                         if (i == 0)
285                                 desired_frame = 0; // first
286                         else if (i == num_snapshots - 1)
287                                 desired_frame = total_frames - 1; // last
288                         else
289                                 // evenly distributed across the file.
290                                 desired_frame = total_frames * i / (num_snapshots - 1);
291
292                         auto frame = render_specific_frame(desired_frame);
293                         frame.transform().image_transform.fill_scale[0] = 1.0 / static_cast<double>(grid);
294                         frame.transform().image_transform.fill_scale[1] = 1.0 / static_cast<double>(grid);
295                         frame.transform().image_transform.fill_translation[0] = 1.0 / static_cast<double>(grid) * x;
296                         frame.transform().image_transform.fill_translation[1] = 1.0 / static_cast<double>(grid) * y;
297
298                         frames.push_back(frame);
299                 }
300
301                 return core::draw_frame(frames);
302         }
303
304         core::draw_frame last_frame() override
305         {
306                 end_seek();
307                 return core::draw_frame::still(last_frame_);
308         }
309
310         core::constraints& pixel_constraints() override
311         {
312                 return constraints_;
313         }
314
315         uint32_t nb_frames() const override
316         {
317                 if(input_.loop())
318                         return std::numeric_limits<uint32_t>::max();
319
320                 uint32_t nb_frames = file_nb_frames();
321
322                 nb_frames = std::min(input_.length(), nb_frames);
323                 nb_frames = muxer_->calc_nb_frames(nb_frames);
324                 
325                 return nb_frames > start_ ? nb_frames - start_ : 0;
326         }
327
328         uint32_t file_nb_frames() const
329         {
330                 uint32_t file_nb_frames = 0;
331                 file_nb_frames = std::max(file_nb_frames, video_decoder_ ? video_decoder_->nb_frames() : 0);
332                 file_nb_frames = std::max(file_nb_frames, audio_decoder_ ? audio_decoder_->nb_frames() : 0);
333                 return file_nb_frames;
334         }
335
336         uint32_t file_frame_number() const
337         {
338                 return video_decoder_ ? video_decoder_->file_frame_number() : 0;
339         }
340                 
341         std::future<std::wstring> call(const std::vector<std::wstring>& params) override
342         {
343                 static const boost::wregex loop_exp(LR"(LOOP\s*(?<VALUE>\d?)?)", boost::regex::icase);
344                 static const boost::wregex seek_exp(LR"(SEEK\s+(?<VALUE>\d+))", boost::regex::icase);
345                 static const boost::wregex length_exp(LR"(LENGTH\s+(?<VALUE>\d+)?)", boost::regex::icase);
346                 static const boost::wregex start_exp(LR"(START\\s+(?<VALUE>\\d+)?)", boost::regex::icase);
347
348                 auto param = boost::algorithm::join(params, L" ");
349                 
350                 std::wstring result;
351                         
352                 boost::wsmatch what;
353                 if(boost::regex_match(param, what, loop_exp))
354                 {
355                         auto value = what["VALUE"].str();
356                         if(!value.empty())
357                                 input_.loop(boost::lexical_cast<bool>(value));
358                         result = boost::lexical_cast<std::wstring>(loop());
359                 }
360                 else if(boost::regex_match(param, what, seek_exp))
361                 {
362                         auto value = what["VALUE"].str();
363                         seek(boost::lexical_cast<uint32_t>(value));
364                 }
365                 else if(boost::regex_match(param, what, length_exp))
366                 {
367                         auto value = what["VALUE"].str();
368                         if(!value.empty())
369                                 length(boost::lexical_cast<uint32_t>(value));                   
370                         result = boost::lexical_cast<std::wstring>(length());
371                 }
372                 else if(boost::regex_match(param, what, start_exp))
373                 {
374                         auto value = what["VALUE"].str();
375                         if(!value.empty())
376                                 start(boost::lexical_cast<uint32_t>(value));
377                         result = boost::lexical_cast<std::wstring>(start());
378                 }
379                 else
380                         CASPAR_THROW_EXCEPTION(invalid_argument());
381
382                 return make_ready_future(std::move(result));
383         }
384                                 
385         std::wstring print() const override
386         {
387                 return L"ffmpeg[" + boost::filesystem::path(filename_).filename().wstring() + L"|" 
388                                                   + print_mode() + L"|" 
389                                                   + boost::lexical_cast<std::wstring>(file_frame_number()) + L"/" + boost::lexical_cast<std::wstring>(file_nb_frames()) + L"]";
390         }
391
392         std::wstring name() const override
393         {
394                 return L"ffmpeg";
395         }
396
397         boost::property_tree::wptree info() const override
398         {
399                 boost::property_tree::wptree info;
400                 info.add(L"type",                               L"ffmpeg");
401                 info.add(L"filename",                   filename_);
402                 info.add(L"width",                              video_decoder_ ? video_decoder_->width() : 0);
403                 info.add(L"height",                             video_decoder_ ? video_decoder_->height() : 0);
404                 info.add(L"progressive",                video_decoder_ ? video_decoder_->is_progressive() : 0);
405                 info.add(L"fps",                                fps_);
406                 info.add(L"loop",                               input_.loop());
407                 info.add(L"frame-number",               frame_number());
408                 auto nb_frames2 = nb_frames();
409                 info.add(L"nb-frames",                  nb_frames2 == std::numeric_limits<int64_t>::max() ? -1 : nb_frames2);
410                 info.add(L"file-frame-number",  file_frame_number());
411                 info.add(L"file-nb-frames",             file_nb_frames());
412                 return info;
413         }
414         
415         core::monitor::subject& monitor_output()
416         {
417                 return *monitor_subject_;
418         }
419
420         // ffmpeg_producer
421         
422         void end_seek()
423         {
424                 for(int n = 0; n < 8 && (last_frame_ == core::draw_frame::empty() || (seek_target_ && file_frame_number() != *seek_target_+2)); ++n)
425                 {
426                         decode_next_frame();
427                         if(!muxer_->empty())
428                         {
429                                 last_frame_ = muxer_->front();
430                                 seek_target_.reset();
431                         }
432                 }
433         }
434
435         void loop(bool value)
436         {
437                 input_.loop(value);
438         }
439
440         bool loop() const
441         {
442                 return input_.loop();
443         }
444
445         void length(uint32_t value)
446         {
447                 input_.length(value);
448         }
449
450         uint32_t length()
451         {
452                 return input_.length();
453         }
454         
455         void start(uint32_t value)
456         {
457                 input_.start(value);
458         }
459
460         uint32_t start()
461         {
462                 return input_.start();
463         }
464
465         void seek(uint32_t target)
466         {               
467                 if (target > file_nb_frames())
468                         CASPAR_THROW_EXCEPTION(seek_out_of_range() << msg_info("SEEK out of range"));
469
470                 seek_target_ = target;
471
472                 input_.seek(*seek_target_);
473                 muxer_->clear();
474         }
475
476         std::wstring print_mode() const
477         {
478                 return ffmpeg::print_mode(video_decoder_ ? video_decoder_->width() : 0, 
479                         video_decoder_ ? video_decoder_->height() : 0, 
480                         fps_, 
481                         video_decoder_ ? !video_decoder_->is_progressive() : false);
482         }
483                         
484         void decode_next_frame()
485         {
486                 for(int n = 0; n < 32 && muxer_->empty(); ++n)
487                 {
488                         std::shared_ptr<AVFrame> video;
489                         std::shared_ptr<AVFrame> audio;
490                         bool needs_video = !muxer_->video_ready();
491                         bool needs_audio = !muxer_->audio_ready();
492
493                         tbb::parallel_invoke(
494                                         [&]
495                                         {
496                                                 if (needs_video)
497                                                         video = video_decoder_ ? (*video_decoder_)() : create_frame();
498                                         },
499                                         [&]
500                                         {
501                                                 if (needs_audio)
502                                                         audio = audio_decoder_ ? (*audio_decoder_)() : create_frame();
503                                         });
504
505                         muxer_->push_video(video);
506                         muxer_->push_audio(audio);
507                 }
508
509                 graph_->set_text(print());
510         }
511 };
512
513 void describe_producer(core::help_sink& sink, const core::help_repository& repo)
514 {
515         sink.short_description(L"A producer for playing media files supported by FFmpeg.");
516         sink.syntax(L"[clip:string] {[loop:LOOP]} {START,SEEK [start:int]} {LENGTH [start:int]} {FILTER [filter:string]} {CHANNEL_LAYOUT [channel_layout:string]}");
517         sink.para()
518                 ->text(L"The FFmpeg Producer can play all media that FFmpeg can play, which includes many ")
519                 ->text(L"QuickTime video codec such as Animation, PNG, PhotoJPEG, MotionJPEG, as well as ")
520                 ->text(L"H.264, FLV, WMV and several audio codecs as well as uncompressed audio.");
521         sink.definitions()
522                 ->item(L"clip", L"The file without the file extension to play. It should reside under the media folder.")
523                 ->item(L"loop", L"Will cause the media file to loop between start and start + length")
524                 ->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.")
525                 ->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.")
526                 ->item(L"filter", L"If specified, will be used as an FFmpeg video filter.")
527                 ->item(L"channel_layout",
528                                 L"Optionally override the automatically deduced audio channel layout. "
529                                 L"Either a named layout as specified in casparcg.config or in the format [type:string]:[channel_order:string] for a custom layout.");
530         sink.para()->text(L"Examples:");
531         sink.example(L">> PLAY 1-10 folder/clip", L"to play all frames in a clip and stop at the last frame.");
532         sink.example(L">> PLAY 1-10 folder/clip LOOP", L"to loop a clip between the first frame and the last frame.");
533         sink.example(L">> PLAY 1-10 folder/clip LOOP START 10", L"to loop a clip between frame 10 and the last frame.");
534         sink.example(L">> PLAY 1-10 folder/clip LOOP START 10 LENGTH 50", L"to loop a clip between frame 10 and frame 60.");
535         sink.example(L">> PLAY 1-10 folder/clip START 10 LENGTH 50", L"to play frames 10-60 in a clip and stop.");
536         sink.example(L">> PLAY 1-10 folder/clip FILTER yadif=1,-1", L"to deinterlace the video.");
537         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.");
538         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.");
539         sink.para()->text(L"The FFmpeg producer also supports changing some of the settings via CALL:");
540         sink.example(L">> CALL 1-10 LOOP 1");
541         sink.example(L">> CALL 1-10 START 10");
542         sink.example(L">> CALL 1-10 LENGTH 50");
543 }
544
545 spl::shared_ptr<core::frame_producer> create_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params)
546 {               
547         auto filename = probe_stem(env::media_folder() + L"/" + params.at(0), false);
548
549         if(filename.empty())
550                 return core::frame_producer::empty();
551         
552         bool loop                       = contains_param(L"LOOP", params);
553         auto start                      = get_param(L"START", params, get_param(L"SEEK", params, static_cast<uint32_t>(0)));
554         auto length                     = get_param(L"LENGTH", params, std::numeric_limits<uint32_t>::max());
555         auto filter_str         = get_param(L"FILTER", params, L"");
556         auto channel_layout     = get_param(L"CHANNEL_LAYOUT", params, L"");
557         bool thumbnail_mode     = false;
558
559         return create_destroy_proxy(spl::make_shared_ptr(std::make_shared<ffmpeg_producer>(
560                         dependencies.frame_factory,
561                         dependencies.format_desc,
562                         channel_layout,
563                         filename,
564                         filter_str,
565                         loop,
566                         start,
567                         length,
568                         thumbnail_mode)));
569 }
570
571 spl::shared_ptr<core::frame_producer> create_thumbnail_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params)
572 {
573         auto quiet_logging = temporary_enable_quiet_logging_for_thread(true);
574         auto filename = probe_stem(env::media_folder() + L"/" + params.at(0), true);
575
576         if(filename.empty())
577                 return core::frame_producer::empty();
578         
579         bool loop                       = false;
580         auto start                      = 0;
581         auto length                     = std::numeric_limits<uint32_t>::max();
582         auto filter_str         = L"";
583         auto channel_layout     = L"";
584         bool thumbnail_mode     = true;
585
586         return spl::make_shared_ptr(std::make_shared<ffmpeg_producer>(
587                         dependencies.frame_factory,
588                         dependencies.format_desc,
589                         channel_layout,
590                         filename,
591                         filter_str,
592                         loop,
593                         start,
594                         length,
595                         thumbnail_mode));
596 }
597
598 }}