/* * myLib - https://github.com/taktod/myLib * Copyright (c) 2014 ttProject. All rights reserved. * * Licensed under The MIT license. */ package com.ttProject.transcode.ffmpeg; import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; import java.util.List; import java.util.Map.Entry; import org.apache.log4j.Logger; import com.ttProject.media.Unit; import com.ttProject.transcode.ITrackManager; import com.ttProject.transcode.TranscodeManager; import com.ttProject.transcode.ffmpeg.process.ProcessHandler; import com.ttProject.transcode.ffmpeg.process.ProcessServer; import com.ttProject.transcode.ffmpeg.track.FfmpegTrackManager; import com.ttProject.transcode.ffmpeg.unit.IDeunitizer; import com.ttProject.transcode.ffmpeg.unit.IUnitizer; /** * ffmpeg経由で変換を実行するマネージャー * こっちの方がどうみてもxuggleよりパフォーマンスがよさそう。 * * やること * ・変換コマンドを登録する。 * ・stream化プログラム設定 * ・unit化プログラムを設定 * ・実行 * ・あとしまつ * これが動作の流れ的なもの * @author taktod */ public class FfmpegTranscodeManager extends TranscodeManager implements IFfmpegTranscodeManager { /** 動作ロガー */ private final Logger logger = Logger.getLogger(FfmpegTranscodeManager.class); /** 動作プロセス */ private ProcessHandler handler = null; /** 動作pid */ private static String pid; /** 動作ポート番号 */ private int portNumber; /** 動作サーバー */ private ProcessServer server = null; /** unitをstreamに戻すときに利用するプログラム */ private IDeunitizer deunitizer = null; /** streamをunitに戻すときに利用するプログラム */ private IUnitizer unitizer = null; // 出力用のデータ変換が複数必要か?トラックごとにつくっておいた方がよさそう。 /** streamデータからそれぞれのstreamのデータを抜き出す処理(映像 + 音声なら2つ、映像 + 映像 + 音声なら3ついる) */ // private Set<IStreamToUnitHandler> unitHandlers; /** streamをunitに戻すmanager */ /** * 静的初期化 */ static { // 実行プロセスのpidを取得 RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean(); pid = bean.getName().split("@")[0]; } /** * コンストラクタ */ public FfmpegTranscodeManager() { ProcessServer processServer = null; int portNumber = Integer.parseInt(pid); if(portNumber < 1000) { portNumber += 1000; } for(;portNumber < 65535;portNumber += 1000) { try { processServer = new ProcessServer(this, portNumber); break; } catch(Exception e) {} } if(portNumber > 65535) { logger.fatal("プロセス番号ベースでローカルサーバー用のポート番号が決定しませんでした。"); throw new RuntimeException("ローカルサーバーのポート番号が決定しませんでした。"); } logger.info("ポート番号がきまりました。:" + portNumber); server = processServer; this.portNumber = portNumber; } /** * 変換コマンドを設置する * @param command */ @Override public void registerCommand(String command) throws Exception { if(handler != null) { throw new Exception("すでにhandlerは定義済みです。"); } handler = new ProcessHandler(this, portNumber); handler.setCommand(command); server.addKey(handler.getKey()); } /** * 変換処理実行 */ @Override public void transcode(Unit unit) throws Exception { // processがなかったら作る必要あり。 if(!handler.isRunning()) { logger.info("プロセスが開始していないので、開始します。"); // 起動していなかったら起動する。 handler.executeProcess(); } server.getSendWorker().send(unit); } public void process(List<?> units) throws Exception { if(units == null) { return; } // このデータをすべてのTrackManagerに渡したい。 for(Entry<Integer, ITrackManager> entry : getTrackManagers().entrySet()) { FfmpegTrackManager trackManager = (FfmpegTrackManager)entry.getValue(); for(Object obj : units) { if(obj instanceof Unit) { trackManager.applyData((Unit)obj); } } trackManager.commit(); } } /** * 終了処理 */ @Override public synchronized void close() { if(handler != null) { handler.close(); handler = null; } if(server != null) { server.closeServer(); server = null; } if(unitizer != null) { unitizer.close(); unitizer = null; } if(deunitizer != null) { deunitizer.close(); deunitizer = null; } for(Entry<Integer, ITrackManager> entry : getTrackManagers().entrySet()) { FfmpegTrackManager trackManager = (FfmpegTrackManager)entry.getValue(); trackManager.close(); } getTrackManagers().clear(); } /** * 内部動作用のtrackをつくる必要がある */ @Override protected ITrackManager makeTrackManager(int newId) { FfmpegTrackManager trackManager = new FfmpegTrackManager(newId); return trackManager; } @Override public void setDeunitizer(IDeunitizer deunitizer) { this.deunitizer = deunitizer; } @Override public void setUnitizer(IUnitizer unitizer) { this.unitizer = unitizer; } public IDeunitizer getDeunitizer() { return deunitizer; } public IUnitizer getUnitizer() { return unitizer; } // wait中はデータがこなくなったらサーバーを殺す・・・がよさそう。 public void waitForEnd() throws Exception { System.out.println("transcodeManager"); if(handler != null) { handler.waitForEnd(); } } }