You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AddVideoToPptx.java.txt 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. /*
  2. * ====================================================================
  3. * Licensed to the Apache Software Foundation (ASF) under one or more
  4. * contributor license agreements. See the NOTICE file distributed with
  5. * this work for additional information regarding copyright ownership.
  6. * The ASF licenses this file to You under the Apache License, Version 2.0
  7. * (the "License"); you may not use this file except in compliance with
  8. * the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. * ====================================================================
  18. */
  19. package org.apache.poi.xslf.usermodel;
  20. import java.awt.Rectangle;
  21. import java.awt.image.BufferedImage;
  22. import java.io.ByteArrayOutputStream;
  23. import java.io.FileOutputStream;
  24. import java.io.IOException;
  25. import java.io.InputStream;
  26. import java.io.OutputStream;
  27. import java.net.URL;
  28. import java.text.DecimalFormat;
  29. import javax.imageio.ImageIO;
  30. import javax.xml.namespace.QName;
  31. import org.apache.poi.openxml4j.opc.PackagePart;
  32. import org.apache.poi.openxml4j.opc.PackagePartName;
  33. import org.apache.poi.openxml4j.opc.PackageRelationship;
  34. import org.apache.poi.openxml4j.opc.PackagingURIHelper;
  35. import org.apache.poi.openxml4j.opc.TargetMode;
  36. import org.apache.poi.sl.usermodel.PictureData.PictureType;
  37. import org.apache.xmlbeans.XmlCursor;
  38. import org.openxmlformats.schemas.drawingml.x2006.main.CTHyperlink;
  39. import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId;
  40. import org.openxmlformats.schemas.presentationml.x2006.main.CTApplicationNonVisualDrawingProps;
  41. import org.openxmlformats.schemas.presentationml.x2006.main.CTExtension;
  42. import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture;
  43. import org.openxmlformats.schemas.presentationml.x2006.main.CTSlide;
  44. import org.openxmlformats.schemas.presentationml.x2006.main.CTTLCommonMediaNodeData;
  45. import org.openxmlformats.schemas.presentationml.x2006.main.CTTLCommonTimeNodeData;
  46. import org.openxmlformats.schemas.presentationml.x2006.main.CTTimeNodeList;
  47. import org.openxmlformats.schemas.presentationml.x2006.main.STTLTimeIndefinite;
  48. import org.openxmlformats.schemas.presentationml.x2006.main.STTLTimeNodeFillType;
  49. import org.openxmlformats.schemas.presentationml.x2006.main.STTLTimeNodeRestartType;
  50. import org.openxmlformats.schemas.presentationml.x2006.main.STTLTimeNodeType;
  51. import com.xuggle.mediatool.IMediaReader;
  52. import com.xuggle.mediatool.MediaListenerAdapter;
  53. import com.xuggle.mediatool.ToolFactory;
  54. import com.xuggle.mediatool.event.IVideoPictureEvent;
  55. import com.xuggle.xuggler.Global;
  56. import com.xuggle.xuggler.IContainer;
  57. import com.xuggle.xuggler.io.InputOutputStreamHandler;
  58. /**
  59. * Adding multiple videos to a slide
  60. *
  61. * need the Xuggler 5.4 jars:
  62. * <repositories>
  63. * <repository>
  64. * <id>xuggle repo</id>
  65. * <url>http://xuggle.googlecode.com/svn/trunk/repo/share/java/</url>
  66. * </repository>
  67. * </repositories>
  68. * ...
  69. * <dependency>
  70. * <groupId>xuggle</groupId>
  71. * <artifactId>xuggle-xuggler</artifactId>
  72. * <version>5.4</version>
  73. * </dependency>
  74. *
  75. * @see <a href="http://stackoverflow.com/questions/15197300/apache-poi-xslf-adding-movie-to-the-slide">Apache POI XSLF Adding movie to the slide</a>
  76. * @see <a href="http://apache-poi.1045710.n5.nabble.com/Question-about-embedded-video-in-PPTX-files-tt5718461.html">Question about embedded video in PPTX files</a>
  77. */
  78. public class AddVideoToPptx {
  79. static DecimalFormat df_time = new DecimalFormat("0.####");
  80. public static void main(String[] args) throws Exception {
  81. URL video = new URL("http://archive.org/download/test-mpeg/test-mpeg.mpg");
  82. // URL video = new URL("file:test-mpeg.mpg");
  83. XMLSlideShow pptx = new XMLSlideShow();
  84. // add video file
  85. String videoFileName = video.getPath().substring(video.getPath().lastIndexOf('/')+1);
  86. PackagePartName partName = PackagingURIHelper.createPartName("/ppt/media/"+videoFileName);
  87. PackagePart part = pptx.getPackage().createPart(partName, "video/mpeg");
  88. OutputStream partOs = part.getOutputStream();
  89. InputStream fis = video.openStream();
  90. byte buf[] = new byte[1024];
  91. for (int readBytes; (readBytes = fis.read(buf)) != -1; partOs.write(buf, 0, readBytes));
  92. fis.close();
  93. partOs.close();
  94. XSLFSlide slide1 = pptx.createSlide();
  95. XSLFPictureShape pv1 = addPreview(pptx, slide1, part, 5, 50, 50);
  96. addVideo(pptx, slide1, part, pv1, 5);
  97. addTimingInfo(slide1, pv1);
  98. XSLFPictureShape pv2 = addPreview(pptx, slide1, part, 9, 50, 250);
  99. addVideo(pptx, slide1, part, pv2, 9);
  100. addTimingInfo(slide1, pv2);
  101. FileOutputStream fos = new FileOutputStream("pptx-with-video.pptx");
  102. pptx.write(fos);
  103. fos.close();
  104. pptx.close();
  105. }
  106. static XSLFPictureShape addPreview(XMLSlideShow pptx, XSLFSlide slide1, PackagePart videoPart, double seconds, int x, int y) throws IOException {
  107. // get preview after 5 sec.
  108. IContainer ic = IContainer.make();
  109. InputOutputStreamHandler iosh = new InputOutputStreamHandler(videoPart.getInputStream());
  110. if (ic.open(iosh, IContainer.Type.READ, null) < 0) return null;
  111. IMediaReader mediaReader = ToolFactory.makeReader(ic);
  112. // stipulate that we want BufferedImages created in BGR 24bit color space
  113. mediaReader.setBufferedImageTypeToGenerate(BufferedImage.TYPE_3BYTE_BGR);
  114. ImageSnapListener isl = new ImageSnapListener(seconds);
  115. mediaReader.addListener(isl);
  116. // read out the contents of the media file and
  117. // dispatch events to the attached listener
  118. while (!isl.hasFired && mediaReader.readPacket() == null) ;
  119. mediaReader.close();
  120. ic.close();
  121. // add snapshot
  122. BufferedImage image1 = isl.image;
  123. ByteArrayOutputStream bos = new ByteArrayOutputStream();
  124. ImageIO.write(image1, "jpeg", bos);
  125. XSLFPictureData snap = pptx.addPicture(bos.toByteArray(), PictureType.JPEG);
  126. XSLFPictureShape pic1 = slide1.createPicture(snap);
  127. pic1.setAnchor(new Rectangle(x, y, image1.getWidth(), image1.getHeight()));
  128. return pic1;
  129. }
  130. static void addVideo(XMLSlideShow pptx, XSLFSlide slide1, PackagePart videoPart, XSLFPictureShape pic1, double seconds) throws IOException {
  131. // add video shape
  132. PackagePartName partName = videoPart.getPartName();
  133. PackageRelationship prsEmbed1 = slide1.getPackagePart().addRelationship(partName, TargetMode.INTERNAL, "http://schemas.microsoft.com/office/2007/relationships/media");
  134. PackageRelationship prsExec1 = slide1.getPackagePart().addRelationship(partName, TargetMode.INTERNAL, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/video");
  135. CTPicture xpic1 = (CTPicture)pic1.getXmlObject();
  136. CTHyperlink link1 = xpic1.getNvPicPr().getCNvPr().addNewHlinkClick();
  137. link1.setId("");
  138. link1.setAction("ppaction://media");
  139. // add video relation
  140. CTApplicationNonVisualDrawingProps nvPr = xpic1.getNvPicPr().getNvPr();
  141. nvPr.addNewVideoFile().setLink(prsExec1.getId());
  142. CTExtension ext = nvPr.addNewExtLst().addNewExt();
  143. // see http://msdn.microsoft.com/en-us/library/dd950140(v=office.12).aspx
  144. ext.setUri("{DAA4B4D4-6D71-4841-9C94-3DE7FCFB9230}");
  145. String p14Ns = "http://schemas.microsoft.com/office/powerpoint/2010/main";
  146. XmlCursor cur = ext.newCursor();
  147. cur.toEndToken();
  148. cur.beginElement(new QName(p14Ns, "media", "p14"));
  149. cur.insertNamespace("p14", p14Ns);
  150. cur.insertAttributeWithValue(new QName(STRelationshipId.type.getName().getNamespaceURI(), "embed"), prsEmbed1.getId());
  151. cur.beginElement(new QName(p14Ns, "trim", "p14"));
  152. cur.insertAttributeWithValue("st", df_time.format(seconds*1000.0));
  153. cur.dispose();
  154. }
  155. static void addTimingInfo(XSLFSlide slide1, XSLFPictureShape pic1) {
  156. // add slide timing information, so video can be controlled
  157. CTSlide xslide = slide1.getXmlObject();
  158. CTTimeNodeList ctnl;
  159. if (!xslide.isSetTiming()) {
  160. CTTLCommonTimeNodeData ctn = xslide.addNewTiming().addNewTnLst().addNewPar().addNewCTn();
  161. ctn.setDur(STTLTimeIndefinite.INDEFINITE);
  162. ctn.setRestart(STTLTimeNodeRestartType.NEVER);
  163. ctn.setNodeType(STTLTimeNodeType.TM_ROOT);
  164. ctnl = ctn.addNewChildTnLst();
  165. } else {
  166. ctnl = xslide.getTiming().getTnLst().getParArray(0).getCTn().getChildTnLst();
  167. }
  168. CTTLCommonMediaNodeData cmedia = ctnl.addNewVideo().addNewCMediaNode();
  169. cmedia.setVol(80000);
  170. CTTLCommonTimeNodeData ctn = cmedia.addNewCTn();
  171. ctn.setFill(STTLTimeNodeFillType.HOLD);
  172. ctn.setDisplay(false);
  173. ctn.addNewStCondLst().addNewCond().setDelay(STTLTimeIndefinite.INDEFINITE);
  174. cmedia.addNewTgtEl().addNewSpTgt().setSpid(""+pic1.getShapeId());
  175. }
  176. static class ImageSnapListener extends MediaListenerAdapter {
  177. final double SECONDS_BETWEEN_FRAMES;
  178. final long MICRO_SECONDS_BETWEEN_FRAMES;
  179. boolean hasFired = false;
  180. BufferedImage image = null;
  181. // The video stream index, used to ensure we display frames from one and
  182. // only one video stream from the media container.
  183. int mVideoStreamIndex = -1;
  184. // Time of last frame write
  185. long mLastPtsWrite = Global.NO_PTS;
  186. public ImageSnapListener(double seconds) {
  187. SECONDS_BETWEEN_FRAMES = seconds;
  188. MICRO_SECONDS_BETWEEN_FRAMES =
  189. (long)(Global.DEFAULT_PTS_PER_SECOND * SECONDS_BETWEEN_FRAMES);
  190. }
  191. @Override
  192. public void onVideoPicture(IVideoPictureEvent event) {
  193. if (event.getStreamIndex() != mVideoStreamIndex) {
  194. // if the selected video stream id is not yet set, go ahead an
  195. // select this lucky video stream
  196. if (mVideoStreamIndex != -1) return;
  197. mVideoStreamIndex = event.getStreamIndex();
  198. }
  199. long evtTS = event.getTimeStamp();
  200. // if uninitialized, back date mLastPtsWrite to get the very first frame
  201. if (mLastPtsWrite == Global.NO_PTS)
  202. mLastPtsWrite = Math.max(0, evtTS - MICRO_SECONDS_BETWEEN_FRAMES);
  203. // if it's time to write the next frame
  204. if (evtTS - mLastPtsWrite >= MICRO_SECONDS_BETWEEN_FRAMES) {
  205. if (!hasFired) {
  206. image = event.getImage();
  207. hasFired = true;
  208. }
  209. // update last write time
  210. mLastPtsWrite += MICRO_SECONDS_BETWEEN_FRAMES;
  211. }
  212. }
  213. }
  214. }