]> git.sesse.net Git - casparcg/blob - core/producer/ffmpeg/ffmpeg_producer.cpp
2.0.0.2:
[casparcg] / core / producer / ffmpeg / ffmpeg_producer.cpp
1 #include "../../stdafx.h"\r
2 \r
3 #include "ffmpeg_producer.h"\r
4 \r
5 #if defined(_MSC_VER)\r
6 #pragma warning (push)\r
7 #pragma warning (disable : 4244)\r
8 #endif\r
9 \r
10 extern "C" \r
11 {\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
18 }\r
19 \r
20 #if defined(_MSC_VER)\r
21 #pragma warning (pop)\r
22 #endif\r
23 \r
24 #include "input.h"\r
25 \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
30 \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
36 \r
37 #include <tbb/mutex.h>\r
38 #include <tbb/parallel_invoke.h>\r
39 #include <tbb/task_group.h>\r
40 \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
45 \r
46 using namespace boost::assign;\r
47 \r
48 namespace caspar{ namespace ffmpeg{\r
49         \r
50 struct ffmpeg_producer : public frame_producer\r
51 {\r
52 public:\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
59 \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
62         {\r
63         if(!boost::filesystem::exists(filename))\r
64                 BOOST_THROW_EXCEPTION(file_not_found() <<  boost::errinfo_file_name(common::narrow(filename)));\r
65                 \r
66                 static boost::once_flag flag = BOOST_ONCE_INIT;\r
67                 boost::call_once(av_register_all, flag);        \r
68                                 \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
76         }\r
77                 \r
78         void initialize(const frame_factory_ptr& factory)\r
79         {\r
80                 video_transformer_->initialize(factory);\r
81         }\r
82                 \r
83         gpu_frame_ptr get_frame()\r
84         {\r
85                 while(ouput_channel_.empty() && !input_->is_eof())\r
86                 {                                                                               \r
87                         tbb::parallel_invoke(\r
88                         [&]\r
89                         { // Video Decoding and Scaling\r
90                                 auto video_packet = input_->get_video_packet();\r
91                                 if(video_packet)\r
92                                 {\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
96                                 }\r
97                         }, \r
98                         [&] \r
99                         { // Audio Decoding\r
100                                 auto audio_packet = input_->get_audio_packet();\r
101                                 if(audio_packet)\r
102                                 {\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
106                                 }\r
107                         });\r
108 \r
109                         while(!video_frame_channel_.empty() && (!audio_chunk_channel_.empty() || !has_audio_))\r
110                         {\r
111                                 if(has_audio_)\r
112                                 {\r
113                                         video_frame_channel_.front()->audio_data() = std::move(audio_chunk_channel_.front());\r
114                                         audio_chunk_channel_.pop_front();\r
115                                 }\r
116                                 \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
120                         }                               \r
121                 }\r
122 \r
123                 gpu_frame_ptr frame;\r
124                 if(!ouput_channel_.empty())\r
125                 {\r
126                         frame = ouput_channel_.front();\r
127                         ouput_channel_.pop();\r
128                 }\r
129                 return frame;\r
130         }\r
131 \r
132         const frame_format_desc& get_frame_format_desc() const { return format_desc_; }\r
133                 \r
134         bool has_audio_;\r
135 \r
136         // Filter 1 : Input\r
137         input_uptr                                                      input_;         \r
138 \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
144         \r
145         // Filter 3 : Audio Decoding\r
146         audio_decoder_uptr                                      audio_decoder_;\r
147         std::deque<std::vector<short>>          audio_chunk_channel_;\r
148 \r
149         // Filter 4 : Merge Video and Audio\r
150         std::queue<gpu_frame_ptr>                       ouput_channel_;\r
151         \r
152         std::wstring                                            filename_;\r
153         frame_format_desc                                       format_desc_;\r
154 };\r
155 \r
156 frame_producer_ptr create_ffmpeg_producer(const  std::vector<std::wstring>& params, const frame_format_desc& format_desc)\r
157 {\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
161                 return nullptr;\r
162 \r
163         return std::make_shared<ffmpeg_producer>(result_filename, params, format_desc);\r
164 }\r
165 \r
166 }}