001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.wicket.markup.html.media; 018 019import org.apache.wicket.markup.ComponentTag; 020import org.apache.wicket.markup.html.WebMarkupContainer; 021import org.apache.wicket.model.IModel; 022import org.apache.wicket.request.Url; 023import org.apache.wicket.request.cycle.RequestCycle; 024import org.apache.wicket.request.mapper.parameter.PageParameters; 025import org.apache.wicket.request.mapper.parameter.PageParametersEncoder; 026import org.apache.wicket.request.resource.ResourceReference; 027 028/** 029 * The media component is used to provide basic functionality to the video and audio component. 030 * 031 * @author Tobias Soloschenko 032 * @author Andrew Lombardi 033 * @since 7.0.0 034 */ 035public abstract class MediaComponent extends WebMarkupContainer 036{ 037 private static final long serialVersionUID = 1L; 038 039 /** 040 * To be used for the <em>crossorigin</em> attribute 041 * 042 * @see #setCrossOrigin(Cors) 043 */ 044 public enum Cors { 045 /** 046 * no authentication required 047 */ 048 ANONYMOUS("anonymous"), 049 /** 050 * user credentials required 051 */ 052 USER_CREDENTIALS("user-credentials"), 053 /** 054 * no cross origin 055 */ 056 NO_CORS(""); 057 058 private final String realName; 059 060 private Cors(String realName) 061 { 062 this.realName = realName; 063 } 064 065 /** 066 * Gets the real name for the cors option 067 * 068 * @return the real name 069 */ 070 public String getRealName() 071 { 072 return realName; 073 } 074 } 075 076 /** 077 * To be used for the <em>preload</em> attribute 078 * 079 * @see #setPreload(Preload) 080 */ 081 public enum Preload { 082 /** 083 * preloads nothing 084 */ 085 NONE("none"), 086 /** 087 * preloads only meta data like first picture, etc. 088 */ 089 METADATA("metadata"), 090 /** 091 * auto detection what is going to be preload 092 */ 093 AUTO("auto"); 094 095 private final String realName; 096 097 Preload(String realname) 098 { 099 realName = realname; 100 } 101 102 /** 103 * Gets the real name for the preload option 104 * 105 * @return the real name 106 */ 107 public String getRealName() 108 { 109 return realName; 110 } 111 } 112 113 private boolean autoplay; 114 115 private boolean loop; 116 117 private boolean muted; 118 119 private boolean controls = true; 120 121 private Preload preload; 122 123 private String startTime; 124 125 private String endTime; 126 127 private String mediaGroup; 128 129 private Cors crossOrigin; 130 131 private String type; 132 133 private PageParameters pageParameters; 134 135 private final ResourceReference resourceReference; 136 137 private final String url; 138 139 /** 140 * Constructor. 141 * 142 * @param id 143 * The component id 144 */ 145 public MediaComponent(String id) 146 { 147 this(id, null, null, null, null); 148 } 149 150 /** 151 * Constructor. 152 * 153 * @param id 154 * The component id 155 * @param model 156 * The component model 157 */ 158 public MediaComponent(String id, IModel<?> model) 159 { 160 this(id, model, null, null, null); 161 } 162 163 /** 164 * Creates a media component 165 * 166 * @param id 167 * The component id 168 * @param resourceReference 169 * the resource reference of the media file 170 */ 171 public MediaComponent(String id, ResourceReference resourceReference) 172 { 173 this(id, null, null, null, resourceReference); 174 } 175 176 /** 177 * Creates a media component 178 * 179 * @param id 180 * The component id 181 * @param model 182 * the internally used model 183 * @param resourceReference 184 * the resource reference of the media file 185 */ 186 public MediaComponent(String id, IModel<?> model, ResourceReference resourceReference) 187 { 188 this(id, model, null, null, resourceReference); 189 } 190 191 /** 192 * Creates a media component 193 * 194 * @param id 195 * The component id 196 * @param resourceReference 197 * the resource reference of the media file 198 * @param pageParameters 199 * the page parameters to be used to be prepended to the media URL 200 */ 201 public MediaComponent(String id, ResourceReference resourceReference, 202 PageParameters pageParameters) 203 { 204 this(id, null, null, pageParameters, resourceReference); 205 } 206 207 /** 208 * Creates a media component 209 * 210 * @param id 211 * The component id 212 * @param model 213 * the internally used model 214 * @param resourceReference 215 * the resource reference of the media file 216 * @param pageParameters 217 * the page parameters to be used to be prepended to the media URL 218 */ 219 public MediaComponent(String id, IModel<?> model, ResourceReference resourceReference, 220 PageParameters pageParameters) 221 { 222 this(id, model, null, pageParameters, resourceReference); 223 } 224 225 /** 226 * Creates a media component 227 * 228 * @param id 229 * The component id 230 * @param url 231 * an external URL to be used for the media component 232 */ 233 public MediaComponent(String id, String url) 234 { 235 this(id, null, url, null, null); 236 } 237 238 /** 239 * Creates a media component 240 * 241 * @param id 242 * The component id 243 * @param model 244 * the internally used model 245 * @param url 246 * an external URL to be used for the media component 247 */ 248 public MediaComponent(String id, IModel<?> model, String url) 249 { 250 this(id, model, url, null, null); 251 } 252 253 /** 254 * Creates a media component 255 * 256 * @param id 257 * The component id 258 * @param model 259 * the internally used model 260 * @param url 261 * an external URL to be used for the media component 262 * @param pageParameters 263 * the page parameters to be used to be prepended to the media URL 264 */ 265 public MediaComponent(String id, IModel<?> model, String url, PageParameters pageParameters) 266 { 267 this(id, model, url, pageParameters, null); 268 } 269 270 private MediaComponent(String id, IModel<?> model, String url, PageParameters pageParameters, 271 ResourceReference resourceReference) 272 { 273 super(id, model); 274 this.url = url; 275 this.pageParameters = pageParameters; 276 this.resourceReference = resourceReference; 277 } 278 279 @Override 280 protected void onComponentTag(ComponentTag tag) 281 { 282 super.onComponentTag(tag); 283 284 // The time management is used to set the start / stop 285 // time in seconds of the movie to be played back 286 String timeManagement = ""; 287 if (startTime != null) 288 { 289 timeManagement += "#t=" + startTime + (endTime != null ? "," + endTime : ""); 290 } 291 292 if (resourceReference != null) 293 { 294 CharSequence urlToMediaReference = RequestCycle.get().urlFor(resourceReference, 295 pageParameters); 296 tag.put("src", urlToMediaReference + timeManagement); 297 } 298 else if (url != null) 299 { 300 Url encoded = new PageParametersEncoder().encodePageParameters(pageParameters); 301 String queryString = encoded.getQueryString(); 302 tag.put("src", url + (queryString != null ? "?" + queryString : "") + timeManagement); 303 } 304 305 String mg = getMediaGroup(); 306 if (mg != null) 307 { 308 tag.put("mediagroup", mg); 309 } 310 311 if (isAutoplay()) 312 { 313 tag.put("autoplay", "autoplay"); 314 } 315 316 if (isLooping()) 317 { 318 tag.put("loop", "loop"); 319 } 320 321 if (isMuted()) 322 { 323 tag.put("muted", "muted"); 324 } 325 326 if (hasControls()) 327 { 328 tag.put("controls", "controls"); 329 } 330 331 Preload _preload = getPreload(); 332 if (_preload != null) 333 { 334 tag.put("preload", _preload.getRealName()); 335 } 336 337 Cors cors = getCrossOrigin(); 338 if (cors != null) 339 { 340 tag.put("crossorigin", cors.getRealName()); 341 } 342 343 String type = getType(); 344 if (type != null) 345 { 346 tag.put("type", type); 347 } 348 } 349 350 /** 351 * If the playback is autoplayed on load 352 * 353 * @return If the playback is autoplayed on load 354 */ 355 public boolean isAutoplay() 356 { 357 return autoplay; 358 } 359 360 /** 361 * Sets the playback to be autoplayed on load 362 * 363 * @param autoplay 364 * If the playback is autoplayed on load 365 */ 366 public void setAutoplay(boolean autoplay) 367 { 368 this.autoplay = autoplay; 369 } 370 371 /** 372 * If the playback is looped 373 * 374 * @return If the playback is looped 375 */ 376 public boolean isLooping() 377 { 378 return loop; 379 } 380 381 /** 382 * Sets the playback to be looped 383 * 384 * @param loop 385 * If the playback is looped 386 */ 387 public void setLooping(boolean loop) 388 { 389 this.loop = loop; 390 } 391 392 /** 393 * Gets the page parameter applied to the URL of the media component 394 * 395 * @return the page parameter applied to the URL of the media component 396 */ 397 public PageParameters getPageParameters() 398 { 399 return pageParameters; 400 } 401 402 /** 403 * Sets the page parameter applied to the URL of the media component 404 * 405 * @param pageParameters 406 * the page parameter which are going to be applied to the URL of the media component 407 */ 408 public void setPageParameters(PageParameters pageParameters) 409 { 410 this.pageParameters = pageParameters; 411 } 412 413 /** 414 * If the playback is muted initially 415 * 416 * @return If the playback is muted initially 417 */ 418 public boolean isMuted() 419 { 420 return muted; 421 } 422 423 /** 424 * Sets the playback muted initially 425 * 426 * @param muted 427 * If the playback is muted initially 428 */ 429 public void setMuted(boolean muted) 430 { 431 this.muted = muted; 432 } 433 434 /** 435 * If the controls are going to be displayed 436 * 437 * @return if the controls are going to displayed 438 */ 439 public boolean hasControls() 440 { 441 return controls; 442 } 443 444 /** 445 * Sets if the controls are going to be displayed 446 * 447 * @param controls 448 * if the controls are going to displayed 449 */ 450 public void setControls(Boolean controls) 451 { 452 this.controls = controls; 453 } 454 455 /** 456 * The type of preload 457 * 458 * @see #setPreload(Preload) 459 * 460 * @return the preload 461 */ 462 public Preload getPreload() 463 { 464 return preload; 465 } 466 467 /** 468 * Sets the type of preload. 469 * <ul> 470 * <li><b>none</b>: Hints to the user agent that either the author does not expect the user to 471 * need the media resource, or that the server wants to minimise unnecessary traffic.</li> 472 * 473 * <li><b>metadata</b>: Hints to the user agent that the author does not expect the user to need 474 * the media resource, but that fetching the resource metadata (dimensions, first frame, track 475 * list, duration, etc) is reasonable.</li> 476 * 477 * <li><b>auto</b>: Hints to the user agent that the user agent can put the user's needs first 478 * without risk to the server, up to and including optimistically downloading the entire 479 * resource.</li> 480 * </ul> 481 * </p> 482 * 483 * @param preload 484 * the type of the preload 485 */ 486 public void setPreload(Preload preload) 487 { 488 this.preload = preload; 489 } 490 491 /** 492 * Gets the position at which the media component starts the playback 493 * 494 * @see #setStartTime(String) 495 * 496 * @return the time at which position the media component starts the playback 497 */ 498 public String getStartTime() 499 { 500 return startTime; 501 } 502 503 /** 504 * Sets the position at which the media component starts the playback<br> 505 * <br> 506 * t=<b>10</b>,20<br> 507 * t=<b>npt:10</b>,20<br> 508 * <br> 509 * 510 * t=<b>120s</b>,121.5s<br> 511 * t=<b>npt:120</b>,0:02:01.5<br> 512 * <br> 513 * 514 * t=<b>smpte-30:0:02:00</b>,0:02:01:15<br> 515 * t=<b>smpte-25:0:02:00:00</b>,0:02:01:12.1<br> 516 * <br> 517 * 518 * t=<b>clock:20090726T111901Z</b>,20090726T121901Z 519 * 520 * @param startTime 521 * the time at which position the media component starts the playback 522 */ 523 public void setStartTime(String startTime) 524 { 525 this.startTime = startTime; 526 } 527 528 /** 529 * Gets the position at which the media component stops the playback 530 * 531 * @see #setEndTime(String) 532 * 533 * @return the time at which position the media component stops the playback 534 */ 535 public String getEndTime() 536 { 537 return endTime; 538 } 539 540 /** 541 * Sets the position at which the media component stops the playback<br> 542 * <br> 543 * t=10,<b>20</b><br> 544 * t=npt:10,<b>20</b><br> 545 * <br> 546 * 547 * t=120s,<b>121.5s</b><br> 548 * t=npt:120,<b>0:02:01.5</b><br> 549 * <br> 550 * 551 * t=smpte-30:0:02:00,<b>0:02:01:15</b><br> 552 * t=smpte-25:0:02:00:00,<b>0:02:01:12.1</b><br> 553 * <br> 554 * 555 * t=clock:20090726T111901Z,<b>20090726T121901Z</b> 556 * 557 * @param endTime 558 * the time at which position the media component stops the playback 559 */ 560 public void setEndTime(String endTime) 561 { 562 this.endTime = endTime; 563 } 564 565 /** 566 * Gets the media group. 567 * 568 * @return the media group 569 */ 570 public String getMediaGroup() 571 { 572 return mediaGroup; 573 } 574 575 /** 576 * Sets the media group 577 * 578 * @param mediaGroup 579 * to be set 580 */ 581 public void setMediaGroup(String mediaGroup) 582 { 583 this.mediaGroup = mediaGroup; 584 } 585 586 /** 587 * Gets the cross origin settings 588 * 589 * @see #setCrossOrigin(Cors) 590 * 591 * @return the cross origins settings 592 */ 593 public Cors getCrossOrigin() 594 { 595 return crossOrigin; 596 } 597 598 /** 599 * Sets the cross origin settings<br> 600 * <br> 601 * 602 * <b>ANONYMOUS</b>: Cross-origin CORS requests for the element will not have the credentials 603 * flag set.<br> 604 * <br> 605 * <b>USER_CREDENTIALS</b>: Cross-origin CORS requests for the element will have the credentials 606 * flag set.<br> 607 * <br> 608 * <b>NO_CORS</b>: The empty string is also a valid keyword, and maps to the Anonymous state. 609 * The attribute's invalid value default is the Anonymous state. The missing value default, used 610 * when the attribute is omitted, is the No CORS state 611 * 612 * @param crossOrigin 613 * the cross origins settings to set 614 */ 615 public void setCrossOrigin(Cors crossOrigin) 616 { 617 this.crossOrigin = crossOrigin; 618 } 619 620 /** 621 * Gets the type 622 * 623 * @see #setType(String) 624 * 625 * @return the type of this media element 626 */ 627 public String getType() 628 { 629 return type; 630 } 631 632 /** 633 * Sets the type<br> 634 * <br> 635 * 636 * * The following list shows some examples of how to use the codecs= MIME parameter in the type 637 * attribute.<br> 638 * <br> 639 * 640 * H.264 Constrained baseline profile video (main and extended video compatible) level 3 and 641 * Low-Complexity AAC audio in MP4 container<br> 642 * <source src='video.mp4' <b>type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"'</b>><br> 643 * H.264 Extended profile video (baseline-compatible) level 3 and Low-Complexity AAC audio in 644 * MP4 container<br> 645 * <source src='video.mp4' <b>type='video/mp4; codecs="avc1.58A01E, mp4a.40.2"'</b>><br> 646 * H.264 Main profile video level 3 and Low-Complexity AAC audio in MP4 container<br> 647 * <source src='video.mp4' <b>type='video/mp4; codecs="avc1.4D401E, mp4a.40.2"'</b>><br> 648 * H.264 'High' profile video (incompatible with main, baseline, or extended profiles) level 3 649 * and Low-Complexity AAC audio in MP4 container<br> 650 * <source src='video.mp4' <b>type='video/mp4; codecs="avc1.64001E, mp4a.40.2"'</b>><br> 651 * MPEG-4 Visual Simple Profile Level 0 video and Low-Complexity AAC audio in MP4 container<br> 652 * <source src='video.mp4' <b>type='video/mp4; codecs="mp4v.20.8, mp4a.40.2"'</b>><br> 653 * MPEG-4 Advanced Simple Profile Level 0 video and Low-Complexity AAC audio in MP4 container 654 * <br> 655 * <source src='video.mp4' <b>type='video/mp4; codecs="mp4v.20.240, mp4a.40.2"'</b>><br> 656 * MPEG-4 Visual Simple Profile Level 0 video and AMR audio in 3GPP container<br> 657 * <source src='video.3gp' <b>type='video/3gpp; codecs="mp4v.20.8, samr"'</b>><br> 658 * Theora video and Vorbis audio in Ogg container<br> 659 * <source src='video.ogv' <b>type='video/ogg; codecs="theora, vorbis"'</b>><br> 660 * Theora video and Speex audio in Ogg container<br> 661 * <source src='video.ogv' <b>type='video/ogg; codecs="theora, speex"'</b>><br> 662 * Vorbis audio alone in Ogg container<br> 663 * <source src='audio.ogg' <b>type='audio/ogg; codecs=vorbis'</b>><br> 664 * Speex audio alone in Ogg container<br> 665 * <source src='audio.spx' <b>type='audio/ogg; codecs=speex'</b>><br> 666 * FLAC audio alone in Ogg container<br> 667 * <source src='audio.oga' <b>type='audio/ogg; codecs=flac'</b>><br> 668 * Dirac video and Vorbis audio in Ogg container<br> 669 * <source src='video.ogv' <b>type='video/ogg; codecs="dirac, vorbis"'</b>><br> 670 * Theora video and Vorbis audio in Matroska container<br> 671 * <source src='video.mkv' <b>type='video/x-matroska; codecs="theora, vorbis"'</b>><br> 672 * 673 * @param type 674 * the type of this media element 675 */ 676 public void setType(String type) 677 { 678 this.type = type; 679 } 680}