/* * myLib - https://github.com/taktod/myLib * Copyright (c) 2014 ttProject. All rights reserved. * * Licensed under The MIT license. */ package com.ttProject.convertprocess.server; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; import org.apache.log4j.Logger; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipelineCoverage; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; import com.ttProject.convertprocess.frame.AnalyzerChecker; import com.ttProject.convertprocess.frame.IShareFrameListener; import com.ttProject.convertprocess.frame.ShareFrameData; import com.ttProject.frame.AudioAnalyzer; import com.ttProject.frame.Frame; import com.ttProject.frame.IAnalyzer; import com.ttProject.frame.IFrame; import com.ttProject.frame.NullFrame; import com.ttProject.frame.VideoAnalyzer; import com.ttProject.frame.VideoFrame; import com.ttProject.nio.channels.ByteReadChannel; import com.ttProject.nio.channels.IReadChannel; import com.ttProject.util.BufferUtil; /** * clientでのデータの受け取りhandler * @author taktod */ @ChannelPipelineCoverage("one") public class ProcessClientHandler extends SimpleChannelUpstreamHandler { /** ロガー */ @SuppressWarnings("unused") private Logger logger = Logger.getLogger(ProcessClientHandler.class); /** データサイズ */ private int size = -1; /** やり取り中のデータbuffer */ private ByteBuffer buffer = null; /** analyzerのmap */ private Map<Integer, IAnalyzer> analyzerMap = new HashMap<Integer, IAnalyzer>(); /** analyzerの確認をするモジュール */ private AnalyzerChecker analyzerChecker = new AnalyzerChecker(); /** フレームを取得したときのlistener */ private final IShareFrameListener listener; /** * コンストラクタ * @param listener */ public ProcessClientHandler(IShareFrameListener listener) { this.listener = listener; } @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { ChannelBuffer buf = ChannelBuffers.buffer("hello".length()); buf.writeBytes("hello".getBytes()); e.getChannel().write(buf); } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { e.getCause().printStackTrace(); } /** * メッセージをうけとった場合の処理 */ @Override public synchronized void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { // System.err.println("データをうけとりました。"); ByteBuffer cbuf = ((ChannelBuffer)e.getMessage()).toByteBuffer(); // System.err.println("確認:" + cbuf.limit() + " " + cbuf.capacity() + " " + cbuf.remaining()); buffer = BufferUtil.connect(buffer, cbuf); while(buffer.remaining() > 0) { if(size == -1) { if(buffer.remaining() < 4) { // サイズデータを参照するのに必要なデータがない return; } size = buffer.getInt(); } if(buffer.remaining() < size) { // 共有フレームデータを参照するのに必要なデータがない return; } if(size < 0) { // データがおかしい return; } ByteBuffer data = ByteBuffer.allocate(size); byte[] tmp = new byte[size]; buffer.get(tmp); data.put(tmp); data.flip(); try { processFrame(data); } catch(Exception ex) { ex.printStackTrace(); // logger.error("フレーム複製時に例外が発生しました。", ex); } size = -1; } // System.err.println("messageReceivedおわり"); } /** * フレームの処理を進める * @param data * @throws Exception */ private void processFrame(ByteBuffer data) throws Exception { ShareFrameData shareFrameData = new ShareFrameData(data); IAnalyzer analyzer = analyzerMap.get(shareFrameData.getTrackId()); if(analyzer == null) { analyzer = analyzerChecker.checkAnalyzer(shareFrameData.getCodecType()); if(analyzer instanceof AudioAnalyzer) { shareFrameData.setupFrameSelector(((AudioAnalyzer) analyzer).getSelector()); } else if(analyzer instanceof VideoAnalyzer){ shareFrameData.setupFrameSelector(((VideoAnalyzer) analyzer).getSelector()); } else { throw new Exception("Analyzerが不明でした。"); } analyzerMap.put(shareFrameData.getTrackId(), analyzer); } // System.err.println("shareFrameData取得完了:" + shareFrameData.getFrameData().remaining()); // この部分でframeの値をとれるだけとらないとだめ。 IFrame frame = null; IReadChannel channel = new ByteReadChannel(shareFrameData.getFrameData()); while((frame = analyzer.analyze(channel)) != null) { completeFrame(frame, shareFrameData); } frame = analyzer.getRemainFrame(); if(frame != null && !(frame instanceof NullFrame)) { completeFrame(frame, shareFrameData); } // System.err.println("フレーム処理完了"); } /** * 出来上がったデータを整形する * @param frame * @param shareFrameData * @throws Exception */ private void completeFrame(IFrame frame, ShareFrameData shareFrameData) throws Exception { Frame f = (Frame)frame; f.setTimebase(shareFrameData.getTimebase()); f.setPts(shareFrameData.getPts()); if(frame instanceof NullFrame) { // nullFrameになっている場合は、処理する必要なし return; } if(frame instanceof VideoFrame) { // 動画の場合はdtsをいれておく。 VideoFrame vFrame = (VideoFrame)frame; vFrame.setDts(shareFrameData.getDts()); } // ここでみつかったデータをlistenerに渡しておく listener.pushFrame(frame, shareFrameData.getTrackId()); } }