Author: andre Date: 2010-03-25 16:14:19 +0100 (Thu, 25 Mar 2010) New Revision: 41615
Added: mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/SegmenterAnalyzer.java mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/SegmenterTranscoder.java Modified: mmbase/trunk/applications/streams/src/main/config/streams/createcaches.xml mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/createcaches/JobCallable.java mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/createcaches/Processor.java mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/createcaches/Result.java mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/createcaches/TranscoderResult.java mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/AbstractTranscoder.java mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/AnalyzerUtils.java mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/CommandTranscoder.java mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/FFMpeg2TheoraTranscoder.java mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/FFMpegRecognizer.java mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/FFMpegTranscoder.java mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/urlcomposers/ImagesURLComposer.java mmbase/trunk/applications/streams/src/main/webapp/mmbase/components/streams/job.jspx Log: porting differences with 1.9 Modified: mmbase/trunk/applications/streams/src/main/config/streams/createcaches.xml =================================================================== --- mmbase/trunk/applications/streams/src/main/config/streams/createcaches.xml 2010-03-25 14:51:40 UTC (rev 41614) +++ mmbase/trunk/applications/streams/src/main/config/streams/createcaches.xml 2010-03-25 15:14:19 UTC (rev 41615) @@ -46,6 +46,65 @@ <loganalyzer name="org.mmbase.streams.transcoders.FFMpeg2TheoraAnalyzer" /> </transcoder> + + <!-- example config for ts streams over cellular networks (for iPhone etc.) --> +<!-- + <transcoder + label="lo" + mimetype="video/*" id="v1"> + <class name="org.mmbase.streams.transcoders.FFMpegTranscoder"> + + <param name="format">ts</param> + <param name="forceFormat">mpegts</param> + <param name="vcodec">libx264</param> + <param name="framesPerSecond">25</param> + <param name="bitrate">96k</param> + <param name="acodec">libmp3lame</param> + <param name="abitrate">48000</param> + <param name="audioChannels">2</param> + <param name="async">2</param> + <param name="width">320</param> + <param name="height">240</param> + + <param name="-flags">+loop</param> + <param name="-cmp">+chroma</param> + <param name="-partitions">+parti4x4+partp8x8+partb8x8</param> + <param name="-subq">5</param> + <param name="-trellis">1</param> + <param name="-refs">1</param> + <param name="-coder">0</param> + <param name="-me_range">16</param> + <param name="-keyint_min">25</param> + <param name="-sc_threshold">40</param> + <param name="-i_qfactor">0.71</param> + <param name="-bt">200k</param> + <param name="-maxrate">96k</param> + <param name="-bufsize">96k</param> + <param name="-rc_eq">'blurCplx^(1-qComp)'</param> + <param name="-qcomp">0.6</param> + <param name="-qmin">10</param> + <param name="-qmax">51</param> + <param name="-qdiff">4</param> + <param name="-level">30</param> + <param name="-aspect">320:240</param> + <param name="-g">30</param> + + </class> + <loganalyzer name="org.mmbase.streams.transcoders.FFMpegAnalyzer" /> + </transcoder> + + <transcoder + label="lo" + mimetype="video/*" in="v1" id="v2"> + <class name="org.mmbase.streams.transcoders.SegmenterTranscoder"> + <param name="format">ts</param> + <param name="duration">10</param> + <param name="httpPrefix">http://www.openimages.eu/</param> + </class> + <loganalyzer name="org.mmbase.streams.transcoders.SegmenterAnalyzer" /> + </transcoder> + --> + <!-- <transcoder mimetype="audio/*" in="v1" id="v3"> <class name="org.mmbase.streams.transcoders.FFMpeg2TheoraTranscoder"> Modified: mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/createcaches/JobCallable.java =================================================================== --- mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/createcaches/JobCallable.java 2010-03-25 14:51:40 UTC (rev 41614) +++ mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/createcaches/JobCallable.java 2010-03-25 15:14:19 UTC (rev 41615) @@ -116,7 +116,7 @@ Result current = thisJob.getCurrent(); if (current == null || current.isReady()) { if (iterator.hasNext()) { - LOG.debug("next !"); + //LOG.debug("next !"); iterator.next(); } current = thisJob.getCurrent(); @@ -125,7 +125,7 @@ if (current.isReady()) { thisJob.ready(); Processor.runningJobs.remove(thisJob.getNode().getNumber()); - LOG.info("1: returning resultCount: " + resultCount); + //LOG.info("1: returning resultCount: " + resultCount); return resultCount; } @@ -136,7 +136,7 @@ thisJob.submit(this); } catch (Exception e) { } - LOG.info("2: returning resultCount: " + resultCount); + //LOG.info("2: returning resultCount: " + resultCount); return resultCount; } result = current; @@ -151,18 +151,18 @@ analyzerLoggers.add(al); logger.addLogger(al); } + assert in != null; - try { jd.transcoder.transcode(in, out, logger); for (AnalyzerLogger al : analyzerLoggers) { al.getAnalyzer().ready(thisJob.getNode(), result.getDestination()); } - resultCount++; result.ready(); logger.info("RESULT " + thisJob + "(" + thisJob.getNode().getNodeManager().getName() + ":" + thisJob.getNode().getNumber() + "):" + result); + if (thisJob.isInterrupted() || Thread.currentThread().isInterrupted()){ logger.info("Interrupted"); break; @@ -196,7 +196,7 @@ logger.info("FINALLY " + resultCount); thisJob.notifyAll(); // notify waiters } - logger.info("3: returning resultCount: " + resultCount); + //logger.info("3: returning resultCount: " + resultCount); return resultCount; } Modified: mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/createcaches/Processor.java =================================================================== --- mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/createcaches/Processor.java 2010-03-25 14:51:40 UTC (rev 41614) +++ mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/createcaches/Processor.java 2010-03-25 15:14:19 UTC (rev 41615) @@ -36,6 +36,7 @@ import org.mmbase.util.externalprocess.CommandExecutor; import org.mmbase.util.logging.*; import org.mmbase.util.xml.*; + import org.w3c.dom.Document; import org.w3c.dom.Element; Modified: mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/createcaches/Result.java =================================================================== --- mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/createcaches/Result.java 2010-03-25 14:51:40 UTC (rev 41614) +++ mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/createcaches/Result.java 2010-03-25 15:14:19 UTC (rev 41615) @@ -27,7 +27,6 @@ import org.mmbase.util.MimeType; - /** * When executing an actual {...@link JobDefinition} the result is contained in an object like this. * @author Michiel Meeuwissen Modified: mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/createcaches/TranscoderResult.java =================================================================== --- mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/createcaches/TranscoderResult.java 2010-03-25 14:51:40 UTC (rev 41614) +++ mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/createcaches/TranscoderResult.java 2010-03-25 15:14:19 UTC (rev 41615) @@ -24,9 +24,9 @@ import java.io.File; import java.net.URI; +import org.mmbase.util.MimeType; import org.mmbase.applications.media.State; import org.mmbase.bridge.Node; -import org.mmbase.util.MimeType; import org.mmbase.util.logging.Logger; import org.mmbase.util.logging.Logging; Modified: mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/AbstractTranscoder.java =================================================================== --- mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/AbstractTranscoder.java 2010-03-25 14:51:40 UTC (rev 41614) +++ mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/AbstractTranscoder.java 2010-03-25 15:14:19 UTC (rev 41615) @@ -21,16 +21,19 @@ package org.mmbase.streams.transcoders; +import org.mmbase.applications.media.Format; +import org.mmbase.applications.media.Codec; +import java.net.*; import java.lang.reflect.*; -import java.net.URI; - -import org.mmbase.applications.media.Codec; -import org.mmbase.applications.media.Format; +import java.io.*; +import java.util.*; +import org.mmbase.util.externalprocess.*; +import org.mmbase.util.WriterOutputStream; import org.mmbase.util.MimeType; -import org.mmbase.util.logging.Logger; -import org.mmbase.util.logging.Logging; +import org.mmbase.util.logging.*; + /** * Base transcoder for others. * @@ -46,7 +49,7 @@ public static Transcoder getInstance(String key) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { String[] split = key.split(" ", 2); Transcoder trans; - { + { // parse split[0] (a class name) to instantiate object String[] idWithClass = split[0].split(":", 2); if (idWithClass.length == 1) { idWithClass = new String[] { "", split[0]}; @@ -65,7 +68,7 @@ trans = (Transcoder) clazz.newInstance(); } } - { + { // parse split[1] to set properties on it. String[] props = split[1].split(", "); for (String prop : props) { String[] entry = prop.split("=", 2); @@ -122,7 +125,7 @@ * * The implementation depends on {...@link Settings} annotations to be set on the classes. */ - public final String getKey() { + public String getKey() { StringBuilder buf = new StringBuilder(); { String cn = getClass().getName(); @@ -171,7 +174,7 @@ return buf.toString(); } - public final void transcode(final URI in, final URI out, final Logger log) throws Exception { + public void transcode(final URI in, final URI out, final Logger log) throws Exception { if (in == null) throw new IllegalArgumentException(toString()); if (out == null) throw new IllegalArgumentException(toString()); this.in = in; Modified: mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/AnalyzerUtils.java =================================================================== --- mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/AnalyzerUtils.java 2010-03-25 14:51:40 UTC (rev 41614) +++ mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/AnalyzerUtils.java 2010-03-25 15:14:19 UTC (rev 41615) @@ -29,6 +29,8 @@ import org.mmbase.bridge.Cloud; import org.mmbase.bridge.Node; import org.mmbase.util.MimeType; + + import org.mmbase.util.logging.*; /** Modified: mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/CommandTranscoder.java =================================================================== --- mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/CommandTranscoder.java 2010-03-25 14:51:40 UTC (rev 41614) +++ mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/CommandTranscoder.java 2010-03-25 15:14:19 UTC (rev 41615) @@ -45,8 +45,7 @@ private String path = org.mmbase.util.ApplicationContextReader.getCachedProperties(getClass().getName()).get("path"); - // TODO - private Map<String, String> moreOptions = new HashMap<String, String>(); + private Map<String, String> moreOptions = new LinkedHashMap<String, String>(); public CommandTranscoder() { LOG.service("" + getClass().getName() + " path:" + path); @@ -79,6 +78,28 @@ return new LoggerWriter(log, Level.ERROR); } + /** + * Overrides the generation of a key in {...@link AbstractTranscoder} to add extra transcoding + * parameters that were not set by {...@link Settings} annotations on the transcoders. + */ + public final String getKey() { + StringBuilder key = new StringBuilder( super.getKey() ); + boolean appendedSetting = false; + if (key.indexOf(", ") > 0) { + appendedSetting = true; + } + + for (Map.Entry<String, String> e : moreOptions.entrySet()) { + if (appendedSetting) { + key.append(", "); + } + key.append(e.getKey()).append("=").append(e.getValue()); + appendedSetting = true; + } + + return key.toString(); + } + protected void transcode(final Logger log) throws Exception { OutputStream outStream = new WriterOutputStream(getOutputWriter(log), System.getProperty("file.encoding")); OutputStream errStream = new WriterOutputStream(getErrorWriter(log), System.getProperty("file.encoding")); @@ -91,23 +112,29 @@ p += File.separator; } + List<String> args = new ArrayList<String>( Arrays.asList(getArguments()) ); + List<String> extra = new ArrayList<String>(); + for (Map.Entry<String, String> e : moreOptions.entrySet()) { + extra.add(e.getKey()); + extra.add(e.getValue()); + } + int pos = args.size() - 2; // last argument is outfile + if (pos > -1) { + if (!extra.isEmpty()) args.addAll(pos, extra); + } else { + LOG.error("Not enough arguments, need at least in- and outfile."); + } if (LOG.isServiceEnabled()) { - LOG.service("Calling (" + method + ") " + p + getCommand() + " " + Arrays.asList(getArguments())); + LOG.service("Calling (" + method + ") " + p + getCommand() + " " + args); } - - // TODO Add support for 'moreOptions' - // Here, but also in getKey. - - CommandExecutor.execute(outStream, errStream, method, p + getCommand(), getArguments()); + CommandExecutor.execute(outStream, errStream, method, p + getCommand(), args.toArray(new String[args.size()])); outStream.close(); errStream.close(); } - public CommandTranscoder clone() { return (CommandTranscoder) super.clone(); } - } Modified: mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/FFMpeg2TheoraTranscoder.java =================================================================== --- mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/FFMpeg2TheoraTranscoder.java 2010-03-25 14:51:40 UTC (rev 41614) +++ mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/FFMpeg2TheoraTranscoder.java 2010-03-25 15:14:19 UTC (rev 41615) @@ -35,7 +35,9 @@ /** - * A trancoder base on an external command, like <code>ffmpeg</code> or <code>ffmpeg2theora</code> + * This transcoder uses the command <code>ffmpeg2theora</code>. Possible parameters to be set in + * 'createcaches.xml' are: videoQuality (--videoquality), keyInt (--keyint), height (-y) and width (-x). + * Others can be added but will be at the end of the commands parameters. * * @author Michiel Meeuwissen * @version $Id$ @@ -43,16 +45,13 @@ @Settings({"videoQuality", "keyInt", "height", "width"}) public class FFMpeg2TheoraTranscoder extends CommandTranscoder { - private static final Logger log = Logging.getLoggerInstance(FFMpeg2TheoraTranscoder.class); - public FFMpeg2TheoraTranscoder() { format = Format.OGV; codec = Codec.THEORA; } - int videoQuality = 5; int keyInt = 64; Integer height = null; @@ -103,7 +102,6 @@ args.add("-y"); args.add("" + height); } - args.add(inFile.toString()); return args.toArray(new String[args.size()]); Modified: mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/FFMpegRecognizer.java =================================================================== --- mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/FFMpegRecognizer.java 2010-03-25 14:51:40 UTC (rev 41614) +++ mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/FFMpegRecognizer.java 2010-03-25 15:14:19 UTC (rev 41615) @@ -25,12 +25,14 @@ import java.net.URI; import org.mmbase.util.MimeType; + import org.mmbase.util.WriterOutputStream; import org.mmbase.util.externalprocess.CommandExecutor; import org.mmbase.util.logging.*; /** + * A recognizer that uses FFmpeg to analyze media. * * @author Michiel Meeuwissen * @version $Id: FFMpegRecognizer.java 36518 2009-07-02 12:52:01Z michiel $ Modified: mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/FFMpegTranscoder.java =================================================================== --- mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/FFMpegTranscoder.java 2010-03-25 14:51:40 UTC (rev 41614) +++ mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/FFMpegTranscoder.java 2010-03-25 15:14:19 UTC (rev 41615) @@ -33,15 +33,23 @@ /** + * The transcoder that uses <code>ffmpeg</code> to transcode media. Possible parameters to be set in + * 'createcaches.xml' are: format, forceFormat (-f), acodec (-acodec), vcodec (-vcodec), + * vpre (-vpre), aq (-aq), ab (-ab), bitrate or b (-b), async (-async), framesPerSecond or + * r (-r), audioChannels or ac (-ac), + * width and height (combined to -s). + * Others can be added as extra parameters but will be at the end of the commands parameters. See the + * documentation for FFmpeg for more information. * * @author Michiel Meeuwissen * @version $Id$ */ -...@settings({"format", "acodec", "vcodec", "vpre", "aq", "ab", "b", "async", "r", "ac", "width", "height"}) +...@settings({"format", "forceFormat", "acodec", "vcodec", "vpre", "aq", "ab", "b", "async", "r", "ac", "width", "height"}) public class FFMpegTranscoder extends CommandTranscoder { private static final Logger log = Logging.getLoggerInstance(FFMpegTranscoder.class); + String forceFormat = null; String acodec = null; String vcodec = null; String vpre = null; @@ -55,6 +63,10 @@ Integer width = null; Integer height = null; + public void setForceFormat(String f) { + forceFormat = f; + } + /* Audio codec to use -acodec */ public void setAcodec(String a) { acodec = a; @@ -155,18 +167,36 @@ args.add("-i"); args.add(inFile.toString()); - if (acodec != null) { - args.add("-acodec"); - args.add(acodec); + if (forceFormat != null) { + args.add("-f"); + args.add(forceFormat); } + // video if (vcodec != null) { args.add("-vcodec"); args.add(vcodec); } + if (b != null) { + args.add("-b"); + args.add(b); + } + if (r != null) { + args.add("-r"); + args.add(r); + } if (vpre != null) { args.add("-vpre"); args.add(vpre); } + if (width != null && height != null) { + args.add("-s"); + args.add(width + "x" + height); + } + // audio + if (acodec != null) { + args.add("-acodec"); + args.add(acodec); + } if (aq != null) { args.add("-aq"); args.add(aq); @@ -175,25 +205,18 @@ args.add("-ab"); args.add(ab); } - if (b != null) { - args.add("-b"); - args.add(b); - } - if (r != null) { - args.add("-r"); - args.add(r); - } if (ac != null) { args.add("-ac"); args.add(ac); } - if (width != null && height != null) { - args.add("-s"); - args.add(width + "x" + height); + + if (async != null) { + args.add("-async"); + args.add(async); } + args.add("-y"); // overwrite args.add(outFile.toString()); - args.add("-y"); // overwrite return args.toArray(new String[args.size()]); } Added: mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/SegmenterAnalyzer.java =================================================================== --- mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/SegmenterAnalyzer.java (rev 0) +++ mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/SegmenterAnalyzer.java 2010-03-25 15:14:19 UTC (rev 41615) @@ -0,0 +1,152 @@ +/* + +This file is part of the MMBase Streams application, +which is part of MMBase - an open source content management system. + Copyright (C) 2009 André van Toly, Michiel Meeuwissen + +MMBase Streams 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. + +MMBase Streams 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 MMBase. If not, see <http://www.gnu.org/licenses/>. + +*/ + +package org.mmbase.streams.transcoders; + +import java.util.regex.*; +import java.util.*; +import java.io.*; + +import org.mmbase.servlet.FileServlet; +import org.mmbase.bridge.*; + +import org.mmbase.util.logging.*; + + +/** + * Analyzes <code>segmenter</code> output during its job, changes url field to m3u8 index file when + * ready and rewrites m3u8 to removed full paths. + * + * @author André van Toly + * @version $Id: SegmenterAnalyzer.java 40036 2009-11-30 20:27:39Z andre $ + */ +public class SegmenterAnalyzer implements Analyzer { + + private static final Logger LOG = Logging.getLoggerInstance(SegmenterAnalyzer.class); + + public int getMaxLines() { + return Integer.MAX_VALUE; + } + + // TODO: progress matcher + // private static final Pattern PROGRESS = Pattern.compile("\\s*(.*?) audio: ([0-9]+)kbps video: ([0-9]+)kbps, time remaining: .*"); + + private ChainedLogger log = new ChainedLogger(LOG); + + private AnalyzerUtils util = new AnalyzerUtils(log); + + private List<Throwable> errors =new ArrayList<Throwable>(); + + public void addThrowable(Throwable t) { + errors.add(t); + } + + public void addLogger(Logger logger) { + log.addLogger(logger); + } + + public void analyze(String l, Node source, Node des) { + synchronized(util) { + Cloud cloud = source.getCloud(); + + if (util.duration(l, source, des)) { + return; + } + + if (util.dimensions(l, source, des)) { + return; + } + + if (util.audio(l, source, des)) { + return; + } + + // TODO: progress matcher + /* + { + Matcher m = PROGRESS.matcher(l); + if (m.matches()) { + long pos = util.getLength(m.group(1)); + long audioBitrate = Integer.parseInt(m.group(2)); + long videoBitrate = Integer.parseInt(m.group(3)); + bits += ((double) (audioBitrate + videoBitrate)) * ((double) pos - prevPos) * 1000; + //System.out.println("" + pos + "ms " + (audioBitrate + videoBitrate) + " -> " + (bits / pos) + " " + (100 * pos / length) + " %"); + + prevPos = pos; + } + } + */ + } + } + + public void ready(Node sourceNode, Node destNode) { + synchronized(util) { + String url = destNode.getStringValue("url"); + url = url.substring(0, url.lastIndexOf('.')) + ".m3u8"; + destNode.setStringValue("url", url); + + if (FileServlet.getInstance() != null) { + + String filesDirectory = FileServlet.getDirectory().toString(); + if (!filesDirectory.endsWith("/")) { + filesDirectory = filesDirectory + "/"; + } + File index = new File(filesDirectory + url); + File temp = new File(filesDirectory + url + ".tmp"); + + try { + BufferedReader in = new BufferedReader(new FileReader(index)); + PrintWriter pw = new PrintWriter(new FileWriter(temp)); + + String line = null; + while((line = in.readLine()) != null) { + if (line.indexOf(filesDirectory) > -1) { + line = line.replace(filesDirectory, ""); + } + pw.println(line); + } + in.close(); + pw.close(); + + // Delete original and rename new one + if (!index.delete()) log.error("Could not delete file: " + index.toString()); + if (!temp.renameTo(index)) log.error("Could not rename file to: " + index.toString()); + + LOG.debug("Rewrote m3u8 indexfile: " + index); + } catch (java.io.IOException ioe) { + LOG.error("Could not rewrite m3u8 indexfile: " + ioe); + } + + } + } + + } + + public SegmenterAnalyzer clone() { + try { + return (SegmenterAnalyzer) super.clone(); + } catch (CloneNotSupportedException cnfe) { + // doesn't happen + return null; + } + } + +} Added: mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/SegmenterTranscoder.java =================================================================== --- mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/SegmenterTranscoder.java (rev 0) +++ mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/transcoders/SegmenterTranscoder.java 2010-03-25 15:14:19 UTC (rev 41615) @@ -0,0 +1,144 @@ +/* + +This file is part of the MMBase Streams application, +which is part of MMBase - an open source content management system. + Copyright (C) 2009 André van Toly, Michiel Meeuwissen + +MMBase Streams 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. + +MMBase Streams 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 MMBase. If not, see <http://www.gnu.org/licenses/>. + +*/ + +package org.mmbase.streams.transcoders; + +import java.net.*; +import java.io.*; +import java.util.*; +import java.util.regex.*; + +import org.mmbase.module.core.MMBaseContext; +import org.mmbase.bridge.*; +import org.mmbase.bridge.util.*; +import org.mmbase.util.logging.*; +import org.mmbase.servlet.FileServlet; + +import org.mmbase.applications.media.Codec; +import org.mmbase.applications.media.Format; + + +/** + * The transcoder that uses <code>segmenter</code> to create segments of a stream including their + * m3u8 index file to be distributed over a cellular network. + * The source of the segmenter can be found: http://svn.assembla.com/svn/legend/segmenter/ + * It accepts the following arguments: + * segmenter sample_low.ts 10 sample_low sample_low.m3u8 http://www.openimages.eu/ + * The input file, output prefix and index prefix arguments are automatically filled, + * specify segment duration (default 10 sec.) and httpPrefix (hostname) in 'createcaches.xml'. + * + * @author André van Toly + * @version $Id: SegmenterTranscoder.java 41564 2010-03-22 19:42:15Z andre $ + */ +...@settings({"duration", "httpPrefix"}) +public class SegmenterTranscoder extends CommandTranscoder { + + private static final Logger log = Logging.getLoggerInstance(SegmenterTranscoder.class); + + + @Override + protected LoggerWriter getErrorWriter(Logger log) { + // ffmpeg write also non-errors to stderr, so lets not log on ERROR, but on SERVICE. + // also pluging an error-detector here. + return new LoggerWriter(new ChainedLogger(log, new ErrorDetector(Pattern.compile("\\s*Unknown encoder.*"))), Level.SERVICE); + } + + int duration = 10; + String httpPrefix = "http://localhost:8080/"; + + public SegmenterTranscoder() { + format = Format.TS; + codec = Codec.H264; + } + + public void setDuration(int d) { + duration = d; + } + + public void setHttpPrefix(String h) { + httpPrefix = h; + } + + @Override + protected String getCommand() { + return "segmenter"; + } + + @Override + protected String[] getArguments() { + if (! in.getScheme().equals("file")) throw new UnsupportedOperationException(); + if (! out.getScheme().equals("file")) throw new UnsupportedOperationException(); + + File inFile = new File(in.getPath()); + File outFile = new File(out.getPath()); + + //String filesDirectory = FileServlet.getDirectory().toString(); + String filesPath = FileServlet.getBasePath("files"); + if (filesPath.startsWith("/")) { + filesPath = filesPath.substring(1); + } + + String outStr = outFile.toString(); + String file_prefix = outStr.substring(0, outStr.lastIndexOf('.')); + String index_file = file_prefix + ".m3u8"; + + if (log.isDebugEnabled()) { + log.debug("filesPath: " + filesPath); + log.debug("file_prefix: " + file_prefix); + log.debug("index_file: " + index_file); + } + + List<String> args = new ArrayList<String>(); + + args.add(inFile.toString()); + args.add("" + duration); + args.add(file_prefix); + args.add(index_file); + args.add(httpPrefix + filesPath); + + //args.add(out); + + return args.toArray(new String[args.size()]); + } + + private static final Pattern PROGRESS = Pattern.compile(".*time remaining.*"); + + @Override + protected LoggerWriter getOutputWriter(final Logger log) { + LoggerWriter w = new LoggerWriter(log, Level.SERVICE) { + @Override + public Level getLevel(String line) { + if (PROGRESS.matcher(line).matches()) { + return Level.DEBUG; + } + return null; + } + }; + + return w; + } + + @Override + public SegmenterTranscoder clone() { + return (SegmenterTranscoder) super.clone(); + } + +} Modified: mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/urlcomposers/ImagesURLComposer.java =================================================================== --- mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/urlcomposers/ImagesURLComposer.java 2010-03-25 14:51:40 UTC (rev 41614) +++ mmbase/trunk/applications/streams/src/main/java/org/mmbase/streams/urlcomposers/ImagesURLComposer.java 2010-03-25 15:14:19 UTC (rev 41615) @@ -23,6 +23,7 @@ package org.mmbase.streams.urlcomposers; import org.mmbase.applications.media.Format; +import org.mmbase.util.MimeType; import org.mmbase.applications.media.State; import org.mmbase.applications.media.urlcomposers.FragmentURLComposer; import org.mmbase.module.builders.ImageCaches; @@ -30,7 +31,6 @@ import org.mmbase.module.core.MMBase; import org.mmbase.module.core.MMObjectNode; import org.mmbase.streams.builders.ImageSources; -import org.mmbase.util.MimeType; import org.mmbase.util.images.Dimension; import org.mmbase.util.images.Factory; import org.mmbase.util.logging.Logger; Modified: mmbase/trunk/applications/streams/src/main/webapp/mmbase/components/streams/job.jspx =================================================================== --- mmbase/trunk/applications/streams/src/main/webapp/mmbase/components/streams/job.jspx 2010-03-25 14:51:40 UTC (rev 41614) +++ mmbase/trunk/applications/streams/src/main/webapp/mmbase/components/streams/job.jspx 2010-03-25 15:14:19 UTC (rev 41615) @@ -47,7 +47,7 @@ <div class="log"> <h4>Job ${_.number} log</h4> <pre> - <jsp:text>${_.logger.debugList}</jsp:text> + <jsp:text>${mm:escape('text/xml', _.logger.debugList)}</jsp:text> </pre> </div> _______________________________________________ Cvs mailing list Cvs@lists.mmbase.org http://lists.mmbase.org/mailman/listinfo/cvs