File indexing completed on 2024-04-21 04:54:00

0001 /*
0002     SPDX-FileCopyrightText: 2006 Koos Vriezen <koos.vriezen@gmail.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-only
0005 */
0006 
0007 #include "config-kmplayer.h"
0008 
0009 #include <QColor>
0010 #include <QTimer>
0011 
0012 #include "kmplayercommon_log.h"
0013 #include "kmplayer_rp.h"
0014 #include "kmplayer_smil.h"
0015 #include "mediaobject.h"
0016 
0017 using namespace KMPlayer;
0018 
0019 
0020 RP::Imfl::Imfl (NodePtr & d)
0021   : Mrl (d, id_node_imfl),
0022     fit (fit_hidden),
0023     duration (0),
0024     duration_timer (nullptr),
0025     needs_scene_img (0) {}
0026 
0027 RP::Imfl::~Imfl () {
0028 }
0029 
0030 void RP::Imfl::closed () {
0031     for (Node *n = firstChild (); n; n = n->nextSibling ())
0032         if (RP::id_node_head == n->id) {
0033             Attribute *a = static_cast <Element *> (n)->attributes ().first ();
0034             for (; a; a = a->nextSibling ()) {
0035                 if (Ids::attr_width == a->name ()) {
0036                     size.width = a->value ().toInt ();
0037                 } else if (Ids::attr_height == a->name ()) {
0038                     size.height = a->value ().toInt ();
0039                 } else if (a->name () == "duration") {
0040                     int dur;
0041                     parseTime (a->value ().toLower (), dur);
0042                     duration = dur;
0043                 }
0044             }
0045         }
0046     Mrl::closed ();
0047 }
0048 
0049 void RP::Imfl::defer () {
0050     qCDebug(LOG_KMPLAYER_COMMON) << "RP::Imfl::defer ";
0051     setState (state_deferred);
0052     for (Node *n = firstChild (); n; n = n->nextSibling ())
0053         if (n->id == RP::id_node_image && !n->active ())
0054             n->activate ();
0055 }
0056 
0057 void RP::Imfl::activate () {
0058     qCDebug(LOG_KMPLAYER_COMMON) << "RP::Imfl::activate ";
0059     resolved = true;
0060     setState (state_activated);
0061     int timings_count = 0;
0062     for (Node *n = firstChild (); n; n = n->nextSibling ())
0063         switch (n->id) {
0064             case RP::id_node_crossfade:
0065             case RP::id_node_fadein:
0066             case RP::id_node_fadeout:
0067             case RP::id_node_fill:
0068             case RP::id_node_wipe:
0069             case RP::id_node_viewchange:
0070                 n->activate (); // set their start timers
0071                 timings_count++;
0072                 break;
0073             case RP::id_node_image:
0074                 if (!n->active ())
0075                     n->activate ();
0076                 break;
0077         }
0078     if (duration > 0)
0079         duration_timer = document ()->post (this,
0080                 new TimerPosting (duration * 10));
0081     else if (!timings_count)
0082         finish ();
0083 }
0084 
0085 void RP::Imfl::finish () {
0086     qCDebug(LOG_KMPLAYER_COMMON) << "RP::Imfl::finish ";
0087     Mrl::finish ();
0088     if (duration_timer) {
0089         document ()->cancelPosting (duration_timer);
0090         duration_timer = nullptr;
0091     }
0092     for (NodePtr n = firstChild (); n; n = n->nextSibling ())
0093         if (n->unfinished ())
0094             n->finish ();
0095 }
0096 
0097 void RP::Imfl::deactivate () {
0098     qCDebug(LOG_KMPLAYER_COMMON) << "RP::Imfl::deactivate ";
0099     if (unfinished ())
0100         finish ();
0101     else if (duration_timer) {
0102         document ()->cancelPosting (duration_timer);
0103         duration_timer = nullptr;
0104     }
0105     if (!active ())
0106         return; // calling finish might call deactivate() as well
0107     setState (state_deactivated);
0108     for (NodePtr n = firstChild (); n; n = n->nextSibling ())
0109         if (n->active ())
0110             n->deactivate ();
0111     rp_surface = (Surface *) role (RoleChildDisplay, nullptr);
0112 }
0113 
0114 void RP::Imfl::message (MessageType msg, void *content) {
0115     switch (msg) {
0116         case MsgEventTimer:
0117             duration_timer = nullptr;
0118             if (unfinished ())
0119                 finish ();
0120             return;
0121         case MsgChildFinished:
0122             if (unfinished () && !duration_timer) {
0123                 for (Node *n = firstChild (); n; n = n->nextSibling ())
0124                     switch (n->id) {
0125                         case RP::id_node_crossfade:
0126                         case RP::id_node_fadein:
0127                         case RP::id_node_fadeout:
0128                         case RP::id_node_fill:
0129                             if (n->unfinished ())
0130                                 return;
0131                     }
0132                 finish ();
0133             }
0134             return;
0135         default:
0136             break;
0137     }
0138     Mrl::message (msg, content);
0139 }
0140 
0141 void RP::Imfl::accept (Visitor * v) {
0142     v->visit (this);
0143 }
0144 
0145 Surface *RP::Imfl::surface () {
0146     if (!rp_surface) {
0147         rp_surface = (Surface *) Mrl::role (RoleChildDisplay, this);
0148         if (rp_surface && size.isEmpty ())
0149             size = rp_surface->bounds.size;
0150     }
0151     return rp_surface.ptr ();
0152 }
0153 
0154 Node *RP::Imfl::childFromTag (const QString & tag) {
0155     QByteArray ba = tag.toLatin1 ();
0156     const char *ctag = ba.constData ();
0157     if (!strcmp (ctag, "head"))
0158         return new DarkNode (m_doc, "head", RP::id_node_head);
0159     else if (!strcmp (ctag, "image"))
0160         return new RP::Image (m_doc);
0161     else if (!strcmp (ctag, "fill"))
0162         return new RP::Fill (m_doc);
0163     else if (!strcmp (ctag, "wipe"))
0164         return new RP::Wipe (m_doc);
0165     else if (!strcmp (ctag, "viewchange"))
0166         return new RP::ViewChange (m_doc);
0167     else if (!strcmp (ctag, "crossfade"))
0168         return new RP::Crossfade (m_doc);
0169     else if (!strcmp (ctag, "fadein"))
0170         return new RP::Fadein (m_doc);
0171     else if (!strcmp (ctag, "fadeout"))
0172         return new RP::Fadeout (m_doc);
0173     return nullptr;
0174 }
0175 
0176 void RP::Imfl::repaint () {
0177     if (!active ()) {
0178         qCWarning(LOG_KMPLAYER_COMMON) << "Spurious Imfl repaint";
0179     } else if (surface () && !size.isEmpty ()) {
0180         rp_surface->markDirty ();
0181         rp_surface->repaint (SRect (0, 0, size));
0182     }
0183 }
0184 
0185 RP::Image::Image (NodePtr & doc)
0186  : Mrl (doc, id_node_image) {
0187     view_mode = WindowMode;
0188 }
0189 
0190 RP::Image::~Image () {
0191 }
0192 
0193 void RP::Image::closed () {
0194     src = getAttribute (Ids::attr_name);
0195     Mrl::closed ();
0196 }
0197 
0198 void RP::Image::activate () {
0199     qCDebug(LOG_KMPLAYER_COMMON) << "RP::Image::activate";
0200     setState (state_activated);
0201     isPlayable (); // update src attribute
0202     if (!media_info)
0203         media_info = new MediaInfo (this, MediaManager::Image);
0204     media_info->wget (absolutePath ());
0205 }
0206 
0207 void RP::Image::begin () {
0208     Node::begin ();
0209 }
0210 
0211 void RP::Image::deactivate () {
0212     if (img_surface) {
0213         img_surface->remove ();
0214         img_surface = nullptr;
0215     }
0216     setState (state_deactivated);
0217     postpone_lock = nullptr;
0218     delete media_info;
0219     media_info = nullptr;
0220 }
0221 
0222 void RP::Image::message (MessageType msg, void *content) {
0223     if (msg == MsgMediaReady) {
0224         if (media_info)
0225             dataArrived ();
0226     } else {
0227         Mrl::message (msg, content);
0228     }
0229 }
0230 
0231 void RP::Image::dataArrived () {
0232     qCDebug(LOG_KMPLAYER_COMMON) << "RP::Image::remoteReady";
0233     ImageMedia *im = media_info->media ? (ImageMedia *)media_info->media : nullptr;
0234     if (im && !im->isEmpty ()) {
0235         size.width = im->cached_img->width;
0236         size.height = im->cached_img->height;
0237     }
0238     postpone_lock = nullptr;
0239 }
0240 
0241 bool RP::Image::isReady (bool postpone_if_not) {
0242     if (media_info->downloading () && postpone_if_not)
0243         postpone_lock = document ()->postpone ();
0244     return !media_info->downloading ();
0245 }
0246 
0247 Surface *RP::Image::surface () {
0248     ImageMedia *im = media_info && media_info->media
0249         ? (ImageMedia *)media_info->media : nullptr;
0250     if (im && !img_surface && !im->isEmpty ()) {
0251         Node * p = parentNode ();
0252         if (p && p->id == RP::id_node_imfl) {
0253             Surface *ps = static_cast <RP::Imfl *> (p)->surface ();
0254             if (ps)
0255                 img_surface = ps->createSurface (this,
0256                         SRect (0, 0, size));
0257         }
0258     }
0259     return img_surface;
0260 }
0261 
0262 RP::TimingsBase::TimingsBase (NodePtr & d, const short i)
0263  : Element (d, i), x (0), y (0), w (0), h (0), start (0), duration (0),
0264    start_timer (nullptr), duration_timer (nullptr), update_timer (nullptr) {}
0265 
0266 void RP::TimingsBase::activate () {
0267     setState (state_activated);
0268     x = y = w = h = 0;
0269     srcx = srcy = srcw = srch = 0;
0270     for (Attribute *a = attributes ().first (); a; a = a->nextSibling ()) {
0271         if (a->name () == Ids::attr_target) {
0272             for (Node *n = parentNode()->firstChild(); n; n= n->nextSibling())
0273                 if (static_cast <Element *> (n)->
0274                         getAttribute ("handle") == a->value ())
0275                     target = n;
0276         } else if (a->name () == "start") {
0277             int dur;
0278             parseTime (a->value ().toLower (), dur);
0279             start = dur;
0280         } else if (a->name () == "duration") {
0281             int dur;
0282             parseTime (a->value ().toLower (), dur);
0283             duration = dur;
0284         } else if (a->name () == "dstx") {
0285             x = a->value ().toInt ();
0286         } else if (a->name () == "dsty") {
0287             y = a->value ().toInt ();
0288         } else if (a->name () == "dstw") {
0289             w = a->value ().toInt ();
0290         } else if (a->name () == "dsth") {
0291             h = a->value ().toInt ();
0292         } else if (a->name () == "srcx") {
0293             srcx = a->value ().toInt ();
0294         } else if (a->name () == "srcy") {
0295             srcy = a->value ().toInt ();
0296         } else if (a->name () == "srcw") {
0297             srcw = a->value ().toInt ();
0298         } else if (a->name () == "srch") {
0299             srch = a->value ().toInt ();
0300         }
0301     }
0302     start_timer = document ()->post (this, new TimerPosting (start *10));
0303 }
0304 
0305 void RP::TimingsBase::deactivate () {
0306     if (unfinished ())
0307         finish ();
0308     else
0309         cancelTimers ();
0310     setState (state_deactivated);
0311 }
0312 
0313 void RP::TimingsBase::message (MessageType msg, void *content) {
0314     switch (msg) {
0315         case MsgEventTimer: {
0316             TimerPosting *te = static_cast <TimerPosting *> (content);
0317             if (te == update_timer && duration > 0) {
0318                 update (100 * 10 * ++curr_step / duration);
0319                 te->interval = true;
0320             } else if (te == start_timer) {
0321                 start_timer = nullptr;
0322                 duration_timer = document()->post (this,
0323                         new TimerPosting (duration * 10));
0324                 begin ();
0325             } else if (te == duration_timer) {
0326                 duration_timer = nullptr;
0327                 update (100);
0328                 finish ();
0329             }
0330             break;
0331         }
0332         case MsgEventPostponed: {
0333             PostponedEvent *pe = static_cast <PostponedEvent *> (content);
0334             if (!pe->is_postponed) {
0335                 document_postponed.disconnect ();
0336                 update (duration > 0 ? 0 : 100);
0337             }
0338             break;
0339         }
0340         default:
0341             Element::message (msg, content);
0342     }
0343 }
0344 
0345 void RP::TimingsBase::begin () {
0346     progress = 0;
0347     setState (state_began);
0348     if (target)
0349         target->begin ();
0350     if (duration > 0) {
0351         steps = duration / 10; // 10/s updates
0352         update_timer = document ()->post (this, new TimerPosting (100)); // 50ms
0353         curr_step = 1;
0354     }
0355 }
0356 
0357 void RP::TimingsBase::update (int percentage) {
0358     progress = percentage;
0359     Node *p = parentNode ();
0360     if (p->id == RP::id_node_imfl)
0361         static_cast <RP::Imfl *> (p)->repaint ();
0362 }
0363 
0364 void RP::TimingsBase::finish () {
0365     progress = 100;
0366     cancelTimers ();
0367     document_postponed.disconnect ();
0368     Element::finish ();
0369 }
0370 
0371 void RP::TimingsBase::cancelTimers () {
0372     if (start_timer) {
0373         document ()->cancelPosting (start_timer);
0374         start_timer = nullptr;
0375     } else if (duration_timer) {
0376         document ()->cancelPosting (duration_timer);
0377         duration_timer = nullptr;
0378     }
0379     if (update_timer) {
0380         document ()->cancelPosting (update_timer);
0381         update_timer = nullptr;
0382     }
0383 }
0384 
0385 void RP::Crossfade::activate () {
0386     TimingsBase::activate ();
0387 }
0388 
0389 void RP::Crossfade::begin () {
0390     //qCDebug(LOG_KMPLAYER_COMMON) << "RP::Crossfade::begin";
0391     TimingsBase::begin ();
0392     if (target && target->id == id_node_image) {
0393         RP::Image * img = static_cast <RP::Image *> (target.ptr ());
0394         if (!img->isReady (true))
0395             document_postponed.connect (document(), MsgEventPostponed, this);
0396         else
0397             update (duration > 0 ? 0 : 100);
0398     }
0399 }
0400 
0401 void RP::Crossfade::accept (Visitor * v) {
0402     v->visit (this);
0403 }
0404 
0405 void RP::Fadein::activate () {
0406     // pickup color from Fill that should be declared before this node
0407     from_color = 0;
0408     TimingsBase::activate ();
0409 }
0410 
0411 void RP::Fadein::begin () {
0412     //qCDebug(LOG_KMPLAYER_COMMON) << "RP::Fadein::begin";
0413     TimingsBase::begin ();
0414     if (target && target->id == id_node_image) {
0415         RP::Image * img = static_cast <RP::Image *> (target.ptr ());
0416         if (!img->isReady (true))
0417             document_postponed.connect (document(), MsgEventPostponed, this);
0418         else
0419             update (duration > 0 ? 0 : 100);
0420     }
0421 }
0422 
0423 void RP::Fadein::accept (Visitor * v) {
0424     v->visit (this);
0425 }
0426 
0427 void RP::Fadeout::activate () {
0428     to_color = QColor (getAttribute ("color")).rgb ();
0429     TimingsBase::activate ();
0430 }
0431 
0432 void RP::Fadeout::begin () {
0433     //qCDebug(LOG_KMPLAYER_COMMON) << "RP::Fadeout::begin";
0434     TimingsBase::begin ();
0435 }
0436 
0437 void RP::Fadeout::accept (Visitor * v) {
0438     v->visit (this);
0439 }
0440 
0441 void RP::Fill::activate () {
0442     color = QColor (getAttribute ("color")).rgb ();
0443     TimingsBase::activate ();
0444 }
0445 
0446 void RP::Fill::begin () {
0447     setState (state_began);
0448     update (0);
0449 }
0450 
0451 void RP::Fill::accept (Visitor * v) {
0452     v->visit (this);
0453 }
0454 
0455 void RP::Wipe::activate () {
0456     //TODO implement 'type="push"'
0457     QString dir = getAttribute ("direction").toLower ();
0458     direction = dir_right;
0459     if (dir == QString::fromLatin1 ("left"))
0460         direction = dir_left;
0461     else if (dir == QString::fromLatin1 ("up"))
0462         direction = dir_up;
0463     else if (dir == QString::fromLatin1 ("down"))
0464         direction = dir_down;
0465     TimingsBase::activate ();
0466 }
0467 
0468 void RP::Wipe::begin () {
0469     //qCDebug(LOG_KMPLAYER_COMMON) << "RP::Wipe::begin";
0470     TimingsBase::begin ();
0471     if (target && target->id == id_node_image) {
0472         RP::Image * img = static_cast <RP::Image *> (target.ptr ());
0473         if (!img->isReady (true))
0474             document_postponed.connect (document(), MsgEventPostponed, this);
0475         else
0476             update (duration > 0 ? 0 : 100);
0477     }
0478 }
0479 
0480 void RP::Wipe::accept (Visitor * v) {
0481     v->visit (this);
0482 }
0483 
0484 void RP::ViewChange::activate () {
0485     TimingsBase::activate ();
0486 }
0487 
0488 void RP::ViewChange::begin () {
0489     qCDebug(LOG_KMPLAYER_COMMON) << "RP::ViewChange::begin";
0490     setState (state_began);
0491     Node *p = parentNode ();
0492     if (p->id == RP::id_node_imfl)
0493         static_cast <RP::Imfl *> (p)->needs_scene_img++;
0494     update (0);
0495 }
0496 
0497 void RP::ViewChange::finish () {
0498     Node *p = parentNode ();
0499     if (p && p->id == RP::id_node_imfl)
0500         static_cast <RP::Imfl *> (p)->needs_scene_img--;
0501     TimingsBase::finish ();
0502 }
0503 
0504 void RP::ViewChange::accept (Visitor * v) {
0505     v->visit (this);
0506 }