]> git.sesse.net Git - casparcg/blob - core/producer/ffmpeg/video/video_transformer.cpp
d88a7347d29483e2e170b4f9572dc4a0b79c44b8
[casparcg] / core / producer / ffmpeg / video / video_transformer.cpp
1 #include "../../../stdafx.h"\r
2 \r
3 #include "video_transformer.h"\r
4 \r
5 #include "../../../frame/frame_format.h"\r
6 #include "../../../../common/image/image.h"\r
7 #include "../../../frame/gpu_frame.h"\r
8 #include "../../../frame/gpu_frame.h"\r
9 #include "../../../frame/frame_factory.h"\r
10 \r
11 #include <tbb/parallel_for.h>\r
12 #include <tbb/atomic.h>\r
13 #include <tbb/mutex.h>\r
14 #include <tbb/concurrent_queue.h>\r
15 #include <tbb/scalable_allocator.h>\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 }\r
27 #if defined(_MSC_VER)\r
28 #pragma warning (pop)\r
29 #endif\r
30 \r
31 namespace caspar{ namespace ffmpeg{\r
32 \r
33 typedef std::shared_ptr<SwsContext> SwsContextPtr;\r
34 \r
35 // TODO: Remove and do copy right into frame\r
36 struct fill_frame\r
37 {\r
38         fill_frame(size_t width, size_t height) \r
39                 : frame(avcodec_alloc_frame(), av_free), buffer(static_cast<unsigned char*>(scalable_aligned_malloc(width*height*4, 16)), scalable_aligned_free)\r
40         {       \r
41                 avpicture_fill(reinterpret_cast<AVPicture*>(frame.get()), buffer.get(), PIX_FMT_BGRA, width, height);\r
42         }\r
43         const AVFramePtr        frame;\r
44         const std::shared_ptr<unsigned char>            buffer;\r
45 };\r
46 typedef std::shared_ptr<fill_frame> fill_frame_ptr;\r
47 \r
48 struct video_transformer::implementation : boost::noncopyable\r
49 {\r
50         video_packet_ptr execute(const video_packet_ptr video_packet)\r
51         {                               \r
52                 assert(video_packet);\r
53 \r
54                 if(!sws_context_)\r
55                 {\r
56                         double param;\r
57                         sws_context_.reset(sws_getContext(video_packet->codec_context->width, video_packet->codec_context->height, video_packet->codec_context->pix_fmt, video_packet->format_desc.width, video_packet->format_desc.height, \r
58                                                                                                 PIX_FMT_BGRA, SWS_BILINEAR, nullptr, nullptr, &param), sws_freeContext);\r
59                 }\r
60                 \r
61                 //AVFrame avFrame;      \r
62                 //avcodec_get_frame_defaults(avFrame);\r
63                 //avpicture_fill(reinterpret_cast<AVPicture*>(&avFrame), video_packet->frame->data(), PIX_FMT_BGRA, video_packet->frameFormat.width, video_packet->frameFormat.height);\r
64                 \r
65                 auto format_desc = video_packet->format_desc;\r
66 \r
67                 fill_frame fill_frame(format_desc.width, format_desc.height);\r
68                 video_packet->frame = factory_->create_frame(format_desc.width, format_desc.height);\r
69                 int result = sws_scale(sws_context_.get(), video_packet->decoded_frame->data, video_packet->decoded_frame->linesize, 0, video_packet->codec_context->height, fill_frame.frame->data, fill_frame.frame->linesize);\r
70                 video_packet->decoded_frame.reset(); // Free memory\r
71                 \r
72                 if(video_packet->codec->id == CODEC_ID_DVVIDEO) // Move up one field\r
73                 {\r
74                         size_t size = format_desc.width * format_desc.height * 4;\r
75                         size_t linesize = format_desc.width * 4;\r
76                         common::image::copy(video_packet->frame->data(), fill_frame.buffer.get() + linesize, size - linesize);\r
77                         common::image::clear(video_packet->frame->data() + size - linesize, linesize);\r
78                 }\r
79                 else\r
80                 {\r
81                          // This copy should be unnecessary. But it seems that when mapping the frame memory to an avframe for scaling there are some artifacts in the picture. See line 59-61.\r
82                         common::image::copy(video_packet->frame->data(), fill_frame.buffer.get(), video_packet->frame->size());\r
83                 }\r
84 \r
85                 return video_packet;    \r
86         }\r
87 \r
88         frame_factory_ptr factory_;\r
89         SwsContextPtr sws_context_;\r
90 };\r
91 \r
92 video_transformer::video_transformer() : impl_(new implementation()){}\r
93 video_packet_ptr video_transformer::execute(const video_packet_ptr& video_packet){return impl_->execute(video_packet);}\r
94 void video_transformer::initialize(const frame_factory_ptr& factory){impl_->factory_ = factory; }\r
95 }}