]> git.sesse.net Git - casparcg/blob - modules/ffmpeg/producer/video/video_decoder.cpp
10d7aee98829a6886b0b4055de5f544ab40554f0
[casparcg] / modules / ffmpeg / producer / video / video_decoder.cpp
1 /*
2 * Copyright 2013 Sveriges Television AB http://casparcg.com/
3 *
4 * This file is part of CasparCG (www.casparcg.com).
5 *
6 * CasparCG is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * CasparCG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author: Robert Nagy, ronag89@gmail.com
20 */
21
22 #include "../../StdAfx.h"
23
24 #include "video_decoder.h"
25
26 #include "../util/util.h"
27
28 #include "../../ffmpeg_error.h"
29
30 #include <core/frame/frame_transform.h>
31 #include <core/frame/frame_factory.h>
32
33 #include <boost/range/algorithm_ext/push_back.hpp>
34 #include <boost/filesystem.hpp>
35
36 #include <queue>
37
38 #if defined(_MSC_VER)
39 #pragma warning (push)
40 #pragma warning (disable : 4244)
41 #endif
42 extern "C"
43 {
44         #include <libavcodec/avcodec.h>
45         #include <libavformat/avformat.h>
46 }
47 #if defined(_MSC_VER)
48 #pragma warning (pop)
49 #endif
50
51 namespace caspar { namespace ffmpeg {
52
53 struct video_decoder::implementation : boost::noncopyable
54 {
55         int                                                                             index_                          = -1;
56         const spl::shared_ptr<AVCodecContext>   codec_context_;
57
58         std::queue<spl::shared_ptr<AVPacket>>   packets_;
59
60         const uint32_t                                                  nb_frames_;
61
62         const int                                                               width_                          = codec_context_->width;
63         const int                                                               height_                         = codec_context_->height;
64         bool                                                                    is_progressive_;
65
66         tbb::atomic<uint32_t>                                   file_frame_number_;
67
68 public:
69         explicit implementation(const spl::shared_ptr<AVFormatContext>& context)
70                 : codec_context_(open_codec(*context, AVMEDIA_TYPE_VIDEO, index_, false))
71                 , nb_frames_(static_cast<uint32_t>(context->streams[index_]->nb_frames))
72         {
73                 file_frame_number_ = 0;
74
75                 codec_context_->refcounted_frames = 1;
76         }
77
78         void push(const std::shared_ptr<AVPacket>& packet)
79         {
80                 if(!packet)
81                         return;
82
83                 if(packet->stream_index == index_ || packet->data == nullptr)
84                         packets_.push(spl::make_shared_ptr(packet));
85         }
86
87         std::shared_ptr<AVFrame> poll()
88         {
89                 if(packets_.empty())
90                         return nullptr;
91
92                 auto packet = packets_.front();
93
94                 if(packet->data == nullptr)
95                 {
96                         if(codec_context_->codec->capabilities & CODEC_CAP_DELAY)
97                         {
98                                 auto video = decode(packet);
99                                 if(video)
100                                         return video;
101                         }
102
103                         packets_.pop();
104                         file_frame_number_ = static_cast<uint32_t>(packet->pos);
105                         avcodec_flush_buffers(codec_context_.get());
106                         return flush_video();
107                 }
108
109                 packets_.pop();
110                 return decode(packet);
111         }
112
113         std::shared_ptr<AVFrame> decode(spl::shared_ptr<AVPacket> pkt)
114         {
115                 auto decoded_frame = create_frame();
116
117                 int frame_finished = 0;
118                 THROW_ON_ERROR2(avcodec_decode_video2(codec_context_.get(), decoded_frame.get(), &frame_finished, pkt.get()), "[video_decoder]");
119
120                 // If a decoder consumes less then the whole packet then something is wrong
121                 // that might be just harmless padding at the end, or a problem with the
122                 // AVParser or demuxer which puted more then one frame in a AVPacket.
123
124                 if(frame_finished == 0)
125                         return nullptr;
126
127                 is_progressive_ = !decoded_frame->interlaced_frame;
128
129                 if(decoded_frame->repeat_pict > 0)
130                         CASPAR_LOG(warning) << "[video_decoder] Field repeat_pict not implemented.";
131
132                 ++file_frame_number_;
133
134                 // This ties the life of the decoded_frame to the packet that it came from. For the
135                 // current version of ffmpeg (0.8 or c17808c) the RAW_VIDEO codec returns frame data
136                 // owned by the packet.
137                 return std::shared_ptr<AVFrame>(decoded_frame.get(), [decoded_frame, pkt](AVFrame*){});
138         }
139
140         bool ready() const
141         {
142                 return packets_.size() >= 8;
143         }
144
145         uint32_t nb_frames() const
146         {
147                 return std::max(nb_frames_, static_cast<uint32_t>(file_frame_number_));
148         }
149
150         std::wstring print() const
151         {
152                 return L"[video-decoder] " + u16(codec_context_->codec->long_name);
153         }
154 };
155
156 video_decoder::video_decoder(const spl::shared_ptr<AVFormatContext>& context) : impl_(new implementation(context)){}
157 void video_decoder::push(const std::shared_ptr<AVPacket>& packet){impl_->push(packet);}
158 std::shared_ptr<AVFrame> video_decoder::poll(){return impl_->poll();}
159 bool video_decoder::ready() const{return impl_->ready();}
160 int video_decoder::width() const{return impl_->width_;}
161 int video_decoder::height() const{return impl_->height_;}
162 uint32_t video_decoder::nb_frames() const{return impl_->nb_frames();}
163 uint32_t video_decoder::file_frame_number() const{return static_cast<uint32_t>(impl_->file_frame_number_);}
164 bool    video_decoder::is_progressive() const{return impl_->is_progressive_;}
165 std::wstring video_decoder::print() const{return impl_->print();}
166
167 }}