Update with current status
[gnash.git] / libcore / Video.cpp
blob6666baeb83a973c1125c02da94a0fd7ba12f4c91
1 // Video.cpp: Draw individual video frames, for Gnash.
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.
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 //
21 #include "Video.h"
23 #include <functional>
24 #include <cassert>
26 #include "DefineVideoStreamTag.h"
27 #include "NetStream_as.h"
28 #include "as_object.h"
29 #include "VM.h"
30 #include "MediaHandler.h" // for setting up embedded video decoder
31 #include "VideoDecoder.h" // for setting up embedded video decoder
32 #include "Renderer.h"
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
39 namespace gnash {
41 Video::Video(as_object* object,
42 const SWF::DefineVideoStreamTag* def, DisplayObject* parent)
44 DisplayObject(getRoot(*object), object, parent),
45 m_def(def),
46 _ns(nullptr),
47 _embeddedStream(m_def),
48 _lastDecodedVideoFrameNum(-1),
49 _lastDecodedVideoFrame(),
50 _smoothing(false)
52 assert(object);
53 assert(def);
55 media::MediaHandler* mh = getRunResources(*object).mediaHandler();
56 if (!mh) {
57 LOG_ONCE(log_error(_("No Media handler registered, "
58 "won't be able to decode embedded video")) );
59 return;
62 media::VideoInfo* info = m_def->getVideoInfo();
63 if (!info) return;
65 try {
66 _decoder = mh->createVideoDecoder(*info);
68 catch (const MediaException& e) {
69 log_error(_("Could not create Video Decoder: %s"), e.what());
73 Video::~Video()
77 int
78 Video::width() const
80 if (_ns) return _ns->videoWidth();
81 return 0;
84 int
85 Video::height() const
87 if (_ns) return _ns->videoHeight();
88 return 0;
91 void
92 Video::clear()
94 // Clear the current image only if paused.
95 if (_ns && _ns->playbackState() == PlayHead::PLAY_PAUSED)
97 set_invalidated();
98 _lastDecodedVideoFrame.reset();
102 void
103 Video::display(Renderer& renderer, const Transform& base)
105 assert(m_def);
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();
113 if (img) {
114 renderer.drawVideoFrame(img, xform, &bounds, _smoothing);
117 clear_invalidated();
120 image::GnashImage*
121 Video::getVideoFrame()
123 // If this is a video from a NetStream_as object, retrieve a video
124 // frame from there.
125 if (_ns) {
126 std::unique_ptr<image::GnashImage> tmp = _ns->get_video();
127 if (tmp.get()) _lastDecodedVideoFrame = std::move(tmp);
130 // If this is a video from a VideoFrame tag, retrieve a video frame
131 // from there.
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 std::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);
147 #endif
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)",
155 current_frame);
156 #endif
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 std::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);
171 #endif
172 from_frame = 0;
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());
183 #endif
185 const size_t frames = m_def->visitSlice(
186 std::bind(std::mem_fn(&media::VideoDecoder::push),
187 _decoder.get(), std::placeholders::_1),
188 from_frame, current_frame);
190 if (!frames) return _lastDecodedVideoFrame.get();
192 _lastDecodedVideoFrame = _decoder->pop();
195 return _lastDecodedVideoFrame.get();
198 void
199 Video::construct(as_object* /*init*/)
201 // For soft references.
202 saveOriginalTarget();
205 void
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);
212 assert(m_def);
214 SWFRect bounds;
215 bounds.expand_to_transformed_rect(getWorldMatrix(*this), m_def->bounds());
217 ranges.add(bounds.getRange());
220 void
221 Video::setStream(NetStream_as* ns)
223 _ns = ns;
224 _ns->setInvalidatedVideo(this);
227 SWFRect
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 ?
234 return SWFRect();
237 void
238 Video::markOwnResources() const
240 if (_ns) _ns->setReachable();
243 } // namespace gnash