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     } catch (NumberFormatException e) {
110       throw new IllegalStateException("Bit rate was malformatted: " + e.getMessage());
111     }
112 
113     // frame rate
114     try {
115       String strFrameRate = (String) xpath.evaluate("framerate/text()", node, XPathConstants.STRING);
116       if (StringUtils.isNotEmpty(strFrameRate))
117         vs.frameRate = Float.valueOf(strFrameRate.trim());
118     } catch (NumberFormatException e) {
119       throw new IllegalStateException("Frame rate was malformatted: " + e.getMessage());
120     }
121 
122     // resolution
123     String res = (String) xpath.evaluate("resolution/text()", node, XPathConstants.STRING);
124     if (StringUtils.isNotEmpty(res)) {
125       vs.resolution = res;
126     }
127 
128     // interlacing
129     String scanType = (String) xpath.evaluate("scantype/@type", node, XPathConstants.STRING);
130     if (StringUtils.isNotEmpty(scanType)) {
131       if (vs.scanType == null)
132         vs.scanType = new Scan();
133       vs.scanType.type = ScanType.fromString(scanType);
134     }
135 
136     String scanOrder = (String) xpath.evaluate("interlacing/@order", node, XPathConstants.STRING);
137     if (StringUtils.isNotEmpty(scanOrder)) {
138       if (vs.scanType == null)
139         vs.scanType = new Scan();
140       vs.scanType.order = ScanOrder.fromString(scanOrder);
141     }
142 
143     return vs;
144   }
145 
146   /**
147    * @see org.opencastproject.mediapackage.ManifestContributor#toManifest(org.w3c.dom.Document,
148    *      org.opencastproject.mediapackage.MediaPackageSerializer)
149    */
150   @Override
151   public Node toManifest(Document document, MediaPackageSerializer serializer) {
152     Element node = document.createElement("video");
153     addCommonManifestElements(node, document, serializer);
154 
155     // Resolution
156     Element resolutionNode = document.createElement("resolution");
157     resolutionNode.appendChild(document.createTextNode(resolution));
158     node.appendChild(resolutionNode);
159 
160     // Interlacing
161     if (scanType != null) {
162       Element interlacingNode = document.createElement("scantype");
163       interlacingNode.setAttribute("type", scanType.toString());
164       if (scanType.order != null)
165         interlacingNode.setAttribute("order", scanType.order.toString());
166       node.appendChild(interlacingNode);
167     }
168 
169     // Bit rate
170     if (bitRate != null) {
171       Element bitrateNode = document.createElement("bitrate");
172       bitrateNode.appendChild(document.createTextNode(bitRate.toString()));
173       node.appendChild(bitrateNode);
174     }
175 
176     // Frame rate
177     if (frameRate != null) {
178       Element framerateNode = document.createElement("framerate");
179       framerateNode.appendChild(document.createTextNode(frameRate.toString()));
180       node.appendChild(framerateNode);
181     }
182 
183     return node;
184   }
185 
186   @Override
187   public Float getBitRate() {
188     return bitRate;
189   }
190 
191   @Override
192   public Float getFrameRate() {
193     return frameRate;
194   }
195 
196   @Override
197   public Integer getFrameWidth() {
198     try {
199       String[] s = resolution.trim().split("x");
200       if (s.length != 2)
201         throw new IllegalStateException("video size must be of the form <hsize>x<vsize>, found " + resolution);
202       return Integer.valueOf(s[0].trim());
203     } catch (NumberFormatException e) {
204       throw new IllegalStateException("Resolution was malformatted: " + e.getMessage());
205     }
206   }
207 
208   @Override
209   public Integer getFrameHeight() {
210     try {
211       String[] s = resolution.trim().split("x");
212       if (s.length != 2)
213         throw new IllegalStateException("video size must be of the form <hsize>x<vsize>, found " + resolution);
214       return Integer.valueOf(s[1].trim());
215     } catch (NumberFormatException e) {
216       throw new IllegalStateException("Resolution was malformatted: " + e.getMessage());
217     }
218   }
219 
220   @Override
221   public ScanType getScanType() {
222     return scanType != null ? scanType.type : null;
223   }
224 
225   @Override
226   public ScanOrder getScanOrder() {
227     return scanType != null ? scanType.order : null;
228   }
229 
230   // Setter
231 
232   public void setBitRate(Float bitRate) {
233     this.bitRate = bitRate;
234   }
235 
236   public void setFrameRate(Float frameRate) {
237     this.frameRate = frameRate;
238   }
239 
240   public void setFrameWidth(Integer frameWidth) {
241     this.frameWidth = frameWidth;
242     if (frameWidth != null && frameHeight != null)
243       updateResolution();
244   }
245 
246   public void setFrameHeight(Integer frameHeight) {
247     this.frameHeight = frameHeight;
248     if (frameWidth != null && frameHeight != null)
249       updateResolution();
250   }
251 
252   private void updateResolution() {
253     resolution = frameWidth.toString() + "x" + frameHeight.toString();
254   }
255 
256   public void setScanType(ScanType scanType) {
257     if (scanType == null)
258       return;
259     if (this.scanType == null)
260       this.scanType = new Scan();
261     this.scanType.type = scanType;
262   }
263 
264   public void setScanOrder(ScanOrder scanOrder) {
265     if (scanOrder == null)
266       return;
267     if (this.scanType == null)
268       this.scanType = new Scan();
269     this.scanType.order = scanOrder;
270   }
271 }