don't add (LIBLTDL) to LDFLAGS, libltdl is part of libgnashbase.
[gnash.git] / libcore / Video.cpp
blob9ec56bf1ddcd5f5835762f349853ff0f52b76b61
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"
37 #include "Transform.h"
39 // Define this to get debug logging during embedded video decoding
40 //#define DEBUG_EMBEDDED_VIDEO_DECODING
42 namespace gnash {
44 namespace {
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) return;
80 try {
81 _decoder = mh->createVideoDecoder(*info);
83 catch (const MediaException& e) {
84 log_error("Could not create Video Decoder: %s", e.what());
88 Video::~Video()
92 int
93 Video::width() const
95 if (_ns) return _ns->videoWidth();
96 return 0;
99 int
100 Video::height() const
102 if (_ns) return _ns->videoHeight();
103 return 0;
106 void
107 Video::clear()
109 // Clear the current image only if paused.
110 if (_ns && _ns->playbackState() == PlayHead::PLAY_PAUSED)
112 set_invalidated();
113 _lastDecodedVideoFrame.reset();
117 void
118 Video::display(Renderer& renderer, const Transform& base)
120 assert(m_def);
122 const DisplayObject::MaskRenderer mr(renderer, *this);
124 const Transform xform = base * transform();
125 const SWFRect& bounds = m_def->bounds();
127 image::GnashImage* img = getVideoFrame();
128 if (img) {
129 renderer.drawVideoFrame(img, xform, &bounds, _smoothing);
132 clear_invalidated();
135 image::GnashImage*
136 Video::getVideoFrame()
140 // If this is a video from a NetStream_as object, retrieve a video
141 // frame from there.
142 if (_ns)
144 std::auto_ptr<image::GnashImage> tmp = _ns->get_video();
145 if ( tmp.get() ) _lastDecodedVideoFrame = tmp;
148 // If this is a video from a VideoFrame tag, retrieve a video frame
149 // from there.
150 else if (_embeddedStream)
153 // Don't try to do anything if there is no decoder. If it was
154 // never constructed (most likely), we'll return nothing,
155 // otherwise the last decoded frame.
156 if (!_decoder.get()) {
157 LOG_ONCE( log_error(_("No Video info in video definition")) );
158 return _lastDecodedVideoFrame.get();
161 int current_frame = get_ratio();
163 #ifdef DEBUG_EMBEDDED_VIDEO_DECODING
164 log_debug("Video instance %s need display video frame (ratio) %d",
165 getTarget(), current_frame);
166 #endif
168 // If current frame is the same then last decoded
169 // we don't need to decode more
170 if ( _lastDecodedVideoFrameNum == current_frame )
172 #ifdef DEBUG_EMBEDDED_VIDEO_DECODING
173 log_debug(" current frame == _lastDecodedVideoFrameNum (%d)",
174 current_frame);
175 #endif
176 return _lastDecodedVideoFrame.get();
179 int from_frame = _lastDecodedVideoFrameNum < 0 ?
180 0 : _lastDecodedVideoFrameNum + 1;
182 // If current frame is smaller then last decoded frame
183 // we restart decoding from scratch
184 if ( current_frame < _lastDecodedVideoFrameNum )
186 #ifdef DEBUG_EMBEDDED_VIDEO_DECODING
187 log_debug(" current frame (%d) < _lastDecodedVideoFrameNum (%d)",
188 current_frame, _lastDecodedVideoFrameNum);
189 #endif
190 from_frame = 0;
193 // Reset last decoded video frame number now, so it's correct
194 // on early return (ie: nothing more to decode)
195 _lastDecodedVideoFrameNum = current_frame;
197 #ifdef DEBUG_EMBEDDED_VIDEO_DECODING
198 log_debug(" decoding embedded frames from %d to %d for Video "
199 "object %s", from_frame, current_frame, getTarget());
200 #endif
202 typedef SWF::DefineVideoStreamTag::EmbeddedFrames EncodedFrames;
204 EncodedFrames toDecode;
205 m_def->getEncodedFrameSlice(from_frame, current_frame, toDecode);
207 // Nothing more to decode, return last decoded (possibly null)
208 if ( toDecode.empty() )
210 #ifdef DEBUG_EMBEDDED_VIDEO_DECODING
211 log_debug(" no defined frames, we'll return last one");
212 #endif
213 return _lastDecodedVideoFrame.get();
216 for (EncodedFrames::iterator it=toDecode.begin(),
217 itEnd=toDecode.end(); it!=itEnd; ++it)
219 media::EncodedVideoFrame* frame = *it;
220 #ifdef DEBUG_EMBEDDED_VIDEO_DECODING
221 log_debug(" pushing frame %d to decoder", frame->frameNum());
222 #endif
223 _decoder->push(*frame);
226 _lastDecodedVideoFrame = _decoder->pop();
229 return _lastDecodedVideoFrame.get();
232 void
233 Video::construct(as_object* /*init*/)
235 // For soft references.
236 saveOriginalTarget();
240 void
241 Video::add_invalidated_bounds(InvalidatedRanges& ranges, bool force)
243 if (!force && !invalidated()) return; // no need to redraw
245 ranges.add(m_old_invalidated_ranges);
247 assert (m_def);
249 SWFRect bounds;
250 bounds.expand_to_transformed_rect(getWorldMatrix(*this), m_def->bounds());
252 ranges.add(bounds.getRange());
255 void
256 Video::setStream(NetStream_as* ns)
258 _ns = ns;
259 _ns->setInvalidatedVideo(this);
262 // extern (used by Global.cpp)
263 void
264 video_class_init(as_object& global, const ObjectURI& uri)
266 // This is going to be the global Video "class"/"function"
267 Global_as& gl = getGlobal(global);
268 as_object* proto = createObject(gl);
269 as_object* cl = gl.createClass(&video_ctor, proto);
270 attachVideoInterface(*proto);
272 // Register _global.Video
273 global.init_member(uri, cl, as_object::DefaultFlags);
276 void
277 registerVideoNative(as_object& global)
279 VM& vm = getVM(global);
280 vm.registerNative(video_ctor, 667, 0);
281 vm.registerNative(video_attach, 667, 1);
282 vm.registerNative(video_clear, 667, 2);
285 SWFRect
286 Video::getBounds() const
288 if (_embeddedStream) return m_def->bounds();
290 // TODO: return the bounds of the dynamically
291 // loaded video if not embedded ?
292 return SWFRect();
295 void
296 Video::markOwnResources() const
298 if (_ns) _ns->setReachable();
301 as_object*
302 createVideoObject(Global_as& gl)
304 // TODO: how to use this for AS3 as well?
305 // Turn into constructBuiltin()
306 as_object* obj = getObjectWithPrototype(gl, NSV::CLASS_VIDEO);
307 as_object* proto = obj->get_prototype();
308 if (proto) attachPrototypeProperties(*proto);
309 return obj;
312 namespace {
314 void
315 attachVideoInterface(as_object& o)
317 VM& vm = getVM(o);
318 o.init_member("attachVideo", vm.getNative(667, 1));
319 o.init_member("clear", vm.getNative(667, 2));
322 void
323 attachPrototypeProperties(as_object& proto)
325 const int protect = PropFlags::dontDelete;
327 proto.init_property("deblocking", &video_deblocking, &video_deblocking,
328 protect);
329 proto.init_property("smoothing", &video_smoothing, &video_smoothing,
330 protect);
332 const int flags = PropFlags::dontDelete |
333 PropFlags::readOnly;
335 proto.init_property("height", &video_height, &video_height, flags);
336 proto.init_property("width", &video_width, &video_width, flags);
339 as_value
340 video_attach(const fn_call& fn)
342 Video* video = ensure<IsDisplayObject<Video> >(fn);
344 if (fn.nargs < 1)
346 IF_VERBOSE_ASCODING_ERRORS(
347 log_aserror(_("attachVideo needs 1 arg"));
349 return as_value();
352 as_object* obj = toObject(fn.arg(0), getVM(fn));
353 NetStream_as* ns;
355 if (isNativeType(obj, ns)) {
356 video->setStream(ns);
358 else {
359 IF_VERBOSE_ASCODING_ERRORS(
360 log_aserror(_("attachVideo(%s) first arg is not a NetStream instance"),
361 fn.arg(0));
364 return as_value();
367 as_value
368 video_deblocking(const fn_call& fn)
370 Video* video = ensure<IsDisplayObject<Video> >(fn);
371 UNUSED(video);
373 log_unimpl("Video.deblocking");
374 return as_value();
377 as_value
378 video_smoothing(const fn_call& fn)
380 Video* video = ensure<IsDisplayObject<Video> >(fn);
382 if (!fn.nargs) return as_value(video->smoothing());
384 const bool smooth = toBool(fn.arg(0), getVM(fn));
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