/** * This file is part of jFlvTool. * * jFlvTool is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * jFlvTool is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * * file name : MetaDataGen.java * authors : Jon Keys * created : July 5, 2007, 8:44 AM * copyright : Sony Digital Authoring Services * * modifications: * Date: Name: Description: * ---------- --------------- ---------------------------------------------- * July 5, 2007 Jon Keys Creation */ package edu.washington.cs.oneswarm.ui.gwt.server.ffmpeg.jflv.metadata; import java.util.ArrayList; import java.util.HashMap; import java.util.logging.Level; import java.util.logging.Logger; import edu.washington.cs.oneswarm.ui.gwt.server.ffmpeg.jflv.tags.FlvTag; import edu.washington.cs.oneswarm.ui.gwt.server.ffmpeg.jflv.tags.MetaTag; /** * * @author Jon Keys */ public class MetaDataGen { private TagBroker tb; private FlvHeader flvh; private EmbeddedData emb; private MetaTag mt2; private long duration; private long lastTimeStamp; private static Logger logger = Logger.getLogger(MetaDataGen.class.getName()); /** Creates a new instance of MetaDataGen */ public MetaDataGen(TagBroker tb, FlvHeader flvh) { this.tb = tb; this.flvh = flvh; emb = null; duration = 0; lastTimeStamp = 0; }// MetaDataGen() public void buildOnLastSecond() { duration = tb.getDuration(); lastTimeStamp = (duration - 1000); MetaTag mt = new MetaTag(); mt.setEvent("onLastSecond"); mt.setTimestamp(lastTimeStamp); mt.setMetaData(new HashMap<String, Object>()); if (lastTimeStamp > 0) { ArrayList<TagStor> nts = new ArrayList<TagStor>(); TagStor mtTagStor = new TagStor(FlvTag.META, (mt.getDataSizeFromBuffer() - 15), lastTimeStamp, mt); mtTagStor.setIsNew(true); nts.add(mtTagStor); tb.addTags(nts, false, true); } }// buildOnLastSecond() public void buildOnMetaData() { mt2 = new MetaTag(); mt2.setEvent("onMetaData"); emb = new EmbeddedData(); // emb.addData("metadatacreator", "Sony DADC jFlvTool"); emb.addData("metadatadate", new AMFTime()); emb.addData("duration", new Double(((duration + tb.getFrameRate())) / 1000d)); emb.addData("lasttimestamp", new Double((duration / 1000d))); emb.addData("audiosize", new Double(tb.getTotalAudioSize())); emb.addData("datasize", new Double(0)); emb.addData("filesize", new Double(0)); emb.addData("cuePoints", tb.getCuePointTags()); emb.addData("keyframes", tb.getKeyFrameTags()); emb.addData("hasMetadata", new Boolean(true)); emb.addData("hasCuePoints", new Boolean((tb.getCuePointTags().size() > 0))); emb.addData("hasKeyframes", new Boolean((tb.getKeyFrameTags().size() > 0))); // has video? if ((tb.getLastVideoTag() != -1) && tb.getFirstVideoTag() != -1) { emb.addData("videocodecid", new Double(tb.getVideoCcodecId())); emb.addData("width", new Double(tb.getVideoWidth())); emb.addData("height", new Double(tb.getVideoHeight())); emb.addData("lastkeyframetimestamp", new Double(tb.getLastKeyFrameTimeStamp())); emb.addData("canSeekToEnd", new Boolean(tb.canSeekToEnd())); emb.addData("framerate", new Double(tb.getFrameRate())); emb.addData("videosize", new Double(tb.getTotalVideoSize())); emb.addData("videodatarate", new Double(tb.getVideoDataRate((duration / 1000f)))); emb.addData("hasVideo", new Boolean(true)); } else { // emb.addData("videocodecid", new Double(0)); // emb.addData("width", new Double(0)); // emb.addData("height", new Double(0)); // emb.addData("lastkeyframetimestamp", new Double(0)); // emb.addData("canSeekToEnd", new Boolean(true)); // emb.addData("framerate", new Double(0)); // emb.addData("videosize", new Double(0)); // emb.addData("videodatarate", new Double(0)); // emb.addData("hasVideo", new Boolean(false)); } // has audio? if ((tb.getLastAudioTag() != -1) && (tb.getFirstAudioTag() != -1)) { emb.addData("hasAudio", new Boolean(true)); emb.addData("audiodatarate", new Double(tb.getAudioDataRate((duration / 1000f)))); emb.addData("audiosamplerate", new Double(tb.getAudioSampleRate())); emb.addData("audiosamplesize", new Double(tb.getAudioSampleSize())); emb.addData("audiocodecid", new Double(tb.getAudioCodecId())); emb.addData("audiodelay", new Double(tb.getAudioDelay())); emb.addData("stereo", new Boolean(tb.isStero())); } else { // emb.addData("hasAudio", new Boolean(false)); // emb.addData("audiodatarate", new Double(0)); // emb.addData("audiosamplerate", new Double(0)); // emb.addData("audiosamplesize", new Double(0)); // emb.addData("audiocodecid", new Double(0)); // emb.addData("audiodelay", new Double(0)); // emb.addData("stereo", new Boolean(false)); } logger.finer("\n===BEGIN created meta data====\n" + emb.printMetaData() + "\n===END created meta data===="); }// buildOnMetaData() public void sealMetaData(boolean updateKeyFrames, boolean keepFrameRate) { mt2.setMetaData(emb.getData()); ArrayList<TagStor> nts2 = new ArrayList<TagStor>(); TagStor mt2TagStor = new TagStor(FlvTag.META, (mt2.getDataSizeFromBuffer() - 15), 0, mt2); mt2TagStor.setIsNew(true); nts2.add(mt2TagStor); tb.addTags(nts2, keepFrameRate, true); // re-calc values affected by adding the actual metatag tb.recalcKeyFrameTagOffsets(); if (updateKeyFrames) { emb.removeData("keyframes"); emb.addData("keyframes", tb.getKeyFrameTags()); emb.removeData("datasize"); emb.addData("datasize", new Double(tb.getTotalDataSize())); emb.removeData("filesize"); emb.addData("filesize", new Double((flvh.getDataOffset() + tb.getTotalDataSize() + ((tb .getTags().size() + 1) * 4)))); } }// addMetaData() @SuppressWarnings("unchecked") public void spoofMetaData(double startOffset, double realDurationInSeconds, double audioRateKBitPerS, double videoRateKbitPerS) { /* * update duration field */ emb.removeData("duration"); emb.addData("duration", new Double(realDurationInSeconds)); /* * lasttimestamp */ emb.removeData("lasttimestamp"); emb.addData("lasttimestamp", new Double(realDurationInSeconds)); /* * audiosize, videosize, datasize, filesize */ // has audio? double audioSize = 0; if ((tb.getLastAudioTag() != -1)) { emb.removeData("audiosize"); audioSize = audioRateKBitPerS * 1024 * realDurationInSeconds / 8.0; emb.addData("audiosize", new Double(audioSize)); } double videoSize = 0; if ((tb.getLastVideoTag() != -1)) { emb.removeData("videosize"); videoSize = videoRateKbitPerS * 1024 * realDurationInSeconds / 8.0; emb.addData("videosize", new Double(videoSize)); } emb.removeData("filesize"); emb.addData("filesize", new Double(audioSize + videoSize)); emb.removeData("datasize"); emb.addData("datasize", new Double(audioSize + videoSize)); /* * keyframes, lastkeyframetimestamp */ try { if ((tb.getKeyFrameTags().size() > 1) && tb.getLastVideoTag() != -1 && tb.getFirstVideoTag() != -1) { AMFObject keyFrameTags = tb.getKeyFrameTags(); ArrayList<Double> times = (ArrayList<Double>) keyFrameTags.get("times"); ArrayList<Double> filepositions = (ArrayList<Double>) keyFrameTags .get("filepositions"); // double timeBetweenKeyFrames = getAverageDiff(times); double timeBetweenKeyFrames = 2.0; // just setting it to 2 sec double bytesBetweenKeyFrames = 2 * videoRateKbitPerS;// getAverageDiff(filepositions); // System.out.println("average diff: time=" + // timeBetweenKeyFrames + " bytes=" + bytesBetweenKeyFrames); double currTime = startOffset; double currByte = filepositions.get(0); times.clear(); filepositions.clear(); while (currTime < realDurationInSeconds) { times.add(currTime); currTime += timeBetweenKeyFrames; filepositions.add(currByte); currByte += bytesBetweenKeyFrames; } emb.removeData("lastkeyframetimestamp"); emb.addData("lastkeyframetimestamp", currTime - timeBetweenKeyFrames); } else { emb.removeData("hasKeyframes"); emb.removeData("keyframes"); } } catch (Throwable t) { t.printStackTrace(); } if (logger.isLoggable(Level.FINER)) { logger.finer("\n===BEGIN spoofed meta data====\n" + emb.printMetaData() + "\n===END spoofed meta data===="); } } // private static double getAverageDiff(ArrayList<Double> list) throws // Exception { // double num = list.size() - 1; // double totalDiff = 0; // for (int i = 1; i < list.size(); i++) { // totalDiff += list.get(i) - list.get(i - 1); // } // if (num == 0 || totalDiff == 0) { // throw new Exception("num=" + num + " totaldiff=" + totalDiff); // } // return totalDiff / num; // } public EmbeddedData getMetaData() { return emb; } }// MetaDataGen