]> git.sesse.net Git - casparcg/blob - modules/ffmpeg/producer/video/video_decoder.cpp
2.0.0.2: Removed fps check.
[casparcg] / modules / ffmpeg / producer / video / video_decoder.cpp
1 #include "../../stdafx.h"\r
2 \r
3 #include "video_decoder.h"\r
4 \r
5 #include <common/memory/safe_ptr.h>\r
6 \r
7 #include <core/video_format.h>\r
8 \r
9 #include <core/producer/frame/basic_frame.h>\r
10 #include <core/producer/frame/write_frame.h>\r
11 #include <core/producer/frame/image_transform.h>\r
12 \r
13 #include <tbb/parallel_for.h>\r
14 \r
15 #include <algorithm>\r
16 \r
17 #if defined(_MSC_VER)\r
18 #pragma warning (push)\r
19 #pragma warning (disable : 4244)\r
20 #endif\r
21 extern "C" \r
22 {\r
23         #define __STDC_CONSTANT_MACROS\r
24         #define __STDC_LIMIT_MACROS\r
25         #include <libswscale/swscale.h>\r
26         #include <libavformat/avformat.h>\r
27 }\r
28 #if defined(_MSC_VER)\r
29 #pragma warning (pop)\r
30 #endif\r
31 \r
32 namespace caspar {\r
33         \r
34 core::pixel_format::type get_pixel_format(PixelFormat pix_fmt)\r
35 {\r
36         switch(pix_fmt)\r
37         {\r
38                 case PIX_FMT_BGRA:              return core::pixel_format::bgra;\r
39                 case PIX_FMT_ARGB:              return core::pixel_format::argb;\r
40                 case PIX_FMT_RGBA:              return core::pixel_format::rgba;\r
41                 case PIX_FMT_ABGR:              return core::pixel_format::abgr;\r
42                 case PIX_FMT_YUV444P:   return core::pixel_format::ycbcr;\r
43                 case PIX_FMT_YUV422P:   return core::pixel_format::ycbcr;\r
44                 case PIX_FMT_YUV420P:   return core::pixel_format::ycbcr;\r
45                 case PIX_FMT_YUV411P:   return core::pixel_format::ycbcr;\r
46                 case PIX_FMT_YUV410P:   return core::pixel_format::ycbcr;\r
47                 case PIX_FMT_YUVA420P:  return core::pixel_format::ycbcra;\r
48                 default:                                return core::pixel_format::invalid;\r
49         }\r
50 }\r
51 \r
52 core::pixel_format_desc get_pixel_format_desc(PixelFormat pix_fmt, size_t width, size_t height)\r
53 {\r
54         // Get linesizes\r
55         AVPicture dummy_pict;   \r
56         avpicture_fill(&dummy_pict, nullptr, pix_fmt, width, height);\r
57 \r
58         core::pixel_format_desc desc;\r
59         desc.pix_fmt = get_pixel_format(pix_fmt);\r
60                 \r
61         switch(desc.pix_fmt)\r
62         {\r
63         case core::pixel_format::bgra:\r
64         case core::pixel_format::argb:\r
65         case core::pixel_format::rgba:\r
66         case core::pixel_format::abgr:\r
67                 {\r
68                         desc.planes.push_back(core::pixel_format_desc::plane(dummy_pict.linesize[0]/4, height, 4));                                             \r
69                         return desc;\r
70                 }\r
71         case core::pixel_format::ycbcr:\r
72         case core::pixel_format::ycbcra:\r
73                 {               \r
74                         // Find chroma height\r
75                         size_t size2 = dummy_pict.data[2] - dummy_pict.data[1];\r
76                         size_t h2 = size2/dummy_pict.linesize[1];                       \r
77 \r
78                         desc.planes.push_back(core::pixel_format_desc::plane(dummy_pict.linesize[0], height, 1));\r
79                         desc.planes.push_back(core::pixel_format_desc::plane(dummy_pict.linesize[1], h2, 1));\r
80                         desc.planes.push_back(core::pixel_format_desc::plane(dummy_pict.linesize[2], h2, 1));\r
81 \r
82                         if(desc.pix_fmt == core::pixel_format::ycbcra)                                          \r
83                                 desc.planes.push_back(core::pixel_format_desc::plane(dummy_pict.linesize[3], height, 1));       \r
84                         return desc;\r
85                 }               \r
86         default:                \r
87                 desc.pix_fmt = core::pixel_format::invalid;\r
88                 return desc;\r
89         }\r
90 }\r
91 \r
92 struct video_decoder::implementation : boost::noncopyable\r
93 {       \r
94         std::shared_ptr<core::frame_factory> frame_factory_;\r
95         std::shared_ptr<SwsContext> sws_context_;\r
96 \r
97         AVCodecContext* codec_context_;\r
98 \r
99         const int width_;\r
100         const int height_;\r
101         const PixelFormat pix_fmt_;\r
102         core::pixel_format_desc desc_;\r
103 \r
104 public:\r
105         explicit implementation(AVCodecContext* codec_context, const safe_ptr<core::frame_factory>& frame_factory) \r
106                 : frame_factory_(frame_factory)\r
107                 , codec_context_(codec_context)\r
108                 , width_(codec_context_->width)\r
109                 , height_(codec_context_->height)\r
110                 , pix_fmt_(codec_context_->pix_fmt)\r
111                 , desc_(get_pixel_format_desc(pix_fmt_, width_, height_))\r
112         {\r
113                 if(desc_.pix_fmt == core::pixel_format::invalid)\r
114                 {\r
115                         CASPAR_LOG(warning) << "Hardware accelerated color transform not supported.";\r
116 \r
117                         desc_ = get_pixel_format_desc(PIX_FMT_BGRA, width_, height_);\r
118                         double param;\r
119                         sws_context_.reset(sws_getContext(width_, height_, pix_fmt_, width_, height_, PIX_FMT_BGRA, SWS_BILINEAR, nullptr, nullptr, &param), sws_freeContext);\r
120                         if(!sws_context_)\r
121                                 BOOST_THROW_EXCEPTION(operation_failed() <<\r
122                                                                           msg_info("Could not create software scaling context.") << \r
123                                                                           boost::errinfo_api_function("sws_getContext"));\r
124                 }\r
125         }\r
126         \r
127         safe_ptr<core::write_frame> execute(const aligned_buffer& video_packet)\r
128         {                               \r
129                 safe_ptr<AVFrame> decoded_frame(avcodec_alloc_frame(), av_free);\r
130 \r
131                 int frame_finished = 0;\r
132                 const int result = avcodec_decode_video(codec_context_, decoded_frame.get(), &frame_finished, video_packet.data(), video_packet.size());\r
133                 \r
134                 if(result < 0)\r
135                         BOOST_THROW_EXCEPTION(invalid_operation() << msg_info("avcodec_decode_video failed"));\r
136                 \r
137                 auto write = frame_factory_->create_frame(desc_);\r
138                 if(sws_context_ == nullptr)\r
139                 {\r
140                         tbb::parallel_for(0, static_cast<int>(desc_.planes.size()), 1, [&](int n)\r
141                         {\r
142                                 auto plane            = desc_.planes[n];\r
143                                 auto result           = write->image_data(n).begin();\r
144                                 auto decoded          = decoded_frame->data[n];\r
145                                 auto decoded_linesize = decoded_frame->linesize[n];\r
146                                 \r
147                                 tbb::parallel_for(0, static_cast<int>(desc_.planes[n].height), 1, [&](int y)\r
148                                 {\r
149                                         std::copy_n(decoded + y*decoded_linesize, plane.linesize, result + y*plane.linesize);\r
150                                 });\r
151                         });\r
152                 }\r
153                 else\r
154                 {\r
155                         safe_ptr<AVFrame> av_frame(avcodec_alloc_frame(), av_free);     \r
156                         avcodec_get_frame_defaults(av_frame.get());                     \r
157                         avpicture_fill(reinterpret_cast<AVPicture*>(av_frame.get()), write->image_data().begin(), PIX_FMT_BGRA, width_, height_);\r
158                  \r
159                         sws_scale(sws_context_.get(), decoded_frame->data, decoded_frame->linesize, 0, height_, av_frame->data, av_frame->linesize);    \r
160                 }       \r
161 \r
162                 if(codec_context_->codec_id == CODEC_ID_DVVIDEO && frame_factory_->get_video_format_desc().mode == core::video_mode::upper)\r
163                         write->get_image_transform().set_fill_translation(0.0f, 1.0/static_cast<double>(height_));\r
164 \r
165                 return write;\r
166         }\r
167 };\r
168 \r
169 video_decoder::video_decoder(AVCodecContext* codec_context, const safe_ptr<core::frame_factory>& frame_factory) : impl_(new implementation(codec_context, frame_factory)){}\r
170 safe_ptr<core::write_frame> video_decoder::execute(const aligned_buffer& video_packet){return impl_->execute(video_packet);}\r
171 \r
172 }