Add example for adding videos
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1728888 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
ce22cc44c4
commit
2aa39f5bdb
@ -0,0 +1,251 @@
|
|||||||
|
/*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ====================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.poi.xslf.usermodel;
|
||||||
|
|
||||||
|
import java.awt.Rectangle;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.text.DecimalFormat;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.xml.namespace.QName;
|
||||||
|
|
||||||
|
import org.apache.poi.openxml4j.opc.PackagePart;
|
||||||
|
import org.apache.poi.openxml4j.opc.PackagePartName;
|
||||||
|
import org.apache.poi.openxml4j.opc.PackageRelationship;
|
||||||
|
import org.apache.poi.openxml4j.opc.PackagingURIHelper;
|
||||||
|
import org.apache.poi.openxml4j.opc.TargetMode;
|
||||||
|
import org.apache.poi.sl.usermodel.PictureData.PictureType;
|
||||||
|
import org.apache.xmlbeans.XmlCursor;
|
||||||
|
import org.openxmlformats.schemas.drawingml.x2006.main.CTHyperlink;
|
||||||
|
import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId;
|
||||||
|
import org.openxmlformats.schemas.presentationml.x2006.main.CTApplicationNonVisualDrawingProps;
|
||||||
|
import org.openxmlformats.schemas.presentationml.x2006.main.CTExtension;
|
||||||
|
import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture;
|
||||||
|
import org.openxmlformats.schemas.presentationml.x2006.main.CTSlide;
|
||||||
|
import org.openxmlformats.schemas.presentationml.x2006.main.CTTLCommonMediaNodeData;
|
||||||
|
import org.openxmlformats.schemas.presentationml.x2006.main.CTTLCommonTimeNodeData;
|
||||||
|
import org.openxmlformats.schemas.presentationml.x2006.main.CTTimeNodeList;
|
||||||
|
import org.openxmlformats.schemas.presentationml.x2006.main.STTLTimeIndefinite;
|
||||||
|
import org.openxmlformats.schemas.presentationml.x2006.main.STTLTimeNodeFillType;
|
||||||
|
import org.openxmlformats.schemas.presentationml.x2006.main.STTLTimeNodeRestartType;
|
||||||
|
import org.openxmlformats.schemas.presentationml.x2006.main.STTLTimeNodeType;
|
||||||
|
|
||||||
|
import com.xuggle.mediatool.IMediaReader;
|
||||||
|
import com.xuggle.mediatool.MediaListenerAdapter;
|
||||||
|
import com.xuggle.mediatool.ToolFactory;
|
||||||
|
import com.xuggle.mediatool.event.IVideoPictureEvent;
|
||||||
|
import com.xuggle.xuggler.Global;
|
||||||
|
import com.xuggle.xuggler.IContainer;
|
||||||
|
import com.xuggle.xuggler.io.InputOutputStreamHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adding multiple videos to a slide
|
||||||
|
*
|
||||||
|
* need the Xuggler 5.4 jars:
|
||||||
|
* <repositories>
|
||||||
|
* <repository>
|
||||||
|
* <id>xuggle repo</id>
|
||||||
|
* <url>http://xuggle.googlecode.com/svn/trunk/repo/share/java/</url>
|
||||||
|
* </repository>
|
||||||
|
* </repositories>
|
||||||
|
* ...
|
||||||
|
* <dependency>
|
||||||
|
* <groupId>xuggle</groupId>
|
||||||
|
* <artifactId>xuggle-xuggler</artifactId>
|
||||||
|
* <version>5.4</version>
|
||||||
|
* </dependency>
|
||||||
|
*
|
||||||
|
* @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>
|
||||||
|
* @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>
|
||||||
|
*/
|
||||||
|
public class AddVideoToPptx {
|
||||||
|
static DecimalFormat df_time = new DecimalFormat("0.####");
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
URL video = new URL("http://archive.org/download/test-mpeg/test-mpeg.mpg");
|
||||||
|
// URL video = new URL("file:test-mpeg.mpg");
|
||||||
|
|
||||||
|
XMLSlideShow pptx = new XMLSlideShow();
|
||||||
|
|
||||||
|
// add video file
|
||||||
|
String videoFileName = video.getPath().substring(video.getPath().lastIndexOf('/')+1);
|
||||||
|
PackagePartName partName = PackagingURIHelper.createPartName("/ppt/media/"+videoFileName);
|
||||||
|
PackagePart part = pptx.getPackage().createPart(partName, "video/mpeg");
|
||||||
|
OutputStream partOs = part.getOutputStream();
|
||||||
|
InputStream fis = video.openStream();
|
||||||
|
byte buf[] = new byte[1024];
|
||||||
|
for (int readBytes; (readBytes = fis.read(buf)) != -1; partOs.write(buf, 0, readBytes));
|
||||||
|
fis.close();
|
||||||
|
partOs.close();
|
||||||
|
|
||||||
|
XSLFSlide slide1 = pptx.createSlide();
|
||||||
|
XSLFPictureShape pv1 = addPreview(pptx, slide1, part, 5, 50, 50);
|
||||||
|
addVideo(pptx, slide1, part, pv1, 5);
|
||||||
|
addTimingInfo(slide1, pv1);
|
||||||
|
XSLFPictureShape pv2 = addPreview(pptx, slide1, part, 9, 50, 250);
|
||||||
|
addVideo(pptx, slide1, part, pv2, 9);
|
||||||
|
addTimingInfo(slide1, pv2);
|
||||||
|
|
||||||
|
FileOutputStream fos = new FileOutputStream("pptx-with-video.pptx");
|
||||||
|
pptx.write(fos);
|
||||||
|
fos.close();
|
||||||
|
|
||||||
|
pptx.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
static XSLFPictureShape addPreview(XMLSlideShow pptx, XSLFSlide slide1, PackagePart videoPart, double seconds, int x, int y) throws IOException {
|
||||||
|
// get preview after 5 sec.
|
||||||
|
IContainer ic = IContainer.make();
|
||||||
|
InputOutputStreamHandler iosh = new InputOutputStreamHandler(videoPart.getInputStream());
|
||||||
|
if (ic.open(iosh, IContainer.Type.READ, null) < 0) return null;
|
||||||
|
|
||||||
|
IMediaReader mediaReader = ToolFactory.makeReader(ic);
|
||||||
|
|
||||||
|
// stipulate that we want BufferedImages created in BGR 24bit color space
|
||||||
|
mediaReader.setBufferedImageTypeToGenerate(BufferedImage.TYPE_3BYTE_BGR);
|
||||||
|
|
||||||
|
ImageSnapListener isl = new ImageSnapListener(seconds);
|
||||||
|
mediaReader.addListener(isl);
|
||||||
|
|
||||||
|
// read out the contents of the media file and
|
||||||
|
// dispatch events to the attached listener
|
||||||
|
while (!isl.hasFired && mediaReader.readPacket() == null) ;
|
||||||
|
|
||||||
|
mediaReader.close();
|
||||||
|
ic.close();
|
||||||
|
|
||||||
|
// add snapshot
|
||||||
|
BufferedImage image1 = isl.image;
|
||||||
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
|
ImageIO.write(image1, "jpeg", bos);
|
||||||
|
XSLFPictureData snap = pptx.addPicture(bos.toByteArray(), PictureType.JPEG);
|
||||||
|
XSLFPictureShape pic1 = slide1.createPicture(snap);
|
||||||
|
pic1.setAnchor(new Rectangle(x, y, image1.getWidth(), image1.getHeight()));
|
||||||
|
return pic1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void addVideo(XMLSlideShow pptx, XSLFSlide slide1, PackagePart videoPart, XSLFPictureShape pic1, double seconds) throws IOException {
|
||||||
|
|
||||||
|
// add video shape
|
||||||
|
PackagePartName partName = videoPart.getPartName();
|
||||||
|
PackageRelationship prsEmbed1 = slide1.getPackagePart().addRelationship(partName, TargetMode.INTERNAL, "http://schemas.microsoft.com/office/2007/relationships/media");
|
||||||
|
PackageRelationship prsExec1 = slide1.getPackagePart().addRelationship(partName, TargetMode.INTERNAL, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/video");
|
||||||
|
CTPicture xpic1 = (CTPicture)pic1.getXmlObject();
|
||||||
|
CTHyperlink link1 = xpic1.getNvPicPr().getCNvPr().addNewHlinkClick();
|
||||||
|
link1.setId("");
|
||||||
|
link1.setAction("ppaction://media");
|
||||||
|
|
||||||
|
// add video relation
|
||||||
|
CTApplicationNonVisualDrawingProps nvPr = xpic1.getNvPicPr().getNvPr();
|
||||||
|
nvPr.addNewVideoFile().setLink(prsExec1.getId());
|
||||||
|
CTExtension ext = nvPr.addNewExtLst().addNewExt();
|
||||||
|
// see http://msdn.microsoft.com/en-us/library/dd950140(v=office.12).aspx
|
||||||
|
ext.setUri("{DAA4B4D4-6D71-4841-9C94-3DE7FCFB9230}");
|
||||||
|
String p14Ns = "http://schemas.microsoft.com/office/powerpoint/2010/main";
|
||||||
|
XmlCursor cur = ext.newCursor();
|
||||||
|
cur.toEndToken();
|
||||||
|
cur.beginElement(new QName(p14Ns, "media", "p14"));
|
||||||
|
cur.insertNamespace("p14", p14Ns);
|
||||||
|
cur.insertAttributeWithValue(new QName(STRelationshipId.type.getName().getNamespaceURI(), "embed"), prsEmbed1.getId());
|
||||||
|
cur.beginElement(new QName(p14Ns, "trim", "p14"));
|
||||||
|
cur.insertAttributeWithValue("st", df_time.format(seconds*1000.0));
|
||||||
|
cur.dispose();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void addTimingInfo(XSLFSlide slide1, XSLFPictureShape pic1) {
|
||||||
|
// add slide timing information, so video can be controlled
|
||||||
|
CTSlide xslide = slide1.getXmlObject();
|
||||||
|
CTTimeNodeList ctnl;
|
||||||
|
if (!xslide.isSetTiming()) {
|
||||||
|
CTTLCommonTimeNodeData ctn = xslide.addNewTiming().addNewTnLst().addNewPar().addNewCTn();
|
||||||
|
ctn.setDur(STTLTimeIndefinite.INDEFINITE);
|
||||||
|
ctn.setRestart(STTLTimeNodeRestartType.NEVER);
|
||||||
|
ctn.setNodeType(STTLTimeNodeType.TM_ROOT);
|
||||||
|
ctnl = ctn.addNewChildTnLst();
|
||||||
|
} else {
|
||||||
|
ctnl = xslide.getTiming().getTnLst().getParArray(0).getCTn().getChildTnLst();
|
||||||
|
}
|
||||||
|
|
||||||
|
CTTLCommonMediaNodeData cmedia = ctnl.addNewVideo().addNewCMediaNode();
|
||||||
|
cmedia.setVol(80000);
|
||||||
|
CTTLCommonTimeNodeData ctn = cmedia.addNewCTn();
|
||||||
|
ctn.setFill(STTLTimeNodeFillType.HOLD);
|
||||||
|
ctn.setDisplay(false);
|
||||||
|
ctn.addNewStCondLst().addNewCond().setDelay(STTLTimeIndefinite.INDEFINITE);
|
||||||
|
cmedia.addNewTgtEl().addNewSpTgt().setSpid(""+pic1.getShapeId());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static class ImageSnapListener extends MediaListenerAdapter {
|
||||||
|
final double SECONDS_BETWEEN_FRAMES;
|
||||||
|
final long MICRO_SECONDS_BETWEEN_FRAMES;
|
||||||
|
boolean hasFired = false;
|
||||||
|
BufferedImage image = null;
|
||||||
|
|
||||||
|
// The video stream index, used to ensure we display frames from one and
|
||||||
|
// only one video stream from the media container.
|
||||||
|
int mVideoStreamIndex = -1;
|
||||||
|
|
||||||
|
// Time of last frame write
|
||||||
|
long mLastPtsWrite = Global.NO_PTS;
|
||||||
|
|
||||||
|
public ImageSnapListener(double seconds) {
|
||||||
|
SECONDS_BETWEEN_FRAMES = seconds;
|
||||||
|
MICRO_SECONDS_BETWEEN_FRAMES =
|
||||||
|
(long)(Global.DEFAULT_PTS_PER_SECOND * SECONDS_BETWEEN_FRAMES);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onVideoPicture(IVideoPictureEvent event) {
|
||||||
|
|
||||||
|
if (event.getStreamIndex() != mVideoStreamIndex) {
|
||||||
|
// if the selected video stream id is not yet set, go ahead an
|
||||||
|
// select this lucky video stream
|
||||||
|
if (mVideoStreamIndex != -1) return;
|
||||||
|
mVideoStreamIndex = event.getStreamIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
long evtTS = event.getTimeStamp();
|
||||||
|
|
||||||
|
// if uninitialized, back date mLastPtsWrite to get the very first frame
|
||||||
|
if (mLastPtsWrite == Global.NO_PTS)
|
||||||
|
mLastPtsWrite = Math.max(0, evtTS - MICRO_SECONDS_BETWEEN_FRAMES);
|
||||||
|
|
||||||
|
// if it's time to write the next frame
|
||||||
|
if (evtTS - mLastPtsWrite >= MICRO_SECONDS_BETWEEN_FRAMES) {
|
||||||
|
if (!hasFired) {
|
||||||
|
image = event.getImage();
|
||||||
|
hasFired = true;
|
||||||
|
}
|
||||||
|
// update last write time
|
||||||
|
mLastPtsWrite += MICRO_SECONDS_BETWEEN_FRAMES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user