package org.red5.server.io; /* * RED5 Open Source Flash Server - http://www.osflash.org/red5 * * Copyright (c) 2006-2009 by respective authors. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free Software * Foundation; either version 2.1 of the License, or (at your option) any later * version. * * This library 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along * with this library; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ import java.io.File; import java.io.IOException; import java.util.TreeSet; import junit.framework.Assert; import junit.framework.TestCase; import org.apache.mina.common.ByteBuffer; import org.red5.io.ITag; import org.red5.io.ITagReader; import org.red5.io.ITagWriter; import org.red5.io.IoConstants; import org.red5.io.amf.Output; import org.red5.io.flv.IFLV; import org.red5.io.flv.IFLVService; import org.red5.io.flv.impl.FLVService; import org.red5.io.flv.impl.Tag; import org.red5.io.flv.meta.ICueType; import org.red5.io.flv.meta.IMetaCue; import org.red5.io.flv.meta.MetaCue; import org.red5.io.object.Deserializer; import org.red5.io.object.Serializer; import org.red5.server.cache.NoCacheImpl; /** * @author The Red5 Project (red5@osflash.org) * @author Dominick Accattato (daccattato@gmail.com) * @author Luke Hubbard, Codegent Ltd (luke@codegent.com) */ public class CuePointInjectionTest extends TestCase { private IFLVService service; /** * SetUp is called before each test * */ @Override public void setUp() { service = new FLVService(); service.setSerializer(new Serializer()); service.setDeserializer(new Deserializer()); } /** * Test MetaData injection * * @throws IOException for fun */ public void testCuePointInjection() throws IOException { File f = new File("src/test/resources/fixtures/test_cue1.flv"); System.out.println("Path: " + f.getAbsolutePath()); if (f.exists()) { f.delete(); } // Create new file f.createNewFile(); // Use service to grab FLV file IFLV flv = (IFLV) service.getStreamableFile(f); // Grab a writer for writing a new FLV ITagWriter writer = flv.getWriter(); // Create a reader for testing File readfile = new File("src/test/resources/fixtures/test_cue.flv"); assertTrue(readfile.exists()); IFLV readflv = (IFLV) service.getStreamableFile(readfile); readflv.setCache(NoCacheImpl.getInstance()); // Grab a reader for reading a FLV in ITagReader reader = readflv.getReader(); // Inject MetaData writeTagsWithInjection(reader, writer); } /** * Write FLV tags and inject Cue Points * * @param reader * @param writer * @throws IOException */ private void writeTagsWithInjection(ITagReader reader, ITagWriter writer) throws IOException { IMetaCue cp = new MetaCue<Object, Object>(); cp.setName("cue_1"); cp.setTime(0.01); cp.setType(ICueType.EVENT); IMetaCue cp1 = new MetaCue<Object, Object>(); cp1.setName("cue_1"); cp1.setTime(2.01); cp1.setType(ICueType.EVENT); // Place in TreeSet for sorting TreeSet<IMetaCue> ts = new TreeSet<IMetaCue>(); ts.add(cp); ts.add(cp1); int cuePointTimeStamp = getTimeInMilliseconds(ts.first()); ITag tag = null; ITag injectedTag = null; while (reader.hasMoreTags()) { tag = reader.readTag(); // if there are cuePoints in the TreeSet if (!ts.isEmpty()) { // If the tag has a greater timestamp than the // cuePointTimeStamp, then inject the tag while (tag.getTimestamp() > cuePointTimeStamp) { injectedTag = injectCuePoint(ts.first(), tag); writer.writeTag(injectedTag); tag.setPreviousTagSize((injectedTag.getBodySize() + 11)); // Advance to the next CuePoint ts.remove(ts.first()); if (ts.isEmpty()) { break; } cuePointTimeStamp = getTimeInMilliseconds(ts.first()); } } writer.writeTag(tag); } } /** * Injects metadata (Cue Points) into a tag * * @param cue * @param writer * @param tag * @return ITag tag */ private ITag injectCuePoint(Object cue, ITag tag) { IMetaCue cp = (MetaCue<?, ?>) cue; Output out = new Output(ByteBuffer.allocate(1000)); Serializer ser = new Serializer(); ser.serialize(out, "onCuePoint"); ser.serialize(out, cp); ByteBuffer tmpBody = out.buf().flip(); int tmpBodySize = out.buf().limit(); int tmpPreviousTagSize = tag.getPreviousTagSize(); byte tmpDataType = ((IoConstants.TYPE_METADATA)); int tmpTimestamp = getTimeInMilliseconds(cp); return new Tag(tmpDataType, tmpTimestamp, tmpBodySize, tmpBody, tmpPreviousTagSize); } /** * Returns a timestamp in milliseconds * * @param object * @return int time */ private int getTimeInMilliseconds(Object object) { IMetaCue cp = (MetaCue<?, ?>) object; return (int) (cp.getTime() * 1000.00); } /** * Test to see if TreeSet is sorting properly */ public void testCuePointOrder() { IMetaCue cue = new MetaCue<Object, Object>(); cue.setName("cue_1"); cue.setTime(0.01); cue.setType(ICueType.EVENT); IMetaCue cue1 = new MetaCue<Object, Object>(); cue1.setName("cue_1"); cue1.setTime(2.01); cue1.setType(ICueType.EVENT); IMetaCue cue2 = new MetaCue<Object, Object>(); cue2.setName("cue_1"); cue2.setTime(1.01); cue2.setType(ICueType.EVENT); TreeSet<IMetaCue> ts = new TreeSet<IMetaCue>(); ts.add(cue); ts.add(cue1); ts.add(cue2); System.out.println("ts: " + ts); Assert.assertEquals(true, true); } }