c#实现flv解析详解示例
c#实现flv解析详解示例
发布时间:2017-01-07 来源:查字典编辑
摘要:先上效果图:工具类在解析的过程中,我们会和byte做各种运算,所以我定义了一个byte工具类ByteUtils:复制代码代码如下:using...

先上效果图:

c#实现flv解析详解示例1
工具类

在解析的过程中,我们会和byte做各种运算,所以我定义了一个byte工具类ByteUtils:

复制代码 代码如下:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.IO;

namespace FLVParer.Utils

{

class ByteUtils

{

public static uint ByteToUInt(byte[] bs, int length)

{

if (bs == null || bs.Length < length)

return 0;

uint rtn = 0;

for (int i = 0; i < length; i++)

{

rtn <<= 8;

rtn |= bs[i];

}

return rtn;

}

public static double ByteToDouble(byte[] bs)

{

if (bs == null || bs.Length < 8)

return 0;

byte[] b2 = new byte[8];

for (int i = 0; i < 8; i++)

{

b2[i] = bs[7 - i];

}

return BitConverter.ToDouble(b2, 0);

}

public static short ReadUI16(Stream src)

{

byte[] bs = new byte[2];

if (src.Read(bs, 0, 2) <= 0)

return 0;

return (short)((bs[0] << 8) | bs[1]);

}

public static uint ReadUI24(Stream src)

{

byte[] bs = new byte[3];

if (src.Read(bs, 0, 3) <= 0)

throw new IOException("Stream end.");

return ByteToUInt(bs, 3);

}

public static uint ReadUI32(Stream src)

{

byte[] bs = new byte[4];

if (src.Read(bs, 0, 4) <= 0)

throw new IOException("Stream end.");

return ByteToUInt(bs, 4);

}

public static string GetTime(uint time)

{

return (time / 60000).ToString() + ":"

+ (time / 1000 % 60).ToString("D2") + "."

+ (time % 1000).ToString("D3");

}

}

}

FLV类

FLV类,主要的类,里面包括一个header和许多的tag,也就是一个FLV文件的结构:

复制代码 代码如下:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.IO;

using FLVParer.Utils;

namespace FLVParer.Model

{

class FLV

{

public Header header { get; private set; }

List<Tag> tags;

public FLV(Stream stream)

{

header = new Header();

header.readHeader(stream);

stream.Seek(header.size, SeekOrigin.Begin);

tags = new List<Tag>();

while (stream.Position < stream.Length-4)

{

tags.Add(readTag(stream));

}

}

private Tag readTag(Stream stream)

{

Tag tag = null;

byte[] buf = new byte[4];

stream.Read(buf, 0, 4);

int type = stream.ReadByte();

switch (type)

{

case 8:

tag = new AudioTag();

break;

case 9:

tag = new VideoTag();

break;

case 18:

tag = new ScriptTag();

break;

}

tag.presize = ByteUtils.ByteToUInt(buf, 4);

tag.datasize = ByteUtils.ReadUI24(stream);

tag.timestamp = ByteUtils.ReadUI24(stream);

tag.timestamp_ex = stream.ReadByte();

tag.streamid = ByteUtils.ReadUI24(stream);

tag.readData(stream);

return tag;

}

}

}

Header类

Header类,保存FLV文件的头信息:

复制代码 代码如下:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.IO;

using FLVParer.Utils;

namespace FLVParer.Model

{

class Header

{

public String type { get; private set; }

public int version { get; private set; }

public bool hasVideo { get; private set; }

public bool hasAudio { get; private set; }

public uint size { get; private set; }

public void readHeader(Stream stream)

{

byte[] buf = new byte[4];

stream.Read(buf, 0, 3);

type = Encoding.Default.GetString(buf);

stream.Read(buf, 0, 1);

version = buf[0];

stream.Read(buf, 0, 1);

buf[0] &= 0x0f;

if ((buf[0] & 0x01) == 1)

{

hasVideo = true;

}

if ((buf[0] & 0x04) == 4)

{

hasAudio = true;

}

stream.Read(buf, 0, 4);

size = ByteUtils.ByteToUInt(buf, 4);

}

}

}

Tag类

Tag类是一个抽象类,因为tag的种类有三种,为了统一管理,抽象出Tag类:

复制代码 代码如下:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.IO;

namespace FLVParer.Model

{

enum TagType

{

video,

audio,

Script

}

abstract class Tag

{

public TagType tagType;//tag类型

public uint presize;//前一tag大小

public uint datasize;//数据区大小

public uint timestamp; //时间戳 单位ms

public int timestamp_ex;//时间戳扩展

public uint streamid;//ID

public long offset;//偏移量

public byte[] data;//数据

//对tag进行读取

public abstract void readData(Stream stream);

}

}

ScriptTag类

脚本tag类,继承自Tag类,并添加成员变量Values,用于保存脚本信息:

复制代码 代码如下:

using System.Collections.Generic;

using System.Text;

using System.IO;

using FLVParer.Utils;

namespace FLVParer.Model

{

class ScriptTag : Tag

{

public List<KeyValuePair<string, object>> Values { get; private set; }

public ScriptTag()

{

tagType = TagType.Script;

Values = new List<KeyValuePair<string, object>>();

}

public override void readData(Stream stream)

{

offset = 0;

Values.Clear();

byte[] bs = new byte[3];

while (offset < this.datasize)

{

stream.Read(bs, 0, 3);

if (bs[0] == 0 && bs[1] == 0 && bs[2] == 9)

{

offset += 3;

break;

}

stream.Seek(-3, SeekOrigin.Current);

AddElement("#" + offset, ReadElement(stream));

}

}

private void AddElement(string key, object o)

{

Values.Add(new KeyValuePair<string, object>(key, o));

}

private object ReadElement(Stream src)

{

int type = src.ReadByte();

offset++;

switch (type)

{

case 0: // Number - 8

return ReadDouble(src);

case 1: // Boolean - 1

return ReadByte(src);

case 2: // String - 2+n

return ReadString(src);

case 3: // Object

return ReadObject(src);

case 4: // MovieClip

return ReadString(src);

case 5: // Null

break;

case 6: // Undefined

break;

case 7: // Reference - 2

return ReadUShort(src);

case 8: // ECMA array

return ReadArray(src);

case 10: // Strict array

return ReadStrictArray(src);

case 11: // Date - 8+2

return ReadDate(src);

case 12: // Long string - 4+n

return ReadLongString(src);

}

return null;

}

private object ReadObject(Stream src)

{

byte[] bs = new byte[3];

ScriptObject obj = new ScriptObject();

while (offset < this.datasize)

{

src.Read(bs, 0, 3);

if (bs[0] == 0 && bs[1] == 0 && bs[2] == 9)

{

offset += 3;

break;

}

src.Seek(-3, SeekOrigin.Current);

string key = ReadString(src);

if (key[0] == 0)

break;

obj[key] = ReadElement(src);

}

return obj;

}

private double ReadDate(Stream src)

{

double d = ReadDouble(src);

src.Seek(2, SeekOrigin.Current);

offset += 2;

return d;

}

private ScriptObject ReadArray(Stream src)

{

byte[] buffer = new byte[4];

src.Read(buffer, 0, 4);

offset += 4;

uint count = ByteUtils.ByteToUInt(buffer, 4);

ScriptObject array = new ScriptObject();

for (uint i = 0; i < count; i++)

{

string key = ReadString(src);

array[key] = ReadElement(src);

}

src.Seek(3, SeekOrigin.Current); // 00 00 09

offset += 3;

return array;

}

private ScriptArray ReadStrictArray(Stream src)

{

byte[] bs = new byte[4];

src.Read(bs, 0, 4);

offset += 4;

ScriptArray array = new ScriptArray();

uint count = ByteUtils.ByteToUInt(bs, 4);

for (uint i = 0; i < count; i++)

{

array.Add(ReadElement(src));

}

return array;

}

private double ReadDouble(Stream src)

{

byte[] buffer = new byte[8];

src.Read(buffer, 0, 8);

offset += 8;

return ByteUtils.ByteToDouble(buffer);

}

private byte ReadByte(Stream src)

{

offset++;

return (byte)src.ReadByte();

}

private string ReadString(Stream src)

{

byte[] bs = new byte[2];

src.Read(bs, 0, 2);

offset += 2;

int n = (int)ByteUtils.ByteToUInt(bs, 2);

bs = new byte[n];

src.Read(bs, 0, n);

offset += n;

return Encoding.ASCII.GetString(bs);

}

private string ReadLongString(Stream src)

{

byte[] bs = new byte[4];

src.Read(bs, 0, 4);

offset += 4;

int n = (int)ByteUtils.ByteToUInt(bs, 4);

bs = new byte[n];

src.Read(bs, 0, n);

offset += n;

return Encoding.ASCII.GetString(bs);

}

private ushort ReadUShort(Stream src)

{

byte[] buffer = new byte[2];

src.Read(buffer, 0, 2);

offset += 2;

return (ushort)ByteUtils.ByteToUInt(buffer, 2);

}

}

public class ScriptObject

{

public static int indent = 0;

private Dictionary<string, object> values = new Dictionary<string, object>();

public object this[string key]

{

get

{

object o;

values.TryGetValue(key, out o);

return o;

}

set

{

if (!values.ContainsKey(key))

{

values.Add(key, value);

}

}

}

public override string ToString()

{

string str = "{rn";

ScriptObject.indent += 2;

foreach (KeyValuePair<string, object> kv in values)

{

str += new string(' ', ScriptObject.indent)

+ kv.Key + ": " + kv.Value + "rn";

}

ScriptObject.indent -= 2;

//if (str.Length > 1)

// str = str.Substring(0, str.Length - 1);

str += "}";

return str;

}

}

public class ScriptArray

{

private List<object> values = new List<object>();

public object this[int index]

{

get

{

if (index >= 0 && index < values.Count)

return values[index];

return null;

}

}

public void Add(object o)

{

values.Add(o);

}

public override string ToString()

{

string str = "[";

int n = 0;

foreach (object o in values)

{

if (n % 10 == 0)

str += "rn";

n++;

str += o + ",";

}

if (str.Length > 1)

str = str.Substring(0, str.Length - 1);

str += "rn]";

return str;

}

}

}

VideoTag类

视频tag类:

复制代码 代码如下:

using System.IO;

namespace FLVParer.Model

{

class VideoTag : Tag

{

public int frameType;//帧类型

public int encodeID;//编码ID

public VideoTag()

{

tagType = TagType.video;

}

public override void readData(Stream stream)

{

int info = stream.ReadByte();

frameType = info >> 4;

encodeID = info & 0x0f;

data = new byte[datasize - 1];

stream.Read(data, 0, (int)datasize - 1);

}

}

}

AudioTag 类

音频tag类:

复制代码 代码如下:

using System.IO;

namespace FLVParer.Model

{

class AudioTag : Tag

{

public int formate;//音频格式

public int rate;//采样率

public int size;//采样的长度

public int type;//音频类型

public AudioTag()

{

tagType = TagType.audio;

}

public override void readData(Stream stream)

{

int info = stream.ReadByte();

formate = info >> 4;

rate = (info & 0x0c) >> 2;

size = (info & 0x02) >> 1;

type = info & 0x01;

data = new byte[datasize - 1];

stream.Read(data, 0, (int)datasize - 1);

}

}

}

使用方法

用法很简单,new出来的时候把FLV文件的stream对象传进去就行了,比如我这样的:

复制代码 代码如下:

FLV flv = null;

using (FileStream fs = new FileStream("t31_stract.flv", FileMode.Open, FileAccess.Read))

{

flv = new FLV(fs);

}

之后就可以使用flv对象来分析当前flv的信息了。

推荐文章
猜你喜欢
附近的人在看
推荐阅读
拓展阅读
相关阅读
网友关注
最新C#教程学习
热门C#教程学习
编程开发子分类