📄 smil_player.cpp
字号:
// This file is part of Ambulant Player, www.ambulantplayer.org.//// Copyright (C) 2003-2007 Stichting CWI, // Kruislaan 413, 1098 SJ Amsterdam, The Netherlands.//// Ambulant Player is free software; you can redistribute it and/or modify// it under the terms of the GNU Lesser General Public License as published by// the Free Software Foundation; either version 2.1 of the License, or// (at your option) any later version.//// Ambulant Player is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU Lesser General Public License for more details.//// You should have received a copy of the GNU Lesser General Public License// along with Ambulant Player; if not, write to the Free Software// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA#include "ambulant/lib/document.h"#include "ambulant/lib/node.h"#include "ambulant/lib/logger.h"#include "ambulant/lib/gtypes.h"#include "ambulant/lib/event.h"#include "ambulant/lib/callback.h"#include "ambulant/lib/system.h"#include "ambulant/lib/transition_info.h"#include "ambulant/common/factory.h"#include "ambulant/common/layout.h"#include "ambulant/common/schema.h"#include "ambulant/smil2/smil_time.h"#include "ambulant/smil2/test_attrs.h"#include "ambulant/smil2/smil_player.h"#include "ambulant/smil2/timegraph.h"#include "ambulant/smil2/smil_layout.h"#include "ambulant/smil2/time_sched.h"#include "ambulant/smil2/animate_e.h"#ifndef AM_DBG#define AM_DBG if(0)#endifusing namespace ambulant;using namespace smil2;common::player *common::create_smil2_player( lib::document *doc, common::factories* factory, common::embedder *sys){ return new smil_player(doc, factory, sys);}smil_player::smil_player(lib::document *doc, common::factories *factory, common::embedder *sys): m_doc(doc), m_factory(factory), m_system(sys), m_feedback_handler(0), m_animation_engine(0), m_root(0), m_dom2tn(0), m_layout_manager(0), m_timer(new timer_control_impl(realtime_timer_factory(), 1.0, false)), m_event_processor(0), m_scheduler(0), m_state(common::ps_idle), m_cursorid(0), m_pointed_node(0), m_wait_for_eom_flag(true), m_focus(0), m_focussed_nodes(new std::set<int>()), m_new_focussed_nodes(0){ m_logger = lib::logger::get_logger(); AM_DBG m_logger->debug("smil_player::smil_player(0x%x)", this);}voidsmil_player::initialize(){ document_loaded(m_doc); m_event_processor = event_processor_factory(m_timer); // build the layout (we need the top-level layout) build_layout(); // Build the timegraph using the current filter build_timegraph(); m_layout_manager->load_bgimages(m_factory);}smil_player::~smil_player() { AM_DBG m_logger->debug("smil_player::~smil_player(0x%x)", this); // sync destruction m_timer->pause(); cancel_all_events(); m_timer->pause(); cancel_all_events(); m_scheduler->reset_document(); std::map<const lib::node*, common::playable *>::iterator it; for(it = m_playables.begin();it!=m_playables.end();it++) { int rem = (*it).second->release(); if (rem) m_logger->trace("smil_player::~smil_player: playable 0x%x still has refcount of %d", (*it).second, rem); } delete m_focussed_nodes; delete m_new_focussed_nodes; delete m_event_processor; delete m_timer; delete m_dom2tn; delete m_animation_engine; delete m_root; delete m_scheduler;// delete m_doc; delete m_layout_manager;}void smil_player::build_layout() { if(m_state != common::ps_idle && m_state != common::ps_done) return; if(m_layout_manager) { delete m_layout_manager; delete m_animation_engine; } m_layout_manager = new smil_layout_manager(m_factory, m_doc); m_animation_engine = new animation_engine(m_event_processor, m_layout_manager);}void smil_player::build_timegraph() { if(m_state != common::ps_idle && m_state != common::ps_done) return; if(m_root) { delete m_root; delete m_dom2tn; delete m_scheduler; } timegraph tg(this, m_doc, schema::get_instance()); m_root = tg.detach_root(); m_dom2tn = tg.detach_dom2tn(); m_scheduler = new scheduler(m_root, m_timer);}void smil_player::schedule_event(lib::event *ev, lib::timer::time_type t, event_priority ep) { m_event_processor->add_event(ev, t, ep);}// Command to start playbackvoid smil_player::start() { if(m_state == common::ps_pausing) { resume(); } else if(m_state == common::ps_idle || m_state == common::ps_done) { if(!m_root) build_timegraph(); if(m_root) { if (m_system) m_system->starting(this); m_scheduler->start(m_root); update(); } }}// Command to stop playbackvoid smil_player::stop() { if(m_state != common::ps_pausing && m_state != common::ps_playing) return; m_timer->pause(); cancel_all_events(); m_scheduler->reset_document(); done_playback();}// Command to pause playbackvoid smil_player::pause() { if(m_state != common::ps_playing) return; m_state = common::ps_pausing; m_timer->pause(); std::map<const lib::node*, common::playable *>::iterator it; for(it = m_playables.begin();it!=m_playables.end();it++) (*it).second->pause();}// Command to resume playbackvoid smil_player::resume() { if(m_state != common::ps_pausing) return; m_state = common::ps_playing; std::map<const lib::node*, common::playable *>::iterator it; for(it = m_playables.begin();it!=m_playables.end();it++) (*it).second->resume(); m_timer->resume();}// Started callback from the schedulervoid smil_player::started_playback() { m_state = common::ps_playing; document_started();}// Done callback from the schedulervoid smil_player::done_playback() { m_state = common::ps_done; m_timer->pause(); document_stopped(); if(m_system) m_system->done(this);}// Request to create a playable for the node.common::playable *smil_player::create_playable(const lib::node *n) { std::map<const lib::node*, common::playable *>::iterator it = m_playables.find(n); common::playable *np = (it != m_playables.end())?(*it).second:0; if(np == NULL) { np = new_playable(n);AM_DBG lib::logger::get_logger()->debug("smil_player::create_playable(0x%x)cs.enter", (void*)n); m_playables_cs.enter(); m_playables[n] = np; m_playables_cs.leave();AM_DBG lib::logger::get_logger()->debug("smil_player::create_playable(0x%x)cs.leave", (void*)n); } // We also need to remember any accesskey attribute (as opposed to accesskey // value for a timing attribute) because these are global. // XXX It may be better/cheaper if we simply iterate over the m_playables.... const char *accesskey = n->get_attribute("accesskey"); if (accesskey) { int nid = n->get_numid(); // XXX Is this unicode-safe? m_accesskey_map[accesskey[0]] = nid; } return np;}// Request to start the playable of the node.// When trans is not null the playable should transition in void smil_player::start_playable(const lib::node *n, double t, const lib::transition_info *trans) { AM_DBG lib::logger::get_logger()->debug("smil_player::start_playable(0x%x, %f)", (void*)n, t); common::playable *np = create_playable(n); if (trans) { common::renderer *rend = np->get_renderer(); if (!rend) { const char *pid = n->get_attribute("id"); m_logger->trace("smil_player::start_playable: node %s has transition but is not visual", pid?pid:"no-id"); } else { rend->set_intransition(trans); } } np->start(t);}// Request to seek the playable of the node.void smil_player::seek_playable(const lib::node *n, double t) { AM_DBG lib::logger::get_logger()->debug("smil_player::seek_playable(0x%x, %f)", (void*)n, t); common::playable *np = create_playable(n); np->seek(t);}// Request to start a transition of the playable of the node.void smil_player::start_transition(const lib::node *n, const lib::transition_info *trans, bool in) { AM_DBG lib::logger::get_logger()->debug("smil_player::start_transition(0x%x, -x%x, in=%d)", (void*)n, trans, in); std::map<const lib::node*, common::playable *>::iterator it = m_playables.find(n); common::playable *np = (it != m_playables.end())?(*it).second:0; if(!np) { const char *pid = n->get_attribute("id"); m_logger->debug("smil_player::start_transition: node %s has no playable", pid?pid:"no-id"); return; } common::renderer *rend = np->get_renderer(); if (!rend) { const char *pid = n->get_attribute("id"); m_logger->trace("smil_player::start_transition: node %s has transition but is not visual", pid?pid:"no-id"); } else { if (in) { // XXX Jack thinks there's no reason for this... AM_DBG m_logger->debug("smil_player::start_transition: called for in-transition"); rend->set_intransition(trans); } else { rend->start_outtransition(trans); } }}// Request to stop the playable of the node.void smil_player::stop_playable(const lib::node *n) { AM_DBG lib::logger::get_logger()->debug("smil_player::stop_playable(0x%x)", (void*)n); if (n == m_focus) { m_focus = NULL; highlight(n, false); node_focussed(NULL); }AM_DBG lib::logger::get_logger()->debug("smil_player::stop_playable(0x%x)cs.enter", (void*)n); m_playables_cs.enter(); std::map<const lib::node*, common::playable *>::iterator it = m_playables.find(n); std::pair<const lib::node*, common::playable*> victim(NULL,NULL); if(it != m_playables.end()) {#ifdef AMBULANT_PLATFORM_WIN32_WCE victim = std::pair<const lib::node*, common::playable*>((*it).first, (*it).second);#else victim = *it;#endif m_playables.erase(it); } m_playables_cs.leave(); if (victim.first) destroy_playable(victim.second, victim.first);AM_DBG lib::logger::get_logger()->debug("smil_player::stop_playable(0x%x)cs.leave", (void*)n);}// Request to pause the playable of the node.void smil_player::pause_playable(const lib::node *n, pause_display d) { AM_DBG lib::logger::get_logger()->debug("smil_player::pause_playable(0x%x)", (void*)n); common::playable *np = get_playable(n); if(np) np->pause(d);}// Request to resume the playable of the node.void smil_player::resume_playable(const lib::node *n) { AM_DBG lib::logger::get_logger()->debug("smil_player::resume_playable(0x%xf)", (void*)n); common::playable *np = get_playable(n); if(np) np->resume();}// Query the node's playable for its duration.common::duration smil_player::get_dur(const lib::node *n) { const common::duration not_available(false, 0.0); std::map<const lib::node*, common::playable *>::iterator it = m_playables.find(n); common::playable *np = (it != m_playables.end())?(*it).second:0; if(np) { common::duration idur = np->get_dur(); if(idur.first) m_playables_dur[n] = idur.second; AM_DBG lib::logger::get_logger()->debug("smil_player::get_dur(0x%x): <%s, %f>", n, idur.first?"true":"false", idur.second); return idur; } std::map<const node*, double>::iterator it2 = m_playables_dur.find(n); common::duration rv = (it2 != m_playables_dur.end())?common::duration(true,(*it2).second):not_available; AM_DBG lib::logger::get_logger()->debug("smil_player::get_dur(0x%x): <%s, %f>", n, rv.first?"true":"false", rv.second); return rv;}// Notify the playable that it should update this on user events (click, point).void smil_player::wantclicks_playable(const lib::node *n, bool want) { common::playable *np = get_playable(n); if(np) np->wantclicks(want);}// Playable notification for a click event.void smil_player::clicked(int n, double t) { AM_DBG m_logger->debug("smil_player::clicked(%d, %f)", n, t); typedef lib::scalar_arg_callback_event<time_node, q_smil_time> dom_event_cb; std::map<int, time_node*>::iterator it = m_dom2tn->find(n); if(it != m_dom2tn->end() && (*it).second->wants_activate_event()) { time_node::value_type root_time = m_root->get_simple_time(); m_scheduler->update_horizon(root_time); q_smil_time timestamp(m_root, root_time); dom_event_cb *cb = new dom_event_cb((*it).second, &time_node::raise_activate_event, timestamp); schedule_event(cb, 0, ep_high); m_scheduler->exec(); }}voidsmil_player::before_mousemove(int cursorid){ m_cursorid = cursorid; delete m_new_focussed_nodes; m_new_focussed_nodes = new std::set<int>(); AM_DBG m_logger->debug("smil_player(0x%x)::before_mousemove(%d) m_new_focussed_nodes=0x%x", this, cursorid, m_new_focussed_nodes);}intsmil_player::after_mousemove(){ typedef lib::scalar_arg_callback_event<time_node, q_smil_time> dom_event_cb; std::set<int>::iterator i; m_pointed_node = 0; // First we send outOfBounds and focusOut events to all // the nodes that were in the focus but no longer are. for (i=m_focussed_nodes->begin(); i!=m_focussed_nodes->end(); i++) { int n = *i; // If the node is also in the new focus we're done. if (m_new_focussed_nodes->count(n) > 0) continue; // If the node can't be found we're done. std::map<int, time_node*>::iterator it = m_dom2tn->find(n); if (it == m_dom2tn->end()) continue; // Otherwise we send it outofbounds and focusout events, if it is interested. time_node *tn = (*it).second; AM_DBG m_logger->debug("after_mousemove: focus lost by %d, 0x%x", n, tn); if (tn->wants_outofbounds_event()) { AM_DBG m_logger->debug("smil_player::pointed: schedule 0x%x.outOfBoundsEvent", (void*)tn); time_node::value_type root_time = m_root->get_simple_time(); m_scheduler->update_horizon(root_time); q_smil_time timestamp(m_root, root_time); dom_event_cb *cb = new dom_event_cb(tn, &time_node::raise_outofbounds_event, timestamp); schedule_event(cb, 0, ep_high); } if (tn->wants_focusout_event()) { AM_DBG m_logger->debug("smil_player::pointed: schedule 0x%x.focusOutEvent", (void*)tn); time_node::value_type root_time = m_root->get_simple_time(); m_scheduler->update_horizon(root_time); q_smil_time timestamp(m_root, root_time); dom_event_cb *cb = new dom_event_cb(tn, &time_node::raise_focusout_event, timestamp); schedule_event(cb, 0, ep_high); } } // Next we send inbound and focusin events to the nodes that // are now in the focus, and were not there before. for (i=m_new_focussed_nodes->begin(); i!=m_new_focussed_nodes->end(); i++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -