View Javadoc
1   /*
2    * #%L
3    * wcm.io
4    * %%
5    * Copyright (C) 2014 wcm.io
6    * %%
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   *
11   *      http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   * #L%
19   */
20  package io.wcm.handler.mediasource.dam.markup;
21  
22  import java.util.ArrayList;
23  import java.util.HashMap;
24  import java.util.List;
25  import java.util.Map;
26  
27  import org.apache.sling.api.SlingHttpServletRequest;
28  import org.apache.sling.api.resource.Resource;
29  import org.apache.sling.api.resource.ResourceResolver;
30  import org.apache.sling.caconfig.resource.ConfigurationResourceResolver;
31  import org.apache.sling.models.annotations.Model;
32  import org.apache.sling.models.annotations.injectorspecific.OSGiService;
33  import org.apache.sling.models.annotations.injectorspecific.Self;
34  import org.apache.sling.models.annotations.injectorspecific.SlingObject;
35  import org.jetbrains.annotations.NotNull;
36  import org.jetbrains.annotations.Nullable;
37  import org.osgi.annotation.versioning.ConsumerType;
38  import org.slf4j.Logger;
39  import org.slf4j.LoggerFactory;
40  
41  import com.day.cq.dam.api.Asset;
42  import com.day.cq.dam.commons.util.PrefixRenditionPicker;
43  import com.day.cq.dam.video.VideoConstants;
44  import com.day.cq.dam.video.VideoProfile;
45  
46  import io.wcm.handler.commons.dom.HtmlElement;
47  import io.wcm.handler.commons.dom.Video;
48  import io.wcm.handler.media.Dimension;
49  import io.wcm.handler.media.Media;
50  import io.wcm.handler.media.markup.MediaMarkupBuilderUtil;
51  import io.wcm.handler.media.spi.MediaMarkupBuilder;
52  import io.wcm.handler.url.UrlHandler;
53  
54  /**
55   * Default implementation of {@link MediaMarkupBuilder} for DAM video assets.
56   */
57  @Model(adaptables = {
58      SlingHttpServletRequest.class, Resource.class
59  })
60  @ConsumerType
61  public class DamVideoMediaMarkupBuilder implements MediaMarkupBuilder {
62  
63    private static final String H264_PROFILE = "format_aac";
64    private static final String OGG_PROFILE = "format_ogg";
65    private static final String LEGACY_H264_PROFILE = "hq"; // for AEM 6.3
66    private static final String LEGACY_OGG_PROFILE = "firefoxhq"; // for AEM 6.3
67    private static final List<String> VIDEO_PROFILE_NAMES = List.of(H264_PROFILE, OGG_PROFILE,
68        LEGACY_H264_PROFILE, LEGACY_OGG_PROFILE);
69  
70    private static final Logger log = LoggerFactory.getLogger(DamVideoMediaMarkupBuilder.class);
71  
72    @SlingObject
73    private ResourceResolver resourceResolver;
74    @Self
75    private UrlHandler urlHandler;
76    @OSGiService
77    private ConfigurationResourceResolver configurationResourceResolver;
78  
79    @Override
80    public final boolean accepts(@NotNull Media media) {
81      if (!media.isValid()) {
82        return false;
83      }
84      Asset asset = getDamAsset(media);
85      if (asset != null) {
86        return asset.getRendition(new PrefixRenditionPicker(VideoConstants.RENDITION_PREFIX)) != null;
87      }
88      else {
89        return false;
90      }
91    }
92  
93    /**
94     * Return video profile names stored below /etc/dam/video supported by this markup builder.
95     * @return Video profile names
96     */
97    protected List<String> getVideoProfileNames() {
98      return VIDEO_PROFILE_NAMES;
99    }
100 
101   /**
102    * Return video profiles supported by this markup builder.
103    * @return Video profiles
104    */
105   protected List<VideoProfile> getVideoProfiles() {
106     List<VideoProfile> profiles = new ArrayList<>();
107     for (String profileName : getVideoProfileNames()) {
108       VideoProfile profile = getVideoProfile(profileName);
109       if (profile != null) {
110         profiles.add(profile);
111       }
112       else {
113         log.debug("DAM video profile with name '{}' does not exist.", profileName);
114       }
115     }
116     return profiles;
117   }
118 
119   private VideoProfile getVideoProfile(String profileName) {
120     return VideoProfile.get(resourceResolver, configurationResourceResolver, profileName);
121   }
122 
123   /**
124    * @param media Media metadata
125    * @return DAM asset or null
126    */
127   protected @Nullable Asset getDamAsset(Media media) {
128     io.wcm.handler.media.Asset asset = media.getAsset();
129     if (asset != null) {
130       return asset.adaptTo(Asset.class);
131     }
132     return null;
133   }
134 
135   @Override
136   public final HtmlElement build(@NotNull Media media) {
137     return getVideoPlayerElement(media);
138   }
139 
140   /**
141    * Build HTML5 video player element
142    * @param media Media metadata
143    * @return Media element
144    */
145   protected Video getVideoPlayerElement(@NotNull Media media) {
146     Dimension dimension = MediaMarkupBuilderUtil.getMediaformatDimension(media);
147 
148     Video video = new Video();
149     video.setWidth(dimension.getWidth());
150     video.setHeight(dimension.getHeight());
151     video.setControls(true);
152 
153     // add video sources for each video profile
154     addSources(video, media);
155 
156     return video;
157   }
158 
159   /**
160    * Add sources for HTML5 video player
161    * @param video Video
162    * @param media Media metadata
163    */
164   protected void addSources(Video video, Media media) {
165     Asset asset = getDamAsset(media);
166     if (asset == null) {
167       return;
168     }
169 
170     for (VideoProfile profile : getVideoProfiles()) {
171       com.day.cq.dam.api.Rendition rendition = profile.getRendition(asset);
172       if (rendition != null) {
173         video.createSource()
174         .setType(profile.getHtmlType())
175         .setSrc(urlHandler.get(rendition.getPath()).buildExternalResourceUrl(rendition.adaptTo(Resource.class)));
176       }
177     }
178   }
179 
180   /**
181    * Get additional parameters to be set as &lt;param&gt; elements on html object element for flash player.
182    * @param media Media metadata
183    * @param dimension Dimension
184    * @return Set of key/value pairs
185    */
186   protected Map<String, String> getAdditionalFlashPlayerParameters(Media media, Dimension dimension) {
187     Map<String, String> parameters = new HashMap<>();
188 
189     parameters.put("allowFullScreen", "true");
190     parameters.put("wmode", "opaque");
191 
192     return parameters;
193   }
194 
195   /**
196    * Get additional parameters to be set as flashvars parameter on html object element for flash player.
197    * @param media Media metadata
198    * @param dimension Dimension
199    * @return Set of key/value pairs
200    */
201   protected Map<String, String> getAdditionalFlashPlayerFlashVars(Media media, Dimension dimension) {
202     Map<String, String> flashvars = new HashMap<>();
203 
204     flashvars.put("autoPlay", "false");
205     flashvars.put("loop", "false");
206 
207     return flashvars;
208   }
209 
210   @Override
211   public final boolean isValidMedia(@NotNull HtmlElement element) {
212     return (element instanceof Video);
213   }
214 
215 }