]> git.sesse.net Git - casparcg/blob - modules/ffmpeg/producer/video/video_decoder.cpp
[ffmpeg] Removed FFMPEG_Resource to simplify code and documented streaming video...
[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 = std::shared_ptr<AVFrame>(av_frame_alloc(), [](AVFrame* frame)
116                 {
117                         av_frame_free(&frame);
118                 });
119                 
120                 int frame_finished = 0;
121                 THROW_ON_ERROR2(avcodec_decode_video2(codec_context_.get(), decoded_frame.get(), &frame_finished, pkt.get()), "[video_decoder]");
122                 
123                 // If a decoder consumes less then the whole packet then something is wrong
124                 // that might be just harmless padding at the end, or a problem with the
125                 // AVParser or demuxer which puted more then one frame in a AVPacket.
126
127                 if(frame_finished == 0) 
128                         return nullptr;
129
130                 is_progressive_ = !decoded_frame->interlaced_frame;
131
132                 if(decoded_frame->repeat_pict > 0)
133                         CASPAR_LOG(warning) << "[video_decoder] Field repeat_pict not implemented.";
134                 
135                 ++file_frame_number_;
136
137                 // This ties the life of the decoded_frame to the packet that it came from. For the
138                 // current version of ffmpeg (0.8 or c17808c) the RAW_VIDEO codec returns frame data
139                 // owned by the packet.
140                 return std::shared_ptr<AVFrame>(decoded_frame.get(), [decoded_frame, pkt](AVFrame*){});
141         }
142         
143         bool ready() const
144         {
145                 return packets_.size() >= 8;
146         }
147
148         uint32_t nb_frames() const
149         {
150                 return std::max(nb_frames_, static_cast<uint32_t>(file_frame_number_));
151         }
152
153         std::wstring print() const
154         {               
155                 return L"[video-decoder] " + u16(codec_context_->codec->long_name);
156         }
157 };
158
159 video_decoder::video_decoder(const spl::shared_ptr<AVFormatContext>& context) : impl_(new implementation(context)){}
160 void video_decoder::push(const std::shared_ptr<AVPacket>& packet){impl_->push(packet);}
161 std::shared_ptr<AVFrame> video_decoder::poll(){return impl_->poll();}
162 bool video_decoder::ready() const{return impl_->ready();}
163 int video_decoder::width() const{return impl_->width_;}
164 int video_decoder::height() const{return impl_->height_;}
165 uint32_t video_decoder::nb_frames() const{return impl_->nb_frames();}
166 uint32_t video_decoder::file_frame_number() const{return static_cast<uint32_t>(impl_->file_frame_number_);}
167 bool    video_decoder::is_progressive() const{return impl_->is_progressive_;}
168 std::wstring video_decoder::print() const{return impl_->print();}
169
170 }}