/*
* myLib - https://github.com/taktod/myLib
* Copyright (c) 2014 ttProject. All rights reserved.
*
* Licensed under The MIT license.
*/
package com.ttProject.chunk.mp3;
import java.util.HashSet;
import java.util.Set;
import org.apache.log4j.Logger;
import com.ttProject.chunk.IMediaChunk;
import com.ttProject.chunk.MediaChunkManager;
import com.ttProject.chunk.mp3.analyzer.IMp3FrameAnalyzer;
import com.ttProject.media.Unit;
import com.ttProject.media.mp3.frame.Mp3;
/**
* mp3のchunkを取り出すための動作マネージャー
* 基本的にgetChunksにUnitデータ(flvのTagとかmpegtsのPacketとか)をいれると
* 対応したMediaChunkがでてくる。
* @author taktod
*/
public class Mp3ChunkManager extends MediaChunkManager {
/** ロガー */
private Logger logger = Logger.getLogger(Mp3ChunkManager.class);
/** 処理中のmp3Data保持オブジェクト */
private Mp3DataList mp3DataList = new Mp3DataList();
/** 解析用のオブジェクト */
private Set<IMp3FrameAnalyzer> analyzers = new HashSet<IMp3FrameAnalyzer>();
/** 経過frame数 */
private long passedFrame = 0;
/**
* mp3の解析オブジェクトを登録する。
*/
public void addMp3FrameAnalyzer(IMp3FrameAnalyzer frameAnalyzer) {
frameAnalyzer.setMp3DataList(mp3DataList);
analyzers.add(frameAnalyzer);
}
/**
* {@inheritDoc}
*/
@Override
public IMediaChunk getChunk(Unit unit) throws Exception {
// 解析してmp3DataListにデータを追記させる。
for(IMp3FrameAnalyzer analyzer : analyzers) {
analyzer.analyze(unit);
}
// 完了したデータを確認してある場合はchunkを応答する
return checkCompleteChunk();
}
/**
* 完了したchunkを確認。ある場合は応答します
* @return
* @throws Exception
*/
private IMediaChunk checkCompleteChunk() throws Exception {
int sampleRate = mp3DataList.getSampleRate();
if(sampleRate == -1) { // 解析前の場合は処理しない
return null;
}
// 処理したいframe数
long targetFrameCount = passedFrame + (long)(getDuration() * sampleRate);
if(mp3DataList.getCounter() > targetFrameCount) {
/** 現在処理中のchunkオブジェクト */
Mp3Chunk chunk = new Mp3Chunk(sampleRate);
chunk.setTimestamp(mp3DataList.getFirstCounter());
// データを構築する。
int frameCount = 0;
do {
Mp3 frame = mp3DataList.shift();
frameCount += frame.getSampleNum();
chunk.write(frame.getBuffer());
} while(mp3DataList.getFirstCounter() <= targetFrameCount);
chunk.setDuration(1.0f * frameCount / sampleRate);
passedFrame += frameCount;
return chunk;
}
return null;
}
/**
* {@inheritDoc}
*/
@Override
public IMediaChunk getCurrentChunk() {
return null;
}
/**
* {@inheritDoc}
*/
@Override
public IMediaChunk close() {
if(mp3DataList.getListCount() == 0) {
return null;
}
// 最終のときには、中身すべて吐き出しておく。
try {
int sampleRate = mp3DataList.getSampleRate();
Mp3Chunk chunk = new Mp3Chunk(sampleRate);
chunk.setTimestamp(mp3DataList.getFirstCounter());
int frameCount = 0;
Mp3 frame = null;
while((frame = mp3DataList.shift()) != null) {
frameCount += frame.getSampleNum();
chunk.write(frame.getBuffer());
}
chunk.setDuration(1.0f * frameCount / sampleRate);
passedFrame += frameCount;
return chunk;
}
catch(Exception e) {
logger.warn("エラー", e);
}
return null;
}
/**
* {@inheritDoc}
*/
@Override
public String getExt() {
return "mp3";
}
/**
* {@inheritDoc}
*/
@Override
@Deprecated
public String getHeaderExt() {
return "mp3";
}
/**
* {@inheritDoc}
*/
@Override
public long getPassedTic() {
return passedFrame;
}
/**
* 動作サンプルレートを応答します。
* @return 処理前は-1が応答されます。
*/
public int getSampleRate() {
return mp3DataList.getSampleRate();
}
}