/*
* myLib - https://github.com/taktod/myLib
* Copyright (c) 2014 ttProject. All rights reserved.
*
* Licensed under The MIT license.
*/
package com.ttProject.media.extra.mp4;
import java.nio.ByteBuffer;
import java.nio.channels.WritableByteChannel;
import com.ttProject.media.flv.CodecType;
import com.ttProject.media.flv.tag.VideoTag;
import com.ttProject.media.mp4.Atom;
import com.ttProject.media.mp4.IAtomAnalyzer;
import com.ttProject.media.mp4.atom.Stco;
import com.ttProject.media.mp4.atom.Stsc;
import com.ttProject.media.mp4.atom.Stss;
import com.ttProject.media.mp4.atom.Stsz;
import com.ttProject.media.mp4.atom.Stts;
import com.ttProject.nio.channels.IReadChannel;
import com.ttProject.util.BufferUtil;
/**
* 映像データ用Atom
* @author taktod
*/
public class Vdeo extends Atom implements IIndexAtom {
/** データサイズ */
private int size;
/** sample数 */
private int totalSampleCount;
/** データサイズ */
private int totalSize;
/** timescale値(1秒あたり何ticあるか) */
private int timescale;
/** mediaSequenceHeader */
private Msh msh;
/** stco */
private Stco stco;
/** stsc */
private Stsc stsc;
/** stsz */
private Stsz stsz;
/** stts */
private Stts stts;
/** stss */
private Stss stss;
/**
* コンストラクタ
* @param size
* @param position
*/
public Vdeo(int position, int size) {
super(Vdeo.class.getSimpleName().toLowerCase(), position, size);
this.size = size;
}
public void setSize(int size) {
this.size = size;
}
public int getSize() {
return size;
}
public int getTotalSize() {
return totalSize;
}
public int getTotalSampleCount() {
return totalSampleCount;
}
public int getTotalFlvSize() {
if(msh == null) {
return totalSampleCount * (11 + 4 + 1) + totalSize;
}
else {
return totalSampleCount * (11 + 4 + 5) + totalSize + msh.getSize() - 8 + 11 + 4 + 5;
}
}
public void setTimescale(int timescale) {
this.timescale = timescale;
}
public int getTimescale() {
return timescale;
}
public Msh getMsh() {
return msh;
}
public Stco getStco() {
return stco;
}
public Stsc getStsc() {
return stsc;
}
public Stsz getStsz() {
return stsz;
}
public Stts getStts() {
return stts;
}
public Stss getStss() {
return stss;
}
@Override
public void analyze(IReadChannel ch, IAtomAnalyzer analyzer)
throws Exception {
ch.position(getPosition() + 8);
ByteBuffer buffer = BufferUtil.safeRead(ch, 16);
buffer.position(4);
totalSampleCount = buffer.getInt();
totalSize = buffer.getInt();
timescale = buffer.getInt();
// ここから先がタグデータ
while(ch.position() < getPosition() + getSize()) {
int position = ch.position();
buffer = BufferUtil.safeRead(ch, 8);
int size = buffer.getInt();
String tag = BufferUtil.getDwordText(buffer);
if("msh ".equals(tag)) {
msh = new Msh(position, size);
}
else if("stco".equals(tag)) {
stco = new Stco(position, size);
}
else if("stsc".equals(tag)) {
stsc = new Stsc(position, size);
}
else if("stsz".equals(tag)) {
stsz = new Stsz(position, size);
}
else if("stts".equals(tag)) {
stts = new Stts(position, size);
}
else if("stss".equals(tag)) {
stss = new Stss(position, size);
}
else {
throw new Exception("解析不能なタグを発見:" + tag);
}
ch.position(position + size);
}
}
@Override
public void writeIndex(WritableByteChannel idx) throws Exception {
ByteBuffer buffer = ByteBuffer.allocate(24);
buffer.putInt(size); // サイズ
buffer.put("vdeo".getBytes()); // タグ
buffer.putInt(0); // version + flags
buffer.putInt(0); // totalSampleCount
buffer.putInt(0); // totalSize
buffer.putInt(timescale); // timescale
buffer.flip();
idx.write(buffer);
}
/**
* flv用のmediaSequenceHeaderを作成します。
* @param tmp
* @return
* @throws Exception
*/
public VideoTag createFlvMshTag(IReadChannel tmp) throws Exception {
if(msh == null) {
return null;
}
VideoTag mshTag = new VideoTag();
mshTag.setCodec(CodecType.AVC);
mshTag.setFrameType(true);
mshTag.setMSHFlg(true);
tmp.position(msh.getPosition() + 8);
mshTag.setData(tmp, msh.getSize() - 8);
return mshTag;
}
}