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