1 // VideoDecoderGst.cpp: Video decoding using Gstreamer.
2 //
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
4 // Free Software Foundation, Inc
5 //
6 // This program 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 // This program 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 this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
20 #include "VideoDecoderGst.h"
21 #include "MediaParserGst.h"
22 #include "GstUtil.h"
23
24 namespace gnash {
25 namespace media {
26 namespace gst {
27
28 // TODO: implement proper seeking.
29
VideoDecoderGst(GstCaps * caps,std::shared_ptr<HostInterface> eventHandler)30 VideoDecoderGst::VideoDecoderGst(GstCaps* caps, std::shared_ptr<HostInterface> eventHandler)
31 :
32 _width(0),
33 _height(0),
34 _eventHandler(eventHandler)
35 {
36 // init GStreamer. TODO: what about doing this in MediaHandlerGst ctor?
37 gst_init (nullptr, nullptr);
38
39 setup(caps);
40 }
41
42 int
width() const43 VideoDecoderGst::width() const
44 {
45 return _width;
46 }
47
48 int
height() const49 VideoDecoderGst::height() const
50 {
51 return _height;
52 }
53
54 // TODO: either use width and height or remove them!
VideoDecoderGst(videoCodecType codec_type,int,int,const std::uint8_t * extradata,size_t extradatasize,std::shared_ptr<HostInterface> eventHandler)55 VideoDecoderGst::VideoDecoderGst(videoCodecType codec_type,
56 int /*width*/, int /*height*/,
57 const std::uint8_t* extradata, size_t extradatasize,
58 std::shared_ptr<HostInterface> eventHandler)
59 :
60 _width(0),
61 _height(0),
62 _eventHandler(eventHandler)
63 {
64 // init GStreamer. TODO: what about doing this in MediaHandlerGst ctor?
65 gst_init (nullptr, nullptr);
66
67 GstCaps* caps;
68 switch (codec_type) {
69 case VIDEO_CODEC_H264:
70 {
71 caps = gst_caps_new_simple ("video/x-h264",
72 nullptr);
73
74 if (extradata && extradatasize) {
75
76 GstBuffer* buf = gst_buffer_new_and_alloc(extradatasize);
77 memcpy(GST_BUFFER_DATA(buf), extradata, extradatasize);
78 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, buf, NULL);
79 }
80 break;
81 }
82 case VIDEO_CODEC_H263:
83 caps = gst_caps_new_simple ("video/x-flash-video",
84 nullptr);
85 break;
86 case VIDEO_CODEC_VP6:
87 caps = gst_caps_new_simple ("video/x-vp6-flash",
88 nullptr);
89 break;
90 case VIDEO_CODEC_VP6A:
91 caps = gst_caps_new_simple ("video/x-vp6-alpha",
92 nullptr);
93 break;
94 case VIDEO_CODEC_SCREENVIDEO:
95 case VIDEO_CODEC_SCREENVIDEO2:
96 caps = gst_caps_new_simple ("video/x-flash-screen",
97 nullptr);
98 break;
99 case NO_VIDEO_CODEC:
100 throw MediaException(_("Video codec is zero. Streaming video expected later."));
101 break;
102 default:
103 boost::format msg = boost::format(_("No support for video codec %s.")) %
104 codec_type;
105 throw MediaException(msg.str());
106
107 return;
108 }
109
110 setup(caps);
111
112 }
113
114
~VideoDecoderGst()115 VideoDecoderGst::~VideoDecoderGst()
116 {
117 swfdec_gst_decoder_push_eos(&_decoder);
118 swfdec_gst_decoder_finish(&_decoder);
119 }
120
121 void
setup(GstCaps * srccaps)122 VideoDecoderGst::setup(GstCaps* srccaps)
123 {
124 if (!srccaps) {
125 throw MediaException(_("VideoDecoderGst: internal error "
126 "(caps creation failed)"));
127 }
128
129 bool success = GstUtil::check_missing_plugins(srccaps, _eventHandler.get());
130 if (!success) {
131 GstStructure* sct = gst_caps_get_structure(srccaps, 0);
132 std::string type(gst_structure_get_name(sct));
133 std::string msg = (boost::format(_("Couldn't find a plugin for "
134 "video type %s!")) % type).str();
135
136 if (type == "video/x-flash-video" || type == "video/x-h264") {
137 msg += _(" Please make sure you have gstreamer-ffmpeg installed.");
138 }
139
140 gst_caps_unref(srccaps);
141
142 throw MediaException(msg);
143 }
144
145 GstCaps* sinkcaps = gst_caps_new_simple("video/x-raw-rgb", "bpp",
146 G_TYPE_INT, 24,
147 "depth", G_TYPE_INT, 24,
148 NULL);
149
150 if (!sinkcaps) {
151 throw MediaException(_("VideoDecoderGst: internal error "
152 "(caps creation failed)"));
153 }
154
155 bool rv = swfdec_gst_decoder_init (&_decoder, srccaps, sinkcaps,
156 "ffmpegcolorspace", NULL);
157 if (!rv) {
158 GstStructure* sct = gst_caps_get_structure(srccaps, 0);
159 std::string type(gst_structure_get_name(sct));
160 std::string msg = (boost::format(
161 _("VideoDecoderGst: initialisation failed for video type %s!"))
162 % type).str();
163 throw MediaException(msg);
164 }
165
166 gst_caps_unref (srccaps);
167 gst_caps_unref (sinkcaps);
168 }
169
170 void
push(const EncodedVideoFrame & frame)171 VideoDecoderGst::push(const EncodedVideoFrame& frame)
172 {
173 GstBuffer* buffer;
174
175 EncodedExtraGstData* extradata =
176 dynamic_cast<EncodedExtraGstData*>(frame.extradata.get());
177
178 if (extradata) {
179 buffer = extradata->buffer;
180 } else {
181 buffer = gst_buffer_new();
182
183 GST_BUFFER_DATA(buffer) = const_cast<std::uint8_t*>(frame.data());
184 GST_BUFFER_SIZE(buffer) = frame.dataSize();
185 GST_BUFFER_OFFSET(buffer) = frame.frameNum();
186 GST_BUFFER_TIMESTAMP(buffer) = GST_CLOCK_TIME_NONE;
187 GST_BUFFER_DURATION(buffer) = GST_CLOCK_TIME_NONE;
188 }
189
190 bool success = swfdec_gst_decoder_push(&_decoder, buffer);
191 if (!success) {
192 log_error(_("VideoDecoderGst: buffer push failed."));
193 }
194 }
195
196
197 std::unique_ptr<image::GnashImage>
pop()198 VideoDecoderGst::pop()
199 {
200 GstBuffer * buffer = swfdec_gst_decoder_pull (&_decoder);
201
202 if (!buffer) {
203 return std::unique_ptr<image::GnashImage>();
204 }
205
206 GstCaps* caps = gst_buffer_get_caps(buffer);
207
208 assert(gst_caps_get_size(caps) == 1);
209
210 GstStructure* structure = gst_caps_get_structure (caps, 0);
211
212 gst_structure_get_int (structure, "width", &_width);
213 gst_structure_get_int (structure, "height", &_height);
214
215 gst_caps_unref(caps);
216
217 std::unique_ptr<image::GnashImage> ret(new gnashGstBuffer(buffer, _width, _height));
218
219 return ret;
220 }
221
222
223 bool
peek()224 VideoDecoderGst::peek()
225 {
226 return !g_queue_is_empty (_decoder.queue);
227 }
228
229
230 } // namespace gnash::media::gst
231 } // namespace gnash::media
232 } // namespace gnash
233