]> git.sesse.net Git - casparcg/blob - modules/ffmpeg/ffmpeg.cpp
Rebase parameters branch on current master.
[casparcg] / modules / ffmpeg / ffmpeg.cpp
1 /*\r
2 * Copyright 2013 Sveriges Television AB http://casparcg.com/\r
3 *\r
4 * This file is part of CasparCG (www.casparcg.com).\r
5 *\r
6 * CasparCG is free software: you can redistribute it and/or modify\r
7 * it under the terms of the GNU General Public License as published by\r
8 * the Free Software Foundation, either version 3 of the License, or\r
9 * (at your option) any later version.\r
10 *\r
11 * CasparCG is distributed in the hope that it will be useful,\r
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14 * GNU General Public License for more details.\r
15 *\r
16 * You should have received a copy of the GNU General Public License\r
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
18 *\r
19 * Author: Robert Nagy, ronag89@gmail.com\r
20 */\r
21 \r
22 #include "StdAfx.h"\r
23 \r
24 #include "consumer/ffmpeg_consumer.h"\r
25 #include "producer/ffmpeg_producer.h"\r
26 \r
27 #include <common/log/log.h>\r
28 \r
29 #include <core/parameters/parameters.h>\r
30 #include <core/consumer/frame_consumer.h>\r
31 #include <core/producer/frame_producer.h>\r
32 \r
33 #include <tbb/recursive_mutex.h>\r
34 \r
35 #include <boost/thread.hpp>\r
36 \r
37 #if defined(_MSC_VER)\r
38 #pragma warning (disable : 4244)\r
39 #pragma warning (disable : 4603)\r
40 #pragma warning (disable : 4996)\r
41 #endif\r
42 \r
43 extern "C" \r
44 {\r
45         #define __STDC_CONSTANT_MACROS\r
46         #define __STDC_LIMIT_MACROS\r
47         #include <libavformat/avformat.h>\r
48         #include <libswscale/swscale.h>\r
49         #include <libavutil/avutil.h>\r
50         #include <libavfilter/avfilter.h>\r
51         #include <libavdevice/avdevice.h>\r
52 }\r
53 \r
54 namespace caspar { namespace ffmpeg {\r
55         \r
56 int ffmpeg_lock_callback(void **mutex, enum AVLockOp op) \r
57\r
58         if(!mutex)\r
59                 return 0;\r
60 \r
61         auto my_mutex = reinterpret_cast<tbb::recursive_mutex*>(*mutex);\r
62         \r
63         switch(op) \r
64         { \r
65                 case AV_LOCK_CREATE: \r
66                 { \r
67                         *mutex = new tbb::recursive_mutex(); \r
68                         break; \r
69                 } \r
70                 case AV_LOCK_OBTAIN: \r
71                 { \r
72                         if(my_mutex)\r
73                                 my_mutex->lock(); \r
74                         break; \r
75                 } \r
76                 case AV_LOCK_RELEASE: \r
77                 { \r
78                         if(my_mutex)\r
79                                 my_mutex->unlock(); \r
80                         break; \r
81                 } \r
82                 case AV_LOCK_DESTROY: \r
83                 { \r
84                         delete my_mutex;\r
85                         *mutex = nullptr;\r
86                         break; \r
87                 } \r
88         } \r
89         return 0; \r
90\r
91 \r
92 static void sanitize(uint8_t *line)\r
93 {\r
94     while(*line)\r
95         {\r
96         if(*line < 0x08 || (*line > 0x0D && *line < 0x20))\r
97             *line='?';\r
98         line++;\r
99     }\r
100 }\r
101 \r
102 void log_callback(void* ptr, int level, const char* fmt, va_list vl)\r
103 {\r
104     static int print_prefix=1;\r
105     static int count;\r
106     static char prev[1024];\r
107     char line[8192];\r
108     static int is_atty;\r
109     AVClass* avc= ptr ? *(AVClass**)ptr : NULL;\r
110     if(level > av_log_get_level())\r
111         return;\r
112     line[0]=0;\r
113         \r
114 #undef fprintf\r
115     if(print_prefix && avc) \r
116         {\r
117         if (avc->parent_log_context_offset) \r
118                 {\r
119             AVClass** parent= *(AVClass***)(((uint8_t*)ptr) + avc->parent_log_context_offset);\r
120             if(parent && *parent)\r
121                 std::sprintf(line, "[%s @ %p] ", (*parent)->item_name(parent), parent);            \r
122         }\r
123         std::sprintf(line + strlen(line), "[%s @ %p] ", avc->item_name(ptr), ptr);\r
124     }\r
125 \r
126     std::vsprintf(line + strlen(line), fmt, vl);\r
127 \r
128     print_prefix = strlen(line) && line[strlen(line)-1] == '\n';\r
129         \r
130     //if(print_prefix && !strcmp(line, prev)){\r
131     //    count++;\r
132     //    if(is_atty==1)\r
133     //        fprintf(stderr, "    Last message repeated %d times\r", count);\r
134     //    return;\r
135     //}\r
136     //if(count>0){\r
137     //    fprintf(stderr, "    Last message repeated %d times\n", count);\r
138     //    count=0;\r
139     //}\r
140     strcpy(prev, line);\r
141     sanitize((uint8_t*)line);\r
142 \r
143         int len = strlen(line);\r
144         if(len > 0)\r
145                 line[len-1] = 0;\r
146         \r
147         if(level == AV_LOG_DEBUG)\r
148                 CASPAR_LOG(debug) << L"[ffmpeg] " << line;\r
149         else if(level == AV_LOG_INFO)\r
150                 CASPAR_LOG(info) << L"[ffmpeg] " << line;\r
151         else if(level == AV_LOG_WARNING)\r
152                 CASPAR_LOG(warning) << L"[ffmpeg] " << line;\r
153         else if(level == AV_LOG_ERROR)\r
154                 CASPAR_LOG(error) << L"[ffmpeg] " << line;\r
155         else if(level == AV_LOG_FATAL)\r
156                 CASPAR_LOG(fatal) << L"[ffmpeg] " << line;\r
157         else\r
158                 CASPAR_LOG(trace) << L"[ffmpeg] " << line;\r
159 \r
160     //colored_fputs(av_clip(level>>3, 0, 6), line);\r
161 }\r
162 \r
163 boost::thread_specific_ptr<bool>& get_disable_logging_for_thread()\r
164 {\r
165         static boost::thread_specific_ptr<bool> disable_logging_for_thread;\r
166 \r
167         return disable_logging_for_thread;\r
168 }\r
169 \r
170 void disable_logging_for_thread()\r
171 {\r
172         if (get_disable_logging_for_thread().get() == nullptr)\r
173                 get_disable_logging_for_thread().reset(new bool); // bool value does not matter\r
174 }\r
175 \r
176 bool is_logging_already_disabled_for_thread()\r
177 {\r
178         return get_disable_logging_for_thread().get() != nullptr;\r
179 }\r
180 \r
181 std::shared_ptr<void> temporary_disable_logging_for_thread(bool disable)\r
182 {\r
183         if (!disable || is_logging_already_disabled_for_thread())\r
184                 return std::shared_ptr<void>();\r
185 \r
186         disable_logging_for_thread();\r
187 \r
188         return std::shared_ptr<void>(nullptr, [] (void*)\r
189         {\r
190                 get_disable_logging_for_thread().release(); // Only works correctly if destructed in same thread as original caller.\r
191         });\r
192 }\r
193 \r
194 void log_for_thread(void* ptr, int level, const char* fmt, va_list vl)\r
195 {\r
196         //if (get_disable_logging_for_thread().get() == nullptr) // It does not matter what the value of the bool is\r
197                 log_callback(ptr, level, fmt, vl);\r
198 }\r
199 \r
200 //static int query_yadif_formats(AVFilterContext *ctx)\r
201 //{\r
202 //    static const int pix_fmts[] = {\r
203 //        PIX_FMT_YUV444P,\r
204 //        PIX_FMT_YUV422P,\r
205 //        PIX_FMT_YUV420P,\r
206 //        PIX_FMT_YUV410P,\r
207 //        PIX_FMT_YUV411P,\r
208 //        PIX_FMT_GRAY8,\r
209 //        PIX_FMT_YUVJ444P,\r
210 //        PIX_FMT_YUVJ422P,\r
211 //        PIX_FMT_YUVJ420P,\r
212 //        AV_NE( PIX_FMT_GRAY16BE, PIX_FMT_GRAY16LE ),\r
213 //        PIX_FMT_YUV440P,\r
214 //        PIX_FMT_YUVJ440P,\r
215 //        AV_NE( PIX_FMT_YUV444P16BE, PIX_FMT_YUV444P16LE ),\r
216 //        AV_NE( PIX_FMT_YUV422P16BE, PIX_FMT_YUV422P16LE ),\r
217 //        AV_NE( PIX_FMT_YUV420P16BE, PIX_FMT_YUV420P16LE ),\r
218 //        PIX_FMT_YUVA420P,\r
219 //        PIX_FMT_NONE\r
220 //    };\r
221 //    avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));\r
222 //\r
223 //    return 0;\r
224 //}\r
225 //\r
226 //#pragma warning (push)\r
227 //#pragma warning (disable : 4706)\r
228 //void fix_yadif_filter_format_query()\r
229 //{\r
230 //      AVFilter** filter = nullptr;\r
231 //    while((filter = av_filter_next(filter)) && *filter)\r
232 //      {\r
233 //              if(strstr((*filter)->name, "yadif") != 0)\r
234 //                      (*filter)->query_formats = query_yadif_formats;\r
235 //      }\r
236 //}\r
237 //#pragma warning (pop)\r
238 \r
239 void init()\r
240 {\r
241         av_lockmgr_register(ffmpeg_lock_callback);\r
242         av_log_set_callback(log_for_thread);\r
243 \r
244         avdevice_register_all();\r
245     avfilter_register_all();\r
246         //fix_yadif_filter_format_query();\r
247         av_register_all();\r
248     avformat_network_init();\r
249         avcodec_init();\r
250     avcodec_register_all();\r
251         \r
252         core::register_consumer_factory([](const core::parameters& params){return ffmpeg::create_consumer(params);});\r
253         core::register_producer_factory(create_producer);\r
254         core::register_thumbnail_producer_factory(create_thumbnail_producer);\r
255 }\r
256 \r
257 void uninit()\r
258 {\r
259         avfilter_uninit();\r
260     avformat_network_deinit();\r
261         av_lockmgr_register(nullptr);\r
262 }\r
263 \r
264 std::wstring make_version(unsigned int ver)\r
265 {\r
266         std::wstringstream str;\r
267         str << ((ver >> 16) & 0xFF) << L"." << ((ver >> 8) & 0xFF) << L"." << ((ver >> 0) & 0xFF);\r
268         return str.str();\r
269 }\r
270 \r
271 std::wstring get_avcodec_version()\r
272 {\r
273         return make_version(avcodec_version());\r
274 }\r
275 \r
276 std::wstring get_avformat_version()\r
277 {\r
278         return make_version(avformat_version());\r
279 }\r
280 \r
281 std::wstring get_avutil_version()\r
282 {\r
283         return make_version(avutil_version());\r
284 }\r
285 \r
286 std::wstring get_avfilter_version()\r
287 {\r
288         return make_version(avfilter_version());\r
289 }\r
290 \r
291 std::wstring get_swscale_version()\r
292 {\r
293         return make_version(swscale_version());\r
294 }\r
295 \r
296 }}