cleanup a few warnings.
[gnash.git] / libcore / Video.cpp
blobc45d20ecd6084ee2967cdda8636f7d0306e71b0c
1 // Video.cpp: Draw individual video frames, for Gnash.
2 //
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
4 // 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.
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 //
22 #include "MovieClip.h"
23 #include "Video.h"
24 #include "DefineVideoStreamTag.h"
25 #include "fn_call.h"
26 #include "as_value.h"
27 #include "NetStream_as.h"
28 #include "NativeFunction.h"
29 #include "movie_root.h"
30 #include "VM.h"
31 #include "MediaHandler.h" // for setting up embedded video decoder
32 #include "VideoDecoder.h" // for setting up embedded video decoder
33 #include "namedStrings.h"
34 #include "Global_as.h"
35 #include "Renderer.h"
36 #include "RunResources.h"
38 // Define this to get debug logging during embedded video decoding
39 //#define DEBUG_EMBEDDED_VIDEO_DECODING
41 namespace gnash {
43 namespace {
44 as_object* getVideoInterface(as_object& where);
45 void attachPrototypeProperties(as_object& o);
46 void attachVideoInterface(as_object& o);
47 as_value video_ctor(const fn_call& fn);
48 as_value video_attach(const fn_call& fn);
49 as_value video_clear(const fn_call& fn);
50 as_value video_deblocking(const fn_call& fn);
51 as_value video_smoothing(const fn_call& fn);
52 as_value video_width(const fn_call& fn);
53 as_value video_height(const fn_call& fn);
56 Video::Video(as_object* object,
57 const SWF::DefineVideoStreamTag* def, DisplayObject* parent)
59 DisplayObject(getRoot(*object), object, parent),
60 m_def(def),
61 _ns(0),
62 _embeddedStream(m_def),
63 _lastDecodedVideoFrameNum(-1),
64 _lastDecodedVideoFrame(),
65 _smoothing(false)
67 assert(object);
68 assert(def);
70 media::MediaHandler* mh = getRunResources(*object).mediaHandler();
71 if (!mh) {
72 LOG_ONCE( log_error(_("No Media handler registered, "
73 "won't be able to decode embedded video")) );
74 return;
77 media::VideoInfo* info = m_def->getVideoInfo();
78 if (!info) {
79 log_error(_("No Video info in video definition"));
80 return;
83 try {
84 _decoder = mh->createVideoDecoder(*info);
86 catch (MediaException &e) {
87 log_error("Could not create Video Decoder: %s", e.what());
91 Video::~Video()
95 int
96 Video::width() const
98 if (_ns) return _ns->videoWidth();
99 return 0;
103 Video::height() const
105 if (_ns) return _ns->videoHeight();
106 return 0;
109 void
110 Video::clear()
112 // Clear the current image only if paused.
113 if (_ns && _ns->playbackState() == PlayHead::PLAY_PAUSED)
115 set_invalidated();
116 _lastDecodedVideoFrame.reset();
120 void
121 Video::display(Renderer& renderer)
123 assert(m_def);
125 SWFMatrix m = getWorldMatrix();
126 const SWFRect& bounds = m_def->bounds();
128 GnashImage* img = getVideoFrame();
129 if (img)
131 renderer.drawVideoFrame(img, &m, &bounds, _smoothing);
134 clear_invalidated();
137 GnashImage*
138 Video::getVideoFrame()
142 // If this is a video from a NetStream_as object, retrieve a video
143 // frame from there.
144 if (_ns)
146 std::auto_ptr<GnashImage> tmp = _ns->get_video();
147 if ( tmp.get() ) _lastDecodedVideoFrame = tmp;
150 // If this is a video from a VideoFrame tag, retrieve a video frame
151 // from there.
152 else if (_embeddedStream)
155 // Don't try to do anything if there is no decoder. If it was
156 // never constructed (most likely), we'll return nothing,
157 // otherwise the last decoded frame.
158 if (!_decoder.get()) return _lastDecodedVideoFrame.get();
160 int current_frame = get_ratio();
162 #ifdef DEBUG_EMBEDDED_VIDEO_DECODING
163 log_debug("Video instance %s need display video frame (ratio) %d",
164 getTarget(), current_frame);
165 #endif
167 // If current frame is the same then last decoded
168 // we don't need to decode more
169 if ( _lastDecodedVideoFrameNum == current_frame )
171 #ifdef DEBUG_EMBEDDED_VIDEO_DECODING
172 log_debug(" current frame == _lastDecodedVideoFrameNum (%d)",
173 current_frame);
174 #endif
175 return _lastDecodedVideoFrame.get();
178 int from_frame = _lastDecodedVideoFrameNum < 0 ?
179 0 : _lastDecodedVideoFrameNum + 1;
181 // If current frame is smaller then last decoded frame
182 // we restart decoding from scratch
183 if ( current_frame < _lastDecodedVideoFrameNum )
185 #ifdef DEBUG_EMBEDDED_VIDEO_DECODING
186 log_debug(" current frame (%d) < _lastDecodedVideoFrameNum (%d)",
187 current_frame, _lastDecodedVideoFrameNum);
188 #endif
189 from_frame = 0;
192 // Reset last decoded video frame number now, so it's correct
193 // on early return (ie: nothing more to decode)
194 _lastDecodedVideoFrameNum = current_frame;
196 #ifdef DEBUG_EMBEDDED_VIDEO_DECODING
197 log_debug(" decoding embedded frames from %d to %d for Video "
198 "object %s", from_frame, current_frame, getTarget());
199 #endif
201 typedef SWF::DefineVideoStreamTag::EmbeddedFrames EncodedFrames;
203 EncodedFrames toDecode;
204 m_def->getEncodedFrameSlice(from_frame, current_frame, toDecode);
206 // Nothing more to decode, return last decoded (possibly null)
207 if ( toDecode.empty() )
209 #ifdef DEBUG_EMBEDDED_VIDEO_DECODING
210 log_debug(" no defined frames, we'll return last one");
211 #endif
212 return _lastDecodedVideoFrame.get();
215 for (EncodedFrames::iterator it=toDecode.begin(),
216 itEnd=toDecode.end(); it!=itEnd; ++it)
218 media::EncodedVideoFrame* frame = *it;
219 #ifdef DEBUG_EMBEDDED_VIDEO_DECODING
220 log_debug(" pushing frame %d to decoder", frame->frameNum());
221 #endif
222 _decoder->push(*frame);
225 _lastDecodedVideoFrame = _decoder->pop();
228 return _lastDecodedVideoFrame.get();
231 void
232 Video::construct(as_object* /*init*/)
234 // For soft references.
235 saveOriginalTarget();
239 void
240 Video::add_invalidated_bounds(InvalidatedRanges& ranges, bool force)
242 if (!force && !invalidated()) return; // no need to redraw
244 ranges.add(m_old_invalidated_ranges);
246 assert (m_def);
248 SWFRect bounds;
249 bounds.expand_to_transformed_rect(getWorldMatrix(), m_def->bounds());
251 ranges.add(bounds.getRange());
254 void
255 Video::setStream(NetStream_as* ns)
257 _ns = ns;
258 _ns->setInvalidatedVideo(this);
261 // extern (used by Global.cpp)
262 void
263 video_class_init(as_object& global, const ObjectURI& uri)
265 // This is going to be the global Video "class"/"function"
266 Global_as& gl = getGlobal(global);
267 as_object* proto = gl.createObject();
268 as_object* cl = gl.createClass(&video_ctor, proto);
269 attachVideoInterface(*proto);
271 // Register _global.Video
272 global.init_member(uri, cl, as_object::DefaultFlags);
275 void
276 registerVideoNative(as_object& global)
278 VM& vm = getVM(global);
279 vm.registerNative(video_ctor, 667, 0);
280 vm.registerNative(video_attach, 667, 1);
281 vm.registerNative(video_clear, 667, 2);
284 SWFRect
285 Video::getBounds() const
287 if (_embeddedStream) return m_def->bounds();
289 // TODO: return the bounds of the dynamically
290 // loaded video if not embedded ?
291 return SWFRect();
294 void
295 Video::markOwnResources() const
297 if (_ns) _ns->setReachable();
300 as_object*
301 createVideoObject(Global_as& gl)
303 // TODO: how to use this for AS3 as well?
304 // Turn into constructBuiltin()
305 as_object* obj = getObjectWithPrototype(gl, NSV::CLASS_VIDEO);
306 as_object* proto = obj->get_prototype();
307 if (proto) attachPrototypeProperties(*proto);
308 return obj;
311 namespace {
313 void
314 attachVideoInterface(as_object& o)
316 VM& vm = getVM(o);
317 o.init_member("attachVideo", vm.getNative(667, 1));
318 o.init_member("clear", vm.getNative(667, 2));
321 void
322 attachPrototypeProperties(as_object& proto)
324 const int protect = PropFlags::dontDelete;
326 proto.init_property("deblocking", &video_deblocking, &video_deblocking,
327 protect);
328 proto.init_property("smoothing", &video_smoothing, &video_smoothing,
329 protect);
331 const int flags = PropFlags::dontDelete |
332 PropFlags::readOnly;
334 proto.init_property("height", &video_height, &video_height, flags);
335 proto.init_property("width", &video_width, &video_width, flags);
338 as_value
339 video_attach(const fn_call& fn)
341 Video* video = ensure<IsDisplayObject<Video> >(fn);
343 if (fn.nargs < 1)
345 IF_VERBOSE_ASCODING_ERRORS(
346 log_aserror(_("attachVideo needs 1 arg"));
348 return as_value();
351 as_object* obj = fn.arg(0).to_object(getGlobal(fn));
352 NetStream_as* ns;
354 if (isNativeType(obj, ns)) {
355 video->setStream(ns);
357 else {
358 IF_VERBOSE_ASCODING_ERRORS(
359 log_aserror(_("attachVideo(%s) first arg is not a NetStream instance"),
360 fn.arg(0));
363 return as_value();
366 as_value
367 video_deblocking(const fn_call& fn)
369 Video* video = ensure<IsDisplayObject<Video> >(fn);
370 UNUSED(video);
372 log_unimpl("Video.deblocking");
373 return as_value();
376 as_value
377 video_smoothing(const fn_call& fn)
379 Video* video = ensure<IsDisplayObject<Video> >(fn);
381 if (!fn.nargs) return as_value(video->smoothing());
383 bool smooth = fn.arg(0).to_bool();
385 video->setSmoothing(smooth);
387 return as_value();
390 as_value
391 video_width(const fn_call& fn)
393 Video* video = ensure<IsDisplayObject<Video> >(fn);
394 return as_value(video->width());
397 as_value
398 video_height(const fn_call& fn)
400 Video* video = ensure<IsDisplayObject<Video> >(fn);
401 return as_value(video->height());
404 as_value
405 video_clear(const fn_call& fn)
407 Video* video = ensure<IsDisplayObject<Video> >(fn);
409 video->clear();
410 return as_value();
413 as_value
414 video_ctor(const fn_call& /* fn */)
416 return as_value();
419 } // anonymous namespace
421 } // end of namespace gnash