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_transformer.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/utility/memory.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
72 video_decoder_.reset(new video_decoder());
\r
73 video_transformer_.reset(new video_transformer());
\r
74 audio_decoder_.reset(new audio_decoder());
\r
75 has_audio_ = input_->get_audio_codec_context() != nullptr;
\r
78 void initialize(const frame_factory_ptr& factory)
\r
80 video_transformer_->initialize(factory);
\r
83 gpu_frame_ptr get_frame()
\r
85 while(ouput_channel_.empty() && !input_->is_eof())
\r
87 tbb::parallel_invoke(
\r
89 { // Video Decoding and Scaling
\r
90 auto video_packet = input_->get_video_packet();
\r
93 video_packet = video_decoder_->execute(video_packet);
\r
94 auto frame = video_transformer_->execute(video_packet)->frame;
\r
95 video_frame_channel_.push_back(std::move(frame));
\r
100 auto audio_packet = input_->get_audio_packet();
\r
103 audio_decoder_->execute(audio_packet);
\r
104 for(size_t n = 0; n < audio_packet->audio_chunks.size(); ++n)
\r
105 audio_chunk_channel_.push_back(std::move(audio_packet->audio_chunks[n]));
\r
109 while(!video_frame_channel_.empty() && (!audio_chunk_channel_.empty() || !has_audio_))
\r
113 video_frame_channel_.front()->audio_data() = std::move(audio_chunk_channel_.front());
\r
114 audio_chunk_channel_.pop_front();
\r
117 gpu_frame_ptr frame = video_frame_channel_.front();
\r
118 video_frame_channel_.pop_front();
\r
119 ouput_channel_.push(std::move(frame));
\r
123 gpu_frame_ptr frame;
\r
124 if(!ouput_channel_.empty())
\r
126 frame = ouput_channel_.front();
\r
127 ouput_channel_.pop();
\r
132 const frame_format_desc& get_frame_format_desc() const { return format_desc_; }
\r
136 // Filter 1 : Input
\r
137 input_uptr input_;
\r
139 // Filter 2 : Video Decoding and Scaling
\r
140 video_decoder_uptr video_decoder_;
\r
141 video_transformer_uptr video_transformer_;
\r
142 //std::deque<video_packet_ptr> videoDecodedPacketChannel_;
\r
143 std::deque<gpu_frame_ptr> video_frame_channel_;
\r
145 // Filter 3 : Audio Decoding
\r
146 audio_decoder_uptr audio_decoder_;
\r
147 std::deque<std::vector<short>> audio_chunk_channel_;
\r
149 // Filter 4 : Merge Video and Audio
\r
150 std::queue<gpu_frame_ptr> ouput_channel_;
\r
152 std::wstring filename_;
\r
153 frame_format_desc format_desc_;
\r
156 frame_producer_ptr create_ffmpeg_producer(const std::vector<std::wstring>& params, const frame_format_desc& format_desc)
\r
158 std::wstring filename = params[0];
\r
159 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
160 if(result_filename.empty())
\r
163 return std::make_shared<ffmpeg_producer>(result_filename, params, format_desc);
\r