File indexing completed on 2024-04-28 08:46:31
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 }