Exemplo n.º 1
0
public class RtmpEncoder extends SimpleChannelDownstreamHandler {

  private static final Logger logger = LoggerFactory.getLogger(RtmpEncoder.class);

  private int chunkSize = 128;
  private RtmpHeader[] channelPrevHeaders = new RtmpHeader[RtmpHeader.MAX_CHANNEL_ID];

  private void clearPrevHeaders() {
    logger.debug("clearing prev stream headers");
    channelPrevHeaders = new RtmpHeader[RtmpHeader.MAX_CHANNEL_ID];
  }

  @Override
  public void writeRequested(final ChannelHandlerContext ctx, final MessageEvent e) {
    Channels.write(ctx, e.getFuture(), encode((RtmpMessage) e.getMessage()));
  }

  public ChannelBuffer encode(final RtmpMessage message) {
    final ChannelBuffer in = message.encode();
    final RtmpHeader header = message.getHeader();
    if (header.isChunkSize()) {
      final ChunkSize csMessage = (ChunkSize) message;
      logger.debug("encoder new chunk size: {}", csMessage);
      chunkSize = csMessage.getChunkSize();
    } else if (header.isControl()) {
      final Control control = (Control) message;
      if (control.getType() == Control.Type.STREAM_BEGIN) {
        clearPrevHeaders();
      }
    }
    final int channelId = header.getChannelId();
    header.setSize(in.readableBytes());
    final RtmpHeader prevHeader = channelPrevHeaders[channelId];
    if (prevHeader != null // first stream message is always large
        && header.getStreamId() > 0 // all control messages always large
        && header.getTime() > 0) { // if time is zero, always large
      if (header.getSize() == prevHeader.getSize()) {
        header.setHeaderType(RtmpHeader.Type.SMALL);
      } else {
        header.setHeaderType(RtmpHeader.Type.MEDIUM);
      }
      final int deltaTime = header.getTime() - prevHeader.getTime();
      if (deltaTime < 0) {
        logger.warn("negative time: {}", header);
        header.setDeltaTime(0);
      } else {
        header.setDeltaTime(deltaTime);
      }
    } else {
      // otherwise force to LARGE
      header.setHeaderType(RtmpHeader.Type.LARGE);
    }
    channelPrevHeaders[channelId] = header;
    if (logger.isDebugEnabled()) {
      // logger.debug(">> {}", message);
    }
    final ChannelBuffer out =
        ChannelBuffers.buffer(
            RtmpHeader.MAX_ENCODED_SIZE + header.getSize() + header.getSize() / chunkSize);
    boolean first = true;
    while (in.readable()) {
      final int size = Math.min(chunkSize, in.readableBytes());
      if (first) {
        header.encode(out);
        first = false;
      } else {
        out.writeBytes(header.getTinyHeader());
      }
      in.readBytes(out, size);
    }
    return out;
  }
}