1 #include "../../stdafx.h"
\r
3 #include "ffmpeg_producer.h"
\r
5 #if defined(_MSC_VER)
\r
6 #pragma warning (push)
\r
7 #pragma warning (disable : 4244)
\r
12 #define __STDC_CONSTANT_MACROS
\r
13 #define __STDC_LIMIT_MACROS
\r
14 #include <libavcodec/avcodec.h>
\r
15 #include <libavformat/avformat.h>
\r
16 #include <libavutil/avutil.h>
\r
17 #include <libswscale/swscale.h>
\r
20 #if defined(_MSC_VER)
\r
21 #pragma warning (pop)
\r
26 #include "audio/audio_decoder.h"
\r
27 #include "video/video_decoder.h"
\r
28 #include "video/video_deinterlacer.h"
\r
29 #include "video/video_scaler.h"
\r
31 #include "../../frame/frame_format.h"
\r
32 #include "../../../common/utility/find_file.h"
\r
33 #include "../../server.h"
\r
34 #include "../../../common/image/image.h"
\r
35 #include "../../../common/utility/scope_exit.h"
\r
37 #include <tbb/mutex.h>
\r
38 #include <tbb/parallel_invoke.h>
\r
39 #include <tbb/task_group.h>
\r
41 #include <boost/algorithm/string/case_conv.hpp>
\r
42 #include <boost/lexical_cast.hpp>
\r
43 #include <boost/thread.hpp>
\r
44 #include <boost/thread/once.hpp>
\r
46 using namespace boost::assign;
\r
48 namespace caspar{ namespace ffmpeg{
\r
50 struct ffmpeg_producer : public frame_producer
\r
53 static const size_t MAX_TOKENS = 5;
\r
54 static const size_t MIN_BUFFER_SIZE = 2;
\r
55 static const size_t DEFAULT_BUFFER_SIZE = 8;
\r
56 static const size_t MAX_BUFFER_SIZE = 64;
\r
57 static const size_t LOAD_TARGET_BUFFER_SIZE = 4;
\r
58 static const size_t THREAD_TIMEOUT_MS = 1000;
\r
60 ffmpeg_producer(const std::wstring& filename, const std::vector<std::wstring>& params, const frame_format_desc& format_desc)
\r
61 : filename_(filename), format_desc_(format_desc)
\r
63 if(!boost::filesystem::exists(filename))
\r
64 BOOST_THROW_EXCEPTION(file_not_found() << boost::errinfo_file_name(common::narrow(filename)));
\r
66 static boost::once_flag flag = BOOST_ONCE_INIT;
\r
67 boost::call_once(av_register_all, flag);
\r
69 input_.reset(new input(format_desc));
\r
70 input_->set_loop(std::find(params.begin(), params.end(), L"LOOP") != params.end());
\r
71 input_->load(common::narrow(filename_));
\r
73 sound_channel_info_ptr snd_channel_info = input_->get_audio_codec_context() != nullptr ?
\r
74 std::make_shared<sound_channel_info>
\r
76 input_->get_audio_codec_context()->channels,
\r
77 input_->get_audio_codec_context()->bits_per_coded_sample,
\r
78 input_->get_audio_codec_context()->sample_rate
\r
81 video_decoder_.reset(new video_decoder());
\r
82 video_scaler_.reset(new video_scaler());
\r
83 audio_decoder_.reset(new audio_decoder(snd_channel_info));
\r
84 has_audio_ = input_->get_audio_codec_context() != nullptr;
\r
87 frame_ptr get_frame()
\r
89 while(ouput_channel_.empty() && !input_->is_eof())
\r
91 tbb::parallel_invoke(
\r
93 { // Video Decoding and Scaling
\r
94 auto video_packet = input_->get_video_packet();
\r
97 video_packet = video_decoder_->execute(video_packet);
\r
98 auto frame = video_scaler_->execute(video_packet)->frame;
\r
99 video_frame_channel_.push_back(std::move(frame));
\r
103 { // Audio Decoding
\r
104 auto audio_packet = input_->get_audio_packet();
\r
107 auto audio_chunks = audio_decoder_->execute(audio_packet);
\r
108 audio_chunk_channel_.insert(audio_chunk_channel_.end(), audio_packet->audio_chunks.begin(), audio_packet->audio_chunks.end());
\r
112 while(!video_frame_channel_.empty() && (!audio_chunk_channel_.empty() || !has_audio_))
\r
116 video_frame_channel_.front()->audio_data().push_back(audio_chunk_channel_.front());
\r
117 audio_chunk_channel_.pop_front();
\r
120 frame_ptr frame = video_frame_channel_.front();
\r
121 video_frame_channel_.pop_front();
\r
122 ouput_channel_.push(std::move(frame));
\r
127 if(!ouput_channel_.empty())
\r
129 frame = ouput_channel_.front();
\r
130 ouput_channel_.pop();
\r
135 const frame_format_desc& get_frame_format_desc() const { return format_desc_; }
\r
139 // Filter 1 : Input
\r
140 input_uptr input_;
\r
142 // Filter 2 : Video Decoding and Scaling
\r
143 video_decoder_uptr video_decoder_;
\r
144 video_scaler_uptr video_scaler_;
\r
145 //std::deque<video_packet_ptr> videoDecodedPacketChannel_;
\r
146 std::deque<frame_ptr> video_frame_channel_;
\r
148 // Filter 3 : Audio Decoding
\r
149 audio_decoder_uptr audio_decoder_;
\r
150 std::deque<audio_chunk_ptr> audio_chunk_channel_;
\r
152 // Filter 4 : Merge Video and Audio
\r
153 std::queue<frame_ptr> ouput_channel_;
\r
155 std::wstring filename_;
\r
156 frame_format_desc format_desc_;
\r
159 frame_producer_ptr create_ffmpeg_producer(const std::vector<std::wstring>& params, const frame_format_desc& format_desc)
\r
161 std::wstring filename = params[0];
\r
162 std::wstring result_filename = common::find_file(server::media_folder() + filename, list_of(L"mpg")(L"avi")(L"mov")(L"dv")(L"wav")(L"mp3")(L"mp4")(L"f4v")(L"flv"));
\r
163 if(result_filename.empty())
\r
166 return std::make_shared<ffmpeg_producer>(result_filename, params, format_desc);
\r