/*
* 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.message;
import java.math.BigInteger;
import com.flazr.rtmp.RtmpHeader;
import com.flazr.util.Utils;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
public class Video extends DataMessage {
public static final int H263VIDEOPACKET = 2;
public static final int SCREENVIDEOPACKET = 3;
public static final int ON2VP6 = 4;
public static final int KEYFRAME = 1;
public static final int INTERFRAME = 2;
public static final int DISPOSABLEINTERFRAME = 3;
private int width = -1;
private int height = -1;
@Override
public boolean isConfig() { // TODO now hard coded for avc1
return data.readableBytes() > 3 && data.getInt(0) == 0x17000000;
}
public Video(final RtmpHeader header, final ChannelBuffer in) {
super(header, in);
}
public Video(final byte[] ... bytes) {
super(bytes);
}
public Video(final int time, final byte[] videoData, final int length){
header.setTime(time);
data = ChannelBuffers.wrappedBuffer(videoData, 0, length);
header.setSize(data.readableBytes());
}
public Video(final int time, final byte[] prefix, final int compositionOffset, final byte[] videoData) {
header.setTime(time);
data = ChannelBuffers.wrappedBuffer(prefix, Utils.toInt24(compositionOffset), videoData);
header.setSize(data.readableBytes());
}
public Video(final int time, final ChannelBuffer in) {
super(time, in);
}
public static Video empty() {
Video empty = new Video();
empty.data = ChannelBuffers.wrappedBuffer(new byte[2]);
return empty;
}
@Override
public MessageType getMessageType() {
return MessageType.VIDEO;
}
public int getCodec() {
return (data.getByte(0) & 0x0f) >> 0;
}
public int getFrameType() {
return (data.getByte(0) & 0xf0) >> 4;
}
// read binary string from existing byte[]
public String readBinaryString(byte[] mpb, int start, int len){
byte[] buf = new byte[len];
System.arraycopy(mpb,start,buf,0,len);
return new BigInteger(buf).toString(2);
} //readBinaryString()
public int bit2uint(char[] bits){
int uint = 0;
for(int i=0;i<bits.length;i++){
if(bits[i] == '1'){
uint += Math.pow(2, (bits.length -i -1));
}
}
return uint;
}//bit2uint
private String padBitSequence(String bitSrc){
String bitSeq = bitSrc;
int pad = 72 - bitSeq.length();
if(pad > 0){
for(int i=0;i<pad;i++){
bitSeq = "0" + bitSeq;
}
}
return bitSeq;
}//padBitSequence()
private int findWidth(String bits, int hwCheck){
int width = 0;
switch(hwCheck){
case 0:
width = bit2uint(bits.substring(33,41).toCharArray());
break;
case 1:
width = bit2uint(bits.substring(33,49).toCharArray());
break;
case 2:
width = 352;
break;
case 3:
width = 176;
break;
case 4:
width = 128;
break;
case 5:
width = 320;
break;
case 6:
width = 160;
break;
}
return width;
}//getWidth()
private int findHeight(String bits, int hwCheck){
int height = 0;
switch(hwCheck){
case 0:
height = bit2uint(bits.substring(41,49).toCharArray());
break;
case 1:
height = bit2uint(bits.substring(49,65).toCharArray());
break;
case 2:
height = 288;
break;
case 3:
height = 144;
break;
case 4:
height = 96;
break;
case 5:
height = 240;
break;
case 6:
height = 120;
break;
}
return height;
}//findHeight()
private void solveWidthAndHeight() {
String bits = padBitSequence(readBinaryString(data.toByteBuffer().array(), 1, 9));
if (getCodec() == H263VIDEOPACKET) {
int hwCheck = bit2uint(bits.substring(30,33).toCharArray());
width = findWidth(bits, hwCheck);
height = findHeight(bits, hwCheck);
} else if (getCodec() == SCREENVIDEOPACKET) {
width = bit2uint(bits.substring(4,16).toCharArray());
height = bit2uint(bits.substring(16,28).toCharArray());
}
}
public int getWidth() {
if (width == -1)
solveWidthAndHeight();
return width;
}
public int getHeight() {
if (height == -1)
solveWidthAndHeight();
return height;
}
public byte[] getBody() {
return data.toByteBuffer().array();
}
}