View Javadoc
1   /*
2    * Licensed to The Apereo Foundation under one or more contributor license
3    * agreements. See the NOTICE file distributed with this work for additional
4    * information regarding copyright ownership.
5    *
6    *
7    * The Apereo Foundation licenses this file to you under the Educational
8    * Community License, Version 2.0 (the "License"); you may not use this file
9    * except in compliance with the License. You may obtain a copy of the License
10   * at:
11   *
12   *   http://opensource.org/licenses/ecl2.txt
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
17   * License for the specific language governing permissions and limitations under
18   * the License.
19   *
20   */
21  
22  
23  package org.opencastproject.mediapackage.track;
24  
25  import org.opencastproject.mediapackage.MediaPackageSerializer;
26  import org.opencastproject.mediapackage.VideoStream;
27  
28  import org.apache.commons.lang3.StringUtils;
29  import org.w3c.dom.Document;
30  import org.w3c.dom.Element;
31  import org.w3c.dom.Node;
32  
33  import java.util.UUID;
34  
35  import javax.xml.bind.annotation.XmlAccessType;
36  import javax.xml.bind.annotation.XmlAccessorType;
37  import javax.xml.bind.annotation.XmlAttribute;
38  import javax.xml.bind.annotation.XmlElement;
39  import javax.xml.bind.annotation.XmlType;
40  import javax.xml.xpath.XPath;
41  import javax.xml.xpath.XPathConstants;
42  import javax.xml.xpath.XPathException;
43  
44  /**
45   * Implementation of {@link org.opencastproject.mediapackage.VideoStream}.
46   */
47  @XmlAccessorType(XmlAccessType.NONE)
48  @XmlType(name = "video", namespace = "http://mediapackage.opencastproject.org")
49  public class VideoStreamImpl extends AbstractStreamImpl implements VideoStream {
50  
51    @XmlElement(name = "bitrate")
52    protected Float bitRate;
53  
54    @XmlElement(name = "framerate")
55    protected Float frameRate;
56  
57    @XmlElement(name = "resolution")
58    protected String resolution;
59  
60    protected Integer frameWidth;
61    protected Integer frameHeight;
62  
63    @XmlElement(name = "scantype")
64    protected Scan scanType = null;
65  
66    @XmlType(name = "scantype")
67    static class Scan {
68      @XmlAttribute(name = "type")
69      protected ScanType type;
70      @XmlAttribute(name = "order")
71      protected ScanOrder order;
72  
73      @Override
74      public String toString() {
75        return type.toString();
76      }
77    }
78  
79    public VideoStreamImpl() {
80      this(UUID.randomUUID().toString());
81    }
82  
83    public VideoStreamImpl(String identifier) {
84      super(identifier);
85    }
86  
87    /**
88     * Create a video stream from the XML manifest.
89     *
90     * @param streamIdHint
91     *          stream ID that has to be used if the manifest does not provide one. This is the case when reading an old
92     *          manifest.
93     */
94    public static VideoStreamImpl fromManifest(String streamIdHint, Node node, XPath xpath) throws IllegalStateException,
95            XPathException {
96      // Create stream
97      String sid = (String) xpath.evaluate("@id", node, XPathConstants.STRING);
98      if (StringUtils.isEmpty(sid)) {
99        sid = streamIdHint;
100     }
101     VideoStreamImpl vs = new VideoStreamImpl(sid);
102     partialFromManifest(vs, node, xpath);
103 
104     // bit rate
105     try {
106       String strBitrate = (String) xpath.evaluate("bitrate/text()", node, XPathConstants.STRING);
107       if (StringUtils.isNotEmpty(strBitrate)) {
108         vs.bitRate = Float.valueOf(strBitrate.trim());
109       }
110     } catch (NumberFormatException e) {
111       throw new IllegalStateException("Bit rate was malformatted: " + e.getMessage());
112     }
113 
114     // frame rate
115     try {
116       String strFrameRate = (String) xpath.evaluate("framerate/text()", node, XPathConstants.STRING);
117       if (StringUtils.isNotEmpty(strFrameRate)) {
118         vs.frameRate = Float.valueOf(strFrameRate.trim());
119       }
120     } catch (NumberFormatException e) {
121       throw new IllegalStateException("Frame rate was malformatted: " + e.getMessage());
122     }
123 
124     // resolution
125     String res = (String) xpath.evaluate("resolution/text()", node, XPathConstants.STRING);
126     if (StringUtils.isNotEmpty(res)) {
127       vs.resolution = res;
128     }
129 
130     // interlacing
131     String scanType = (String) xpath.evaluate("scantype/@type", node, XPathConstants.STRING);
132     if (StringUtils.isNotEmpty(scanType)) {
133       if (vs.scanType == null) {
134         vs.scanType = new Scan();
135       }
136       vs.scanType.type = ScanType.fromString(scanType);
137     }
138 
139     String scanOrder = (String) xpath.evaluate("interlacing/@order", node, XPathConstants.STRING);
140     if (StringUtils.isNotEmpty(scanOrder)) {
141       if (vs.scanType == null) {
142         vs.scanType = new Scan();
143       }
144       vs.scanType.order = ScanOrder.fromString(scanOrder);
145     }
146 
147     return vs;
148   }
149 
150   /**
151    * @see org.opencastproject.mediapackage.ManifestContributor#toManifest(org.w3c.dom.Document,
152    *      org.opencastproject.mediapackage.MediaPackageSerializer)
153    */
154   @Override
155   public Node toManifest(Document document, MediaPackageSerializer serializer) {
156     Element node = document.createElement("video");
157     addCommonManifestElements(node, document, serializer);
158 
159     // Resolution
160     Element resolutionNode = document.createElement("resolution");
161     resolutionNode.appendChild(document.createTextNode(resolution));
162     node.appendChild(resolutionNode);
163 
164     // Interlacing
165     if (scanType != null) {
166       Element interlacingNode = document.createElement("scantype");
167       interlacingNode.setAttribute("type", scanType.toString());
168       if (scanType.order != null) {
169         interlacingNode.setAttribute("order", scanType.order.toString());
170       }
171       node.appendChild(interlacingNode);
172     }
173 
174     // Bit rate
175     if (bitRate != null) {
176       Element bitrateNode = document.createElement("bitrate");
177       bitrateNode.appendChild(document.createTextNode(bitRate.toString()));
178       node.appendChild(bitrateNode);
179     }
180 
181     // Frame rate
182     if (frameRate != null) {
183       Element framerateNode = document.createElement("framerate");
184       framerateNode.appendChild(document.createTextNode(frameRate.toString()));
185       node.appendChild(framerateNode);
186     }
187 
188     return node;
189   }
190 
191   @Override
192   public Float getBitRate() {
193     return bitRate;
194   }
195 
196   @Override
197   public Float getFrameRate() {
198     return frameRate;
199   }
200 
201   @Override
202   public Integer getFrameWidth() {
203     try {
204       String[] s = resolution.trim().split("x");
205       if (s.length != 2) {
206         throw new IllegalStateException("video size must be of the form <hsize>x<vsize>, found " + resolution);
207       }
208       return Integer.valueOf(s[0].trim());
209     } catch (NumberFormatException e) {
210       throw new IllegalStateException("Resolution was malformatted: " + e.getMessage());
211     }
212   }
213 
214   @Override
215   public Integer getFrameHeight() {
216     try {
217       String[] s = resolution.trim().split("x");
218       if (s.length != 2) {
219         throw new IllegalStateException("video size must be of the form <hsize>x<vsize>, found " + resolution);
220       }
221       return Integer.valueOf(s[1].trim());
222     } catch (NumberFormatException e) {
223       throw new IllegalStateException("Resolution was malformatted: " + e.getMessage());
224     }
225   }
226 
227   @Override
228   public ScanType getScanType() {
229     return scanType != null ? scanType.type : null;
230   }
231 
232   @Override
233   public ScanOrder getScanOrder() {
234     return scanType != null ? scanType.order : null;
235   }
236 
237   // Setter
238 
239   public void setBitRate(Float bitRate) {
240     this.bitRate = bitRate;
241   }
242 
243   public void setFrameRate(Float frameRate) {
244     this.frameRate = frameRate;
245   }
246 
247   public void setFrameWidth(Integer frameWidth) {
248     this.frameWidth = frameWidth;
249     if (frameWidth != null && frameHeight != null) {
250       updateResolution();
251     }
252   }
253 
254   public void setFrameHeight(Integer frameHeight) {
255     this.frameHeight = frameHeight;
256     if (frameWidth != null && frameHeight != null) {
257       updateResolution();
258     }
259   }
260 
261   private void updateResolution() {
262     resolution = frameWidth.toString() + "x" + frameHeight.toString();
263   }
264 
265   public void setScanType(ScanType scanType) {
266     if (scanType == null) {
267       return;
268     }
269     if (this.scanType == null) {
270       this.scanType = new Scan();
271     }
272     this.scanType.type = scanType;
273   }
274 
275   public void setScanOrder(ScanOrder scanOrder) {
276     if (scanOrder == null) {
277       return;
278     }
279     if (this.scanType == null) {
280       this.scanType = new Scan();
281     }
282     this.scanType.order = scanOrder;
283   }
284 }