Skip to content

Instantly share code, notes, and snippets.

@andrelashley
Created November 2, 2013 00:18
Show Gist options
  • Save andrelashley/7273946 to your computer and use it in GitHub Desktop.
Save andrelashley/7273946 to your computer and use it in GitHub Desktop.
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.xml.namespace.QName;
import org.apache.poi.openxml4j.opc.*;
import org.apache.poi.xslf.usermodel.*;
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.*;
import com.xuggle.mediatool.*;
import com.xuggle.mediatool.event.IVideoPictureEvent;
import com.xuggle.xuggler.Global;
public class AddVideoToPptx {
public static void main(String[] args) throws Exception {
URL video = new URL("http://archive.org/download/test-mpeg/test-mpeg.mpg");
XMLSlideShow pptx = new XMLSlideShow();
XSLFSlide slide = pptx.createSlide();
// 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();
PackageRelationship prsEmbed = slide.getPackagePart().addRelationship(partName, TargetMode.INTERNAL, "http://schemas.microsoft.com/office/2007/relationships/media");
PackageRelationship prsExec = slide.getPackagePart().addRelationship(partName, TargetMode.INTERNAL, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/video");
// add snapshot
BufferedImage image = getSnapShot(video.toExternalForm());
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ImageIO.write(image, "jpeg", bos);
int snapIdx = pptx.addPicture(bos.toByteArray(), XSLFPictureData.PICTURE_TYPE_JPEG);
// add video shape
XSLFPictureShape pic = slide.createPicture(snapIdx);
pic.setAnchor(new Rectangle2D.Double(50, 50, image.getWidth(), image.getHeight()));
CTPicture xpic = (CTPicture)pic.getXmlObject();
CTHyperlink link = xpic.getNvPicPr().getCNvPr().addNewHlinkClick();
link.setId("");
link.setAction("ppaction://media");
// add video relation
CTApplicationNonVisualDrawingProps nvPr = xpic.getNvPicPr().getNvPr();
nvPr.addNewVideoFile().setLink(prsExec.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}");
XmlCursor cur = ext.newCursor();
cur.toEndToken();
cur.beginElement(new QName("http://schemas.microsoft.com/office/powerpoint/2010/main", "media"));
cur.insertAttributeWithValue(new QName(STRelationshipId.type.getName().getNamespaceURI(), "embed"), prsEmbed.getId());
cur.dispose();
// add slide timing information, so video can be controlled
CTSlide xslide = slide.getXmlObject();
CTTLCommonTimeNodeData ctn = xslide.addNewTiming().addNewTnLst().addNewPar().addNewCTn();
ctn.setDur(STTLTimeIndefinite.INDEFINITE);
ctn.setRestart(STTLTimeNodeRestartType.NEVER);
ctn.setNodeType(STTLTimeNodeType.TM_ROOT);
CTTLCommonMediaNodeData cmedia = ctn.addNewChildTnLst().addNewVideo().addNewCMediaNode();
cmedia.setVol(80000);
ctn = cmedia.addNewCTn();
ctn.setFill(STTLTimeNodeFillType.HOLD);
ctn.setDisplay(false);
ctn.addNewStCondLst().addNewCond().setDelay(STTLTimeIndefinite.INDEFINITE);
cmedia.addNewTgtEl().addNewSpTgt().setSpid(""+pic.getShapeId());
FileOutputStream fos = new FileOutputStream("pptx-with-video.pptx");
pptx.write(fos);
fos.close();
}
static BufferedImage getSnapShot(String videoURL) {
// get preview after 5 sec.
IMediaReader mediaReader = ToolFactory.makeReader(videoURL);
// stipulate that we want BufferedImages created in BGR 24bit color space
mediaReader.setBufferedImageTypeToGenerate(BufferedImage.TYPE_3BYTE_BGR);
ImageSnapListener isl = new ImageSnapListener();
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();
return isl.image;
}
static class ImageSnapListener extends MediaListenerAdapter {
static final double SECONDS_BETWEEN_FRAMES = 5;
static final long MICRO_SECONDS_BETWEEN_FRAMES =
(long)(Global.DEFAULT_PTS_PER_SECOND * 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 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();
}
// if uninitialized, back date mLastPtsWrite to get the very first frame
if (mLastPtsWrite == Global.NO_PTS)
mLastPtsWrite = event.getTimeStamp() - MICRO_SECONDS_BETWEEN_FRAMES;
// if it's time to write the next frame
if (event.getTimeStamp() - mLastPtsWrite >= MICRO_SECONDS_BETWEEN_FRAMES) {
if (!hasFired) {
image = event.getImage();
hasFired = true;
}
// update last write time
mLastPtsWrite += MICRO_SECONDS_BETWEEN_FRAMES;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment