写在前面:前一篇文字已经把视频的解析叙述了,http://blog.csdn.net/linyanwen99/article/details/8260199,该篇是用C/C++写的,
考虑到视频前端的开发通常是基于flash或者html来实现,这里不妨给出用actionscript3.0实现的一个,尽管在本系列文字中显得格格不入。
考虑到前一篇中该讲述的都讲得差不多了,这里不再赘述,若有差别,也只是编程语言的差别,算法是一致的。
一.BitBuffer类的实现,如下:
package com.yy.web.core.manager.voice
{
import flash.utils.ByteArray;
public class BitBuffer
{
public var size:uint = 0;
public var current:ByteArray = new ByteArray();
public var read_bits:uint = 0;
public var currentPos:uint = 0;
private var position:uint = 0;
private var byte:uint = 0;
public function BitBuffer()
{
}
public function readByte():uint{//考虑到ByteArray的readByte()方法,ByteArray会同时移动到下一个字节处,这不是该程序的本意,由此定义了该方法
position = current.position;
byte = current.readByte();
current.position = position;
return byte;
}
}
}
转载请注明出处:山水间博客,http://blog.csdn.net/linyanwen99/article/details/8260573
二.BitHandler类的实现,如下:
package com.yy.web.core.manager.voice
{
import flash.utils.ByteArray;
public class BitHandler
{
private var _width:uint = 0;
private var _height:uint = 0;
private var sps_size:uint = 0;
private var bb:BitBuffer = new BitBuffer();
private static var _instance:BitHandler = null;
public function BitHandler()
{
if(_instance != null){
throw Error("singleton strategy");
}
}
public static function getInstance():BitHandler{//单例模式
if(_instance == null){
_instance = new BitHandler();
}
return _instance;
}
public function skip_bits(bb:BitBuffer,nbits:uint):void{
var offset:uint = (nbits + bb.read_bits) / 8;
bb.current.position = bb.currentPos + offset;
bb.currentPos = bb.current.position;
bb.read_bits = (bb.read_bits + nbits) % 8;
}
public function get_bit(bb:BitBuffer):uint{
//该函数的实现,请参考前一篇的说明
}
public function get_bits(bb:BitBuffer,nbits:uint):uint{
//该函数的实现,请参考前一篇的说明
}
public function exp_golomb_ue(bb:BitBuffer):uint{
var bit:uint = 0;
var significant_bits:uint = 0;
var ret:uint = 0;
bit = get_bit(bb);
while(0 == bit){
significant_bits++;
bit = get_bit(bb);
}
ret = (1<<significant_bits) + get_bits(bb,significant_bits) - 1;
return ret;
}
public function exp_golomb_se(bb:BitBuffer):int{
var ret:int = 0;
ret = exp_golomb_ue(bb);
if(0 == (ret & 0x01)){
return -(ret >> 1);
}else{
return (ret + 1) >> 1;
}
}
public function parse_scaling_list(size:uint,bb:BitBuffer):void{
var last_scale:uint = 8;
var next_scale:uint = 8;
var i:uint = 0;
var delta_scale:int = 0;
for(i = 0;i < size;++i){
if(next_scale != 0){
delta_scale = exp_golomb_se(bb);
next_scale = (last_scale + delta_scale + 256) % 256;
}
if(next_scale != 0){
last_scale = next_scale;
}
}
}
public function parse_sps(sps:ByteArray):void{
var profile:uint = 0;
var pic_order_cnt_type:uint = 0;
var width_in_mbs:uint = 0;
var height_in_map_uints:uint = 0;
var i:uint = 0;
var size:uint = 0;
var left:uint = 0;
var right:uint = 0;
var top:uint = 0;
var bottom:uint = 0;
var frame_mbs_only_flag:uint = 0;
//calculate the key-frame`s sps size
sps.position = 0x0a;
sps_size |= (sps.readByte() << 8);
sps_size |= sps.readByte();
bb.size = sps_size;
bb.current = sps;
bb.read_bits = 0;
bb.currentPos = 0x0c;//reset the position
bb.current.position = 0x0c;
skip_bits(bb,8);
profile = get_bits(bb,8);
skip_bits(bb,16);
exp_golomb_ue(bb);
if(profile == 100 || profile == 110 || profile == 122 || profile == 144){
if(exp_golomb_ue(bb) == 3){
skip_bits(bb,1);
}
exp_golomb_ue(bb);
exp_golomb_ue(bb);
skip_bits(bb,1);
if(get_bit(bb)){
for(i=0;i<8;++i){
if(get_bit(bb)){
parse_scaling_list(i<6?16:64,bb);
}
}
}
exp_golomb_ue(bb);
pic_order_cnt_type = exp_golomb_ue(bb);
if(pic_order_cnt_type == 0){
exp_golomb_ue(bb);
}else if(pic_order_cnt_type == 1){
skip_bits(bb,1);
exp_golomb_se(bb);
exp_golomb_se(bb);
size = exp_golomb_ue(bb);
for(i=0;i<size;++i){
exp_golomb_se(bb);
}
}
exp_golomb_ue(bb);
skip_bits(bb,1);
width_in_mbs = exp_golomb_ue(bb) + 1;
height_in_map_uints = exp_golomb_ue(bb) + 1;
frame_mbs_only_flag = get_bit(bb);
if(!frame_mbs_only_flag){
skip_bits(bb,1);
}
skip_bits(bb,1);
left = right = top = bottom = 0;
if(get_bit(bb)){
left = exp_golomb_ue(bb) * 2;
right = exp_golomb_ue(bb) * 2;
top = exp_golomb_ue(bb) * 2;
bottom = exp_golomb_ue(bb) * 2;
if(!frame_mbs_only_flag){
top = top * 2;
bottom = bottom * 2;
}
}
_width = width_in_mbs * 16 - (left + right);
_height = height_in_map_uints * 16 - (top + bottom);
if(!frame_mbs_only_flag){
_height = _height * 2;
}
}
}
public function get width():uint
{
return _width;
}
public function get heigth():uint
{
return _height;
}
}
}
转载请注明出处:山水间博客,http://blog.csdn.net/linyanwen99/article/details/8260573
三.main函数的实现,如下:
package
{
import com.yy.web.core.manager.voice.BitBuffer;
import com.yy.web.core.manager.voice.BitHandler;
import flash.display.Sprite;
import flash.utils.ByteArray;
public class Main extends Sprite
{
private var sps:ByteArray = new ByteArray();
public function Main()
{
writeData();
BitHandler.getInstance().parse_sps(sps);
trace("sps len: "+0x18);
trace("video width: "+BitHandler.getInstance().width);
trace("video height: "+BitHandler.getInstance().heigth);
}
public function writeData():void{//该函数直接把视频数据写入sps,代替了从文件中读入
sps.writeByte(0x29);//可以对照前一篇中给出的视频数据图,其实就是一个字节一个字节的读入
sps.writeByte(0x00);
sps.writeByte(0x00);
sps.writeByte(0x00);
sps.writeByte(0x01);
sps.writeByte(0x64);
sps.writeByte(0x00);
sps.writeByte(0x15);
sps.writeByte(0xff);
sps.writeByte(0xe1);
sps.writeByte(0x00);
sps.writeByte(0x18);
//construct sps data
sps.writeByte(0x67);
sps.writeByte(0x64);
sps.writeByte(0x00);
sps.writeByte(0x15);
sps.writeByte(0xac);
sps.writeByte(0xd0);
sps.writeByte(0x90);
sps.writeByte(0x50);
sps.writeByte(0x7e);
sps.writeByte(0x84);
sps.writeByte(0x00);
sps.writeByte(0x00);
sps.writeByte(0x03);
sps.writeByte(0x00);
sps.writeByte(0x04);
sps.writeByte(0x00);
sps.writeByte(0x00);
sps.writeByte(0x03);
sps.writeByte(0x00);
sps.writeByte(0x50);
sps.writeByte(0x3c);
sps.writeByte(0x58);
sps.writeByte(0xb4);
sps.writeByte(0x26);
//set sps`s position 0
sps.position = 0;
}
}
}
四.运行结果,如下:
转载请注明出处:山水间博客,http://blog.csdn.net/linyanwen99/article/details/8260573