1 // Video.cpp: Draw individual video frames, for Gnash.
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
4 // Free Software Foundation, Inc
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.
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
23 #include <boost/bind.hpp>
26 #include "DefineVideoStreamTag.h"
27 #include "NetStream_as.h"
28 #include "as_object.h"
30 #include "MediaHandler.h" // for setting up embedded video decoder
31 #include "VideoDecoder.h" // for setting up embedded video decoder
33 #include "RunResources.h"
34 #include "Transform.h"
36 // Define this to get debug logging during embedded video decoding
37 //#define DEBUG_EMBEDDED_VIDEO_DECODING
41 Video::Video(as_object
* object
,
42 const SWF::DefineVideoStreamTag
* def
, DisplayObject
* parent
)
44 DisplayObject(getRoot(*object
), object
, parent
),
47 _embeddedStream(m_def
),
48 _lastDecodedVideoFrameNum(-1),
49 _lastDecodedVideoFrame(),
55 media::MediaHandler
* mh
= getRunResources(*object
).mediaHandler();
57 LOG_ONCE(log_error(_("No Media handler registered, "
58 "won't be able to decode embedded video")) );
62 media::VideoInfo
* info
= m_def
->getVideoInfo();
66 _decoder
= mh
->createVideoDecoder(*info
);
68 catch (const MediaException
& e
) {
69 log_error(_("Could not create Video Decoder: %s"), e
.what());
80 if (_ns
) return _ns
->videoWidth();
87 if (_ns
) return _ns
->videoHeight();
94 // Clear the current image only if paused.
95 if (_ns
&& _ns
->playbackState() == PlayHead::PLAY_PAUSED
)
98 _lastDecodedVideoFrame
.reset();
103 Video::display(Renderer
& renderer
, const Transform
& base
)
107 const DisplayObject::MaskRenderer
mr(renderer
, *this);
109 const Transform xform
= base
* transform();
110 const SWFRect
& bounds
= m_def
->bounds();
112 image::GnashImage
* img
= getVideoFrame();
114 renderer
.drawVideoFrame(img
, xform
, &bounds
, _smoothing
);
121 Video::getVideoFrame()
123 // If this is a video from a NetStream_as object, retrieve a video
126 std::auto_ptr
<image::GnashImage
> tmp
= _ns
->get_video();
127 if (tmp
.get()) _lastDecodedVideoFrame
= tmp
;
130 // If this is a video from a VideoFrame tag, retrieve a video frame
132 else if (_embeddedStream
) {
134 // Don't try to do anything if there is no decoder. If it was
135 // never constructed (most likely), we'll return nothing,
136 // otherwise the last decoded frame.
137 if (!_decoder
.get()) {
138 LOG_ONCE(log_error(_("No Video info in video definition")));
139 return _lastDecodedVideoFrame
.get();
142 const boost::uint16_t current_frame
= get_ratio();
144 #ifdef DEBUG_EMBEDDED_VIDEO_DECODING
145 log_debug("Video instance %s need display video frame (ratio) %d",
146 getTarget(), current_frame
);
149 // If current frame is the same then last decoded
150 // we don't need to decode more
151 if (_lastDecodedVideoFrameNum
>= 0 &&
152 _lastDecodedVideoFrameNum
== current_frame
) {
153 #ifdef DEBUG_EMBEDDED_VIDEO_DECODING
154 log_debug(" current frame == _lastDecodedVideoFrameNum (%d)",
157 return _lastDecodedVideoFrame
.get();
160 // TODO: find a better way than using -1 to show that no
161 // frames have been decoded yet.
162 assert(_lastDecodedVideoFrameNum
>= -1);
163 boost::uint16_t from_frame
= _lastDecodedVideoFrameNum
+ 1;
165 // If current frame is smaller then last decoded frame
166 // we restart decoding from scratch
167 if (current_frame
< static_cast<size_t>(_lastDecodedVideoFrameNum
)) {
168 #ifdef DEBUG_EMBEDDED_VIDEO_DECODING
169 log_debug(" current frame (%d) < _lastDecodedVideoFrameNum (%d)",
170 current_frame
, _lastDecodedVideoFrameNum
);
175 // Reset last decoded video frame number now, so it's correct
176 // on early return (ie: nothing more to decode)
177 _lastDecodedVideoFrameNum
= current_frame
;
179 #ifdef DEBUG_EMBEDDED_VIDEO_DECODING
180 log_debug(" decoding embedded frames from %d to %d"
181 "for Video object %s", from_frame
,
182 current_frame
, getTarget());
185 const size_t frames
= m_def
->visitSlice(
186 boost::bind(boost::mem_fn(&media::VideoDecoder::push
),
188 from_frame
, current_frame
);
190 if (!frames
) return _lastDecodedVideoFrame
.get();
192 _lastDecodedVideoFrame
= _decoder
->pop();
195 return _lastDecodedVideoFrame
.get();
199 Video::construct(as_object
* /*init*/)
201 // For soft references.
202 saveOriginalTarget();
206 Video::add_invalidated_bounds(InvalidatedRanges
& ranges
, bool force
)
208 if (!force
&& !invalidated()) return; // no need to redraw
210 ranges
.add(m_old_invalidated_ranges
);
215 bounds
.expand_to_transformed_rect(getWorldMatrix(*this), m_def
->bounds());
217 ranges
.add(bounds
.getRange());
221 Video::setStream(NetStream_as
* ns
)
224 _ns
->setInvalidatedVideo(this);
228 Video::getBounds() const
230 if (_embeddedStream
) return m_def
->bounds();
232 // TODO: return the bounds of the dynamically
233 // loaded video if not embedded ?
238 Video::markOwnResources() const
240 if (_ns
) _ns
->setReachable();