/*
* Flazr <http://flazr.com> Copyright (C) 2009 Peter Thomas.
*
* This file is part of Flazr.
*
* Flazr is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Flazr is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Flazr. If not, see <http://www.gnu.org/licenses/>.
*/
package com.flazr.rtmp.client;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import android.util.Log;
import com.flazr.rtmp.RtmpHeader;
import com.flazr.rtmp.RtmpMessage;
import com.flazr.rtmp.message.MessageType;
import com.flazr.rtmp.reader.FileChannelReader;
public class FlvAtom implements RtmpMessage {
private final RtmpHeader header;
private ChannelBuffer data;
/**
* FlvWriterからのみ呼ばれる
* @param in
*/
public FlvAtom(final ChannelBuffer in) {
header = readHeader(in);
data = in.readBytes(header.getSize());
in.skipBytes(4); // prev offset
}
/**
* メインで呼ばれる
* カメラ/音声は別なので、FlvReaderのnext,prevから呼ばれる
* @param in
*/
public FlvAtom(final FileChannelReader in) {
//タグタイプ1バイト、サイズ3バイト、タイムスタンプ3バイト、タイムスタンプ拡張1バイト、ストリームID3バイト
ChannelBuffer head = in.wrappedReadBytes(11);
header = readHeader(head);
byte[] xa = head.array();
String str = "";
for(int i = 0; i < xa.length; i++){
if(i > 0 && i % 20 == 0)str += "\n";
str += String.format("%02X ", xa[i]);
}
Log.d("NLiveRoid" ,"HEAD::::::::::::::\n"+str);
// header = readHeader(in.wrappedReadBytes(11));
// byte[] h = head.array();
// Log.d("FlvAtom","Header "+Utils.toHex(h,0,h.length,true));
//ここでタグ内のデータがChannelBufferとして取得される→native化はここを代替してやればいい
//ここでinはヘッダを読んだ後、4バイト(拡張タイムスタンプ+ストリームID)進んだ状態になって返ってくる
//ここのreadでサイズ分new byte[]アロケートされている!!!!これ重いんでないか?
data = in.wrappedReadBytes(header.getSize());//メタデータのデータを突っ込む
byte[] ba = data.toByteBuffer().array();
str = "";
for(int i = 0; i < 30; i++){
if(i % 30 == 0)str += "\n";
str += String.format("%02X ", ba[i]);
}
Log.d("NLiveRoid" ,"DATA::::::::::::::\n"+str);
// byte[] ba = data.toByteBuffer().array();
// Log.d("FlvAtom","data:"+Utils.toHex(ba,0,ba.length,true));
//4バイト(1つ前のタグのサイズ→必ず00 00 00 00)進める
in.position(in.position() + 4);
//StaticDebug.setTime(header.getTime());
}
/**
* F4vReader
* FlvWriter
* から呼ばれる
* @return
*/
public FlvAtom(final MessageType messageType, final int time, final ChannelBuffer in) {
header = new RtmpHeader(messageType, time, in.readableBytes());
data = in;
// Log.d("new FlvAtom r"," ----"+data.toString());
}
/**
* ここが呼ばれる前に普通にnewされているはずなので、headerとdataは既にある想定で
* 1つのChannelBufferの参照にヘッダ、データを入れる
* F4vReader#next
* FlvReader#next
* FlvWriter#write
* から呼ばれる
* @return
*/
public ChannelBuffer write() {
// Log.d("FlvAtom","write HeaderSize" + header.getSize());
final ChannelBuffer out = ChannelBuffers.buffer(ChannelBuffers.BIG_ENDIAN,15 + header.getSize());
// final ChannelBuffer out = ChannelBuffers.buffer(ChannelBuffers.BIG_ENDIAN,header.getSize()+4);
//ヘッダーを書き込む
out.writeByte((byte) header.getMessageType().intValue());
out.writeMedium(header.getSize());
out.writeMedium(header.getTime());
out.writeInt(0); // 4 bytes of zeros (reserved)
//データを書き込む
out.writeBytes(data,data.readableBytes());
out.writeInt(header.getSize() + 11); // previous tag size(Previousとかいいながら、このタグのサイズな件)
// byte[] ba = out.toByteBuffer().array();
// Log.d("FlvAtom","write()data:"+Utils.toHex(ba,0,ba.length,true));
return out;
}
//FileChannelがChannelBufferとして確保されたもの
//ヘッダーとして読み出すべき11バイトが入ってくる
public static RtmpHeader readHeader(final ChannelBuffer in) {
byte type= in.readByte();
// byte[] ba = in.copy().array();
// Log.d("FlvAtom","readHeader"+Utils.toHex(ba,0,ba.length,true));
final MessageType messageType = MessageType.valueToEnum(type);
// Log.d("FlvAtom","TYPE:"+messageType.toString()+" VAL:"+new String(Utils.toHexChars(type)));
//次の3バイト
final int size = in.readMedium();
//次の3バイト
final int timestamp = in.readMedium();
in.skipBytes(4); // 拡張タイムスタンプと、ストリームIDは非対応を意味する
return new RtmpHeader(messageType, timestamp, size);
}
@Override
public RtmpHeader getHeader() {
return header;
}
@Override
public ChannelBuffer encode() {
return data;
}
@Override
public void decode(final ChannelBuffer in) {
data = in;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append(header);
sb.append(" data: ").append(data);
return sb.toString();
}
@Override
public MessageType getMessageType() {//AbstractMessage無くす為に新たに追加
return MessageType.VIDEO;
}
}