/* * myLib - https://github.com/taktod/myLib * Copyright (c) 2014 ttProject. All rights reserved. * * Licensed under GNU LESSER GENERAL PUBLIC LICENSE Version 3. */ package com.ttProject.flazr.unit; import java.nio.ByteBuffer; import java.util.Map.Entry; import org.jboss.netty.buffer.ChannelBuffer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.flazr.rtmp.RtmpHeader; import com.flazr.rtmp.RtmpMessage; import com.flazr.rtmp.message.Audio; import com.flazr.rtmp.message.Metadata; import com.flazr.rtmp.message.Video; import com.ttProject.container.flv.AggregateTag; import com.ttProject.container.flv.FlvTag; import com.ttProject.container.flv.FlvTagReader; import com.ttProject.container.flv.type.MetaTag; import com.ttProject.container.flv.type.VideoTag; import com.ttProject.container.flv.type.AudioTag; import com.ttProject.flazr.rtmp.message.MetadataAmf3; import com.ttProject.nio.channels.ByteReadChannel; import com.ttProject.unit.extra.BitConnector; import com.ttProject.unit.extra.bit.Bit24; import com.ttProject.unit.extra.bit.Bit32; import com.ttProject.unit.extra.bit.Bit8; /** * messageManager * to get flvTag on myLib.container.flv from flvAtom. * @author taktod * note this program try to make byteStream for flvTag. * it is possible to get frame directly. */ public class MessageManager { /** logger */ @SuppressWarnings("unused") private Logger logger = LoggerFactory.getLogger(MessageManager.class); /** byteStream reader for flvTag */ private FlvTagReader flvTagReader = new FlvTagReader(); /** * get flvTag from rtmpMessage. * @param message * @return */ public FlvTag getTag(RtmpMessage message) throws Exception { RtmpHeader header = message.getHeader(); if(header.isAggregate()) { return convertToAggregateTag(message); } else if(header.isAudio()) { return convertToAudioTag((Audio)message); } else if(header.isVideo()) { return convertToVideoTag((Video)message); } else if(message instanceof MetadataAmf3) { return convertToMetaTag((MetadataAmf3)message); } else if(header.isMetadata() && message instanceof Metadata) { return convertToMetaTag((Metadata) message); } return null; } /** * from aggregate message * @param message * @return * @throws Exception */ private AggregateTag convertToAggregateTag(RtmpMessage message) throws Exception { final RtmpHeader header = message.getHeader(); int difference = -1; final ChannelBuffer in = message.encode(); AggregateTag aTag = new AggregateTag(); BitConnector connector = new BitConnector(); while(in.readable()) { Bit8 type = new Bit8(in.readByte()); Bit24 dataSize = new Bit24(in.readMedium()); Bit24 timestamp = new Bit24(in.readMedium()); Bit8 timestampExt = new Bit8(in.readByte()); Bit24 streamId = new Bit24(0); Bit32 prevTagSize = new Bit32(11 + dataSize.get()); ByteBuffer buffer = ByteBuffer.allocate(dataSize.get() + 15); int time = timestamp.get() | timestampExt.get() << 24; if(difference == -1) { difference = time - header.getTime(); } time = time - difference; timestamp.set(time & 0x00FFFFFF); timestampExt.set((time >> 24) & 0xFF); in.skipBytes(3); buffer.put(connector.connect(type, dataSize, timestamp, timestampExt, streamId)); buffer.put(in.readBytes(dataSize.get()).toByteBuffer()); buffer.put(connector.connect(prevTagSize)); buffer.flip(); in.skipBytes(4); FlvTag tag = (FlvTag)flvTagReader.read(new ByteReadChannel(buffer)); if(tag != null) { aTag.add(tag); } } if(aTag.count() == 0) { return null; } else { return aTag; } } /** * get videoTag * @param video * @return * @throws Exception */ private VideoTag convertToVideoTag(Video video) throws Exception { RtmpHeader header = video.getHeader(); ChannelBuffer data = video.encode(); if(data.capacity() < 3) { // data is empty, not to make flvTag. return null; } ByteBuffer buffer = ByteBuffer.allocate(header.getSize() + 15); Bit8 type = new Bit8(0x09); Bit24 dataSize = new Bit24(header.getSize()); Bit24 timestamp = new Bit24(header.getTime() & 0x00FFFFFF); Bit8 timestampExt = new Bit8((header.getTime() >>> 24) & 0xFF); Bit24 streamId = new Bit24(0); Bit32 prevTagSize = new Bit32(11 + header.getSize()); BitConnector connector = new BitConnector(); buffer.put(connector.connect(type, dataSize, timestamp, timestampExt, streamId)); buffer.put(data.toByteBuffer()); buffer.put(connector.connect(prevTagSize)); buffer.flip(); VideoTag tag = (VideoTag)flvTagReader.read(new ByteReadChannel(buffer)); return tag; } /** * get audioTag * @param audio * @return * @throws Exception */ private AudioTag convertToAudioTag(Audio audio) throws Exception { RtmpHeader header = audio.getHeader(); ChannelBuffer data = audio.encode(); if(data.capacity() < 3) { // data is empty, not to make flvTag. return null; } ByteBuffer buffer = ByteBuffer.allocate(header.getSize() + 15); Bit8 type = new Bit8(0x08); Bit24 dataSize = new Bit24(header.getSize()); Bit24 timestamp = new Bit24(header.getTime() & 0x00FFFFFF); Bit8 timestampExt = new Bit8((header.getTime() >>> 24) & 0xFF); Bit24 streamId = new Bit24(0); Bit32 prevTagSize = new Bit32(11 + header.getSize()); BitConnector connector = new BitConnector(); buffer.put(connector.connect(type, dataSize, timestamp, timestampExt, streamId)); buffer.put(data.toByteBuffer()); buffer.put(connector.connect(prevTagSize)); buffer.flip(); AudioTag tag = (AudioTag)flvTagReader.read(new ByteReadChannel(buffer)); return tag; } /** * get metaTag * @param meta * @return */ private MetaTag convertToMetaTag(Metadata meta) throws Exception { MetaTag metaTag = new MetaTag(); for(Entry<String, Object> entry : meta.getMap(0).entrySet()) { metaTag.put(entry.getKey(), entry.getValue()); } return metaTag; } /** * get metaTag(amf3) * @param meta * @return */ private MetaTag convertToMetaTag(MetadataAmf3 meta) throws Exception { MetaTag metaTag = new MetaTag(); for(Entry<String, Object> entry : meta.getData().entrySet()) { metaTag.put(entry.getKey(), entry.getValue()); } return metaTag; } }