Source: ui/save_video_frame_button.js

  1. /*! @license
  2. * Shaka Player
  3. * Copyright 2016 Google LLC
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. goog.provide('shaka.ui.SaveVideoFrameButton');
  7. goog.require('shaka.ads.Utils');
  8. goog.require('shaka.cast.CastProxy');
  9. goog.require('shaka.ui.ContextMenu');
  10. goog.require('shaka.ui.Controls');
  11. goog.require('shaka.ui.Element');
  12. goog.require('shaka.ui.Enums');
  13. goog.require('shaka.ui.Locales');
  14. goog.require('shaka.ui.Localization');
  15. goog.require('shaka.ui.OverflowMenu');
  16. goog.require('shaka.ui.Utils');
  17. goog.require('shaka.util.Dom');
  18. /**
  19. * @extends {shaka.ui.Element}
  20. * @final
  21. * @export
  22. */
  23. shaka.ui.SaveVideoFrameButton = class extends shaka.ui.Element {
  24. /**
  25. * @param {!HTMLElement} parent
  26. * @param {!shaka.ui.Controls} controls
  27. */
  28. constructor(parent, controls) {
  29. super(parent, controls);
  30. /** @private {shaka.cast.CastProxy} */
  31. this.castProxy_ = this.controls.getCastProxy();
  32. const LocIds = shaka.ui.Locales.Ids;
  33. /** @private {!HTMLButtonElement} */
  34. this.button_ = shaka.util.Dom.createButton();
  35. this.button_.classList.add('shaka-save.video-frame-button');
  36. this.button_.classList.add('shaka-tooltip');
  37. /** @private {!HTMLElement} */
  38. this.icon_ = shaka.util.Dom.createHTMLElement('i');
  39. this.icon_.classList.add('material-icons-round');
  40. this.icon_.textContent = shaka.ui.Enums.MaterialDesignIcons.DOWNLOAD;
  41. this.button_.appendChild(this.icon_);
  42. const label = shaka.util.Dom.createHTMLElement('label');
  43. label.classList.add('shaka-overflow-button-label');
  44. label.classList.add('shaka-overflow-menu-only');
  45. this.nameSpan_ = shaka.util.Dom.createHTMLElement('span');
  46. this.nameSpan_.textContent =
  47. this.localization.resolve(LocIds.DOWNLOAD_VIDEO_FRAME);
  48. label.appendChild(this.nameSpan_);
  49. /** @private {!HTMLElement} */
  50. this.currentState_ = shaka.util.Dom.createHTMLElement('span');
  51. this.currentState_.classList.add('shaka-current-selection-span');
  52. label.appendChild(this.currentState_);
  53. this.button_.appendChild(label);
  54. this.updateLocalizedStrings_();
  55. this.parent.appendChild(this.button_);
  56. this.eventManager.listen(
  57. this.localization, shaka.ui.Localization.LOCALE_UPDATED, () => {
  58. this.updateLocalizedStrings_();
  59. });
  60. this.eventManager.listen(
  61. this.localization, shaka.ui.Localization.LOCALE_CHANGED, () => {
  62. this.updateLocalizedStrings_();
  63. });
  64. this.eventManager.listen(this.button_, 'click', () => {
  65. this.onClick_();
  66. });
  67. const vr = this.controls.getVR();
  68. this.eventManager.listen(vr, 'vrstatuschanged', () => {
  69. this.checkAvailability_();
  70. });
  71. this.eventManager.listen(
  72. this.adManager, shaka.ads.Utils.AD_STARTED, () => {
  73. this.checkAvailability_();
  74. });
  75. this.eventManager.listen(
  76. this.adManager, shaka.ads.Utils.AD_STOPPED, () => {
  77. this.checkAvailability_();
  78. });
  79. this.eventManager.listen(this.player, 'unloading', () => {
  80. this.checkAvailability_();
  81. });
  82. this.eventManager.listen(this.player, 'loaded', () => {
  83. this.checkAvailability_();
  84. });
  85. this.eventManager.listen(this.player, 'loaded', () => {
  86. this.checkAvailability_();
  87. });
  88. this.eventManager.listen(this.video, 'play', () => {
  89. this.checkAvailability_();
  90. });
  91. this.eventManager.listen(this.video, 'pause', () => {
  92. this.checkAvailability_();
  93. });
  94. this.eventManager.listen(this.video, 'seeking', () => {
  95. this.checkAvailability_();
  96. });
  97. this.eventManager.listen(this.controls, 'caststatuschanged', () => {
  98. this.checkAvailability_();
  99. });
  100. this.checkAvailability_();
  101. }
  102. /** @private */
  103. onClick_() {
  104. const canvas = /** @type {!HTMLCanvasElement}*/ (
  105. document.createElement('canvas'));
  106. const context = /** @type {CanvasRenderingContext2D} */ (
  107. canvas.getContext('2d'));
  108. const video = /** @type {!HTMLVideoElement} */ (
  109. this.controls.getLocalVideo());
  110. canvas.width = video.videoWidth;
  111. canvas.height = video.videoHeight;
  112. context.drawImage(video, 0, 0, canvas.width, canvas.height);
  113. const dataURL = canvas.toDataURL('image/png');
  114. const downloadLink = /** @type {!HTMLAnchorElement}*/ (
  115. document.createElement('a'));
  116. downloadLink.href = dataURL;
  117. downloadLink.download =
  118. 'videoframe_' + video.currentTime.toFixed(3) + '.png';
  119. downloadLink.click();
  120. }
  121. /**
  122. * @private
  123. */
  124. checkAvailability_() {
  125. let available = true;
  126. if (this.controls.isPlayingVR()) {
  127. available = false;
  128. }
  129. if (available && this.castProxy_.isCasting()) {
  130. available = false;
  131. }
  132. if (available &&
  133. (this.player.drmInfo() || this.player.isAudioOnly())) {
  134. available = false;
  135. }
  136. if (available && this.ad) {
  137. available = false;
  138. }
  139. if (available &&
  140. this.video.remote && this.video.remote.state != 'disconnected') {
  141. available = false;
  142. }
  143. shaka.ui.Utils.setDisplay(this.button_, available);
  144. }
  145. /**
  146. * @private
  147. */
  148. updateLocalizedStrings_() {
  149. const LocIds = shaka.ui.Locales.Ids;
  150. this.button_.ariaLabel =
  151. this.localization.resolve(LocIds.DOWNLOAD_VIDEO_FRAME);
  152. this.nameSpan_.textContent =
  153. this.localization.resolve(LocIds.DOWNLOAD_VIDEO_FRAME);
  154. }
  155. };
  156. /**
  157. * @implements {shaka.extern.IUIElement.Factory}
  158. * @final
  159. */
  160. shaka.ui.SaveVideoFrameButton.Factory = class {
  161. /** @override */
  162. create(rootElement, controls) {
  163. return new shaka.ui.SaveVideoFrameButton(rootElement, controls);
  164. }
  165. };
  166. shaka.ui.OverflowMenu.registerElement(
  167. 'save_video_frame', new shaka.ui.SaveVideoFrameButton.Factory());
  168. shaka.ui.ContextMenu.registerElement(
  169. 'save_video_frame', new shaka.ui.SaveVideoFrameButton.Factory());