如何读取Flv视频文件的时间
来源:互联网 发布:网络填表终结者破解版 编辑:程序博客网 时间:2024/06/05 18:05
Mobicast闪播在搜索时需要反馈Flv的时间长度,可是如果使用flvmdi来将每个文件注入metadata再读取出时间,那么陈奕迅的歌词“明年今日”就相当适合我的软件了。
得自己写程序读取Flv的时间长度。
上网搜索,发现鲜有这样的文章,多数都是教你用as来读取metadata的时间,但是如果没有注入metadata,那就没办法了。
以下教程适用大多数可以读写文件的编程语言。读者需要有一定的文件读写的基础知识。补充一句,其实,大家如果不懒,英文又还过得去,可以直接看看Flv的文档,那么自然就很清晰该怎么做了,也用不着来听我罗嗦了,呵呵。
要看中文教程?好,follow me!
一、头文件
Flv的头文件格式比较简单,由9个字节组成.
前3个字节是文件格式标识 0x464C56.
第4个字节也是标识文件的版本号 0x01.
第5个字节 0x05
该字节前5个bit是保留的必须是0
第6个bit音频类型标志(TypeFlagsAudio)
第7个bit也是保留的必须是0
第8个bit视频类型标志(TypeFlagsVideo)
第6-9的四个字节保留,为的是以后flv版本的升级扩展 0x00000009。
二、文件tag和内容
Flv文件除去头文件,就是由n个tag及内容组成。
tag1 内容1,tag2 内容2 ..... tagn 内容n
我们要读取的信息如时间就在tag里面。下面我来分析一下tag。
tag的格式如下:
1字节的类型。tag的类型目前有三种,分别为音频tag(0x08),视频tag(0x09),脚本tag(0x12)。(图例中是0x12)
3个字节的数据大小,即上面所说的内容的大小 0x000920
3个字节的时间戳 数据的时间戳(单位级为毫秒,如果要转为秒要除以1000) 0x000000
1个字节的时间戳扩展 0x00
3个字节的streamID,目前都是0 0x000000
之后的0x02开始的就是数据内容了,如脚本数据内容metadata,音频数据内容,视频数据内容。
大家是否还有注意到,在0x12 tag类型前面有4个字节 0x00000000,这个是表示前一个tag的大小。由于这里是第一个tag,所以无所谓前面的tag的大小,就为0了。
知道了Flv的文件格式,要读取时间那是易如反掌了。
什么?不会读取字节?汗,请打开搜索引擎,输入“xx语言 读取字节”。
下面给出程序:
flv.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="flv.aspx.cs" Inherits="flv" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>flvinfo</title>
<style type="text/css">
body{font-size:12px;}
td{height:20px; font-size:12px; padding:3px;}
</style>
</head>
<body>
<form id="form1" runat="server">
<div style=" background:#cccccc; padding-left:20px;">
<br />
<div style=" background:#cccccc; text-align:left; padding:3px;">
<strong>Flv文件的结构:</strong><br />
<table border="1" bordercolor="#000000" cellpadding="0" cellspacing="0" style="border-collapse:collapse;">
<tr>
<td style="height: 20px" colspan="9"> Flv的头文件格式比较简单,由9个字节组成. </td>
<td style="height: 20px" colspan="4"> tag1</td>
<td style="height: 20px"> tag2</td>
<td style="height: 20px" colspan="3"> tag3</td>
<td style="height: 20px" colspan="3"> tag4</td>
<td style="height: 20px"> tag5</td>
<td style="height: 20px" colspan="3"> tag6</td>
<td style="height: 20px;"></td>
</tr>
<tr>
<td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td> 6</td><td>7</td><td>8</td><td>9</td><td>10</td><td>11</td><td>12</td><td>13</td>
<td>14</td><td>15</td><td> 16</td><td>17</td><td>18</td><td>19</td><td>20</td><td>21</td><td>22</td><td>23</td><td>24</td><td>25...</td>
</tr>
<tr>
<td style="background-color: #ffff66; height: 20px;">46</td><td style="background-color: #ffff66; height: 20px;">4C</td>
<td style="background-color: #ffff66; height: 20px;">56</td><td style="background-color: #ffff66; height: 20px;">01</td>
<td style="background-color: #ffff66; height: 20px;">05</td><td style="background-color: #ffff66; height: 20px;">00</td>
<td style="background-color: #ffff66; height: 20px;">00</td><td style="background-color: #ffff66; height: 20px;">00</td>
<td style="background-color: #ffff66; height: 20px;">09</td><td style="background-color: #72ABD8; height: 20px;">00</td>
<td style="background-color: #72ABD8; height: 20px;">00</td><td style="background-color: #72ABD8; height: 20px;">00</td>
<td style="background-color: #72ABD8; height: 20px;">00</td><td style="background-color: #72ABD8; height: 20px;">12</td>
<td style="background-color: #72ABD8; height: 20px;">00</td><td style="background-color: #72ABD8; height: 20px;">09</td>
<td style="background-color: #72ABD8; height: 20px;">20</td><td style="background-color: #72ABD8; height: 20px;">00</td>
<td style="background-color: #72ABD8; height: 20px;">00</td><td style="background-color: #72ABD8; height: 20px;">00</td>
<td style="background-color: #72ABD8; height: 20px;">00</td><td style="background-color: #72ABD8; height: 20px;">00</td>
<td style="background-color: #72ABD8; height: 20px;">00</td><td style="background-color: #72ABD8; height: 20px;">00</td>
<td style="height: 20px;">02...</td>
</tr>
<tr>
<td style="height: 20px; text-align: left;" colspan="3">格式标识</td>
<td style="height: 20px; text-align: left;">版本号</td>
<td style="height: 20px; text-align: left;">
该字节前5个bit是保留的必须是0<br />
第6个bit音频类型标志(TypeFlagsAudio)<br />
第7个bit也是保留的必须是0<br />
第8个bit视频类型标志(TypeFlagsVideo)</td>
<td style="height: 20px; text-align: left;" colspan="4">字节保留,为以后<br />flv版本升级扩展</td>
<td style="height: 20px; text-align: left;" colspan="4">
前一个tag大小<br />
由于这里是第<br />
一个tag所以无<br />
所谓前面的tag<br />
大小,就为0了</td>
<td style="height: 20px; text-align: left;">脚本tag(0x12)<br />音频tag(0x08)<br />视频tag(0x09)</td>
<td style="height: 20px; text-align: left;" colspan="3">数据大小<br />内容大小</td>
<td style="height: 20px; text-align: left;" colspan="3" >时间戳<br />单位级毫秒,<br />如果要转为<br />秒要除以1000</td>
<td style="height: 20px; text-align: left;"> 时间戳扩展</td>
<td style="height: 20px; text-align: left;" colspan="3">streamID<br />目前都是0<br />0x000000</td>
<td style="height: 20px; text-align: left;">
metadata<br />
数据内容<br />
脚本数据内容<br />
音频数据内容<br />
视频数据内容</td>
</tr>
</table>
</div>
<div style=" background:#cccccc; text-align:left; padding:3px;">
<asp:Label ID="flvInfo" runat="server" Text="暂无信息"></asp:Label>
</div>
<div style=" background:#cccccc; text-align:left; padding:3px;">
<asp:Button ID="Button1" runat="server" Text="rename" BackColor="DarkGray" BorderColor="#000000" BorderStyle="Solid" BorderWidth="1px" OnClick="Button1_Click" />
</div>
</div>
</form>
</body>
</html>
flv.aspx.cs:
using System;
using System.IO;
using System.Text;
public partial class flv : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
//
}
public struct FlvInfo
{
//头文件
public string Expand; //3个字节,格式, (前3个字节文件格式标识.)
public string Version; //1个字节,版本, (第4个字节也是标识文件的版本号)
public string Flags; //1个字节,标志, (该字节前5个bit是保留的必须是0,第6个bit音频类型标志(TypeFlagsAudio,第7个bit也是保留的必须是0,第8个bit视频类型标志(TypeFlagsVideo))
public string VerUpgrade; //4个字节,升级, (第6-9的四个字节保留,为的是以后flv版本的升级扩展 0x00000009.)
//tag
public string FrontTagSize; //4个字节,前一个tag的大小
public string TagClass; //1个字节,TAG类型,tag的类型目前有三种,分别为音频tag(0x08),视频tag(0x09),脚本tag(0x12)。
public string ContentSize; //3个字节,数据大小,即上面所说的内容的大小
public string AllTime; //3个字节,时间戳,数据的时间戳(单位级为毫秒,如果要转为秒要除以1000)
public string TimeExpand; //1个字节,时间戳扩展
public string StreamID; //3个字节,streamID,目前都是0 0x000000
}
/// <summary>
/// 获取Flv文件开始的24个字节
/// </summary>
/// <param name="FileName">文件名</param>
/// <returns>返回字节数组</returns>
private byte[] getBegin24(string FileName)
{
FileStream fs = new FileStream(FileName, FileMode.Open, FileAccess.Read);
Stream stream = fs;
stream.Seek(0, SeekOrigin.Begin);
const int seekPos = 64;
int rl = 0;
byte[] Info = new byte[seekPos];
rl = stream.Read(Info, 0, seekPos);
fs.Close();
stream.Close();
return Info;
}
/// <summary>
/// 获取Flv相关信息,对上面返回的字节数组分段取出,并保存到FlvInfo结构中返回。
/// </summary>
/// <param name = "Info">从Flv文件中截取的二进制信息</param>
/// <returns>返回一个FlvInfo结构</returns>
private FlvInfo getFlvInfo(byte[] Info)
{
FlvInfo flvInfo = new FlvInfo();
int i;
int j;
int position = 0;//循环的起始值
int currentIndex = 0;//Info的当前索引值
////获取格式
j = 0;
byte[] bytExpand = new byte[3];//将格式部分读到一个单独的数组中
for (i = currentIndex; i < currentIndex + 3; i++)
{
bytExpand[j] = Info[i];
position++;
j++;
}
currentIndex = position;
flvInfo.Expand = this.byteToString(bytExpand);
//获取版本
j = 0;
byte[] bytVersion = new byte[1];//将版本部分读到一个单独的数组中
for (i = currentIndex; i < currentIndex + 1; i++)
{
bytVersion[j] = Info[i];
position++;
j++;
}
currentIndex = position;
flvInfo.Version = this.byteToString(bytVersion);
//获取Flags
j = 0;
byte[] bytFlags = new byte[1];//将Flags部分读到一个单独的数组中
for (i = currentIndex; i < currentIndex + 1; i++)
{
bytFlags[j] = Info[i];
position++;
j++;
}
currentIndex = position;
flvInfo.Flags = this.byteToString(bytFlags);
//获取VerUpgrade
j = 0;
byte[] bytVerUpgrade = new byte[4];//将VerUpgrade部分读到一个单独的数组中
for (i = currentIndex; i < currentIndex + 4; i++)
{
bytVerUpgrade[j] = Info[i];
position++;
j++;
}
currentIndex = position;
flvInfo.VerUpgrade = this.byteToString(bytVerUpgrade);
//获取FrontTagSize
j = 0;
byte[] bytFrontTagSize = new byte[4];//将FrontTagSize部分读到一个单独的数组中
for (i = currentIndex; i < currentIndex + 4; i++)
{
bytFrontTagSize[j] = Info[i];
position++;
j++;
}
currentIndex = position;
flvInfo.FrontTagSize = this.byteToString(bytFrontTagSize);
//TagClass
j = 0;
byte[] bytTagClass = new byte[1];//将FrontTagSize部分读到一个单独的数组中
for (i = currentIndex; i < currentIndex + 1; i++)
{
bytTagClass[j] = Info[i];
position++;
j++;
}
currentIndex = position;
flvInfo.TagClass = this.byteToString(bytTagClass);
//ContentSize
j = 0;
byte[] bytContentSize = new byte[3];//将ContentSize部分读到一个单独的数组中
for (i = currentIndex; i < currentIndex + 3; i++)
{
bytContentSize[j] = Info[i];
position++;
j++;
}
currentIndex = position;
flvInfo.ContentSize = this.byteToString(bytContentSize);
//AllTime
j = 0;
byte[] bytAllTime = new byte[3];//将AllTime部分读到一个单独的数组中
for (i = currentIndex; i < currentIndex + 3; i++)
{
bytAllTime[j] = Info[i];
position++;
j++;
}
currentIndex = position;
flvInfo.AllTime = this.byteToString(bytAllTime);
//TimeExpand
j = 0;
byte[] bytTimeExpand = new byte[1];//将TimeExpand部分读到一个单独的数组中
for (i = currentIndex; i < currentIndex + 1; i++)
{
bytTimeExpand[j] = Info[i];
position++;
j++;
}
currentIndex = position;
flvInfo.TimeExpand = this.byteToString(bytTimeExpand);
//StreamID
j = 0;
byte[] bytStreamID = new byte[3];//将StreamID部分读到一个单独的数组中
for (i = currentIndex; i < currentIndex + 3; i++)
{
bytStreamID[j] = Info[i];
position++;
j++;
}
currentIndex = position;
flvInfo.StreamID = this.byteToString(bytStreamID);
return flvInfo;
}
/// <summary>
/// 将字节数组转换成字符串,上面程序用到的方法.
/// </summary>
/// <param name = "b">字节数组</param>
/// <returns>返回转换后的字符串</returns>
private string byteToString(byte[] b)
{
Encoding enc = Encoding.GetEncoding("GB2312");
string str = enc.GetString(b);
str = str.Substring(0, str.IndexOf('/0') >= 0 ? str.IndexOf('/0') : str.Length);//去掉无用字符
return str;
}
/// <summary>
/// 更改文件名
/// </summary>
/// <param name="filePath">文件名</param>
/// <returns></returns>
private bool ReName(string filePath)
{
if (File.Exists(filePath))
{
FlvInfo flvInfo = new FlvInfo();
flvInfo = this.getFlvInfo(this.getBegin24(filePath));//读出文件信息
if (flvInfo.Expand.Trim().Length == 0)
{
flvInfo.Expand = "未知格式";
}
if (flvInfo.AllTime.Trim().Length == 0)
{
flvInfo.AllTime = "未知时间";
}
try
{
////更名
//File.Move(filePath, filePath.Substring(0, filePath.ToLower().LastIndexOf("//")).Trim() + "//" + "(" + flvInfo.Expand.Trim() + ")" + flvInfo.AllTime.Trim() + ".flv");
//Response.Write("<script>alert('Flv改名成功!');</script>");
string b = "<table border='1' bordercolor='#000000' cellpadding='0' cellspacing='0' style='border-collapse:collapse;'>"
+ " <tr>"
+ " <td>格式标识</td><td>版本号</td><td>前5个bit</td><td>字节保留</td><td>前一个tag大小</td>"
+ " <td>脚本tag</td><td>数据大小</td><td>时间戳</td><td>时间扩展</td><td>streamID</td>"
+ " </tr>"
+ " <tr>"
+ " <td>" + flvInfo.Expand + "</td>"
+ " <td>" + flvInfo.Version + "</td>"
+ " <td>" + flvInfo.Flags + "</td>"
+ " <td>" + flvInfo.VerUpgrade + "</td>"
+ " <td>" + flvInfo.FrontTagSize + "</td>"
+ " <td>" + flvInfo.FrontTagSize + "</td>"
+ " <td>" + flvInfo.ContentSize + "</td>"
+ " <td>" + flvInfo.AllTime + "</td>"
+ " <td>" + flvInfo.TimeExpand + "</td>"
+ " <td>" + flvInfo.StreamID + "</td>"
+ " </tr>"
+ "</table>";
//Response.Write(b);
this.flvInfo.Text = b;
return true;
}
catch (Exception e)
{
Response.Write(e.ToString());
return false;
}
}
else
{
Response.Write("<script>alert('Flv文件不存在!');</script>");
return false;
}
}
protected void Button1_Click(object sender, EventArgs e)
{
ReName(@"D:/Ffmpeg/ps1.flv");
}
}
- 如何读取Flv视频文件的时间
- 如何读取Flv视频文件的时间
- 如何读取Flv视频文件的时间
- C++获取flv视频文件的播放时间
- FLV视频文件的转换
- Flv视频文件的来源
- 用C#怎样读取一个视频文件的播放时间
- [讨论]好的在线播放flv视频文件代码
- 网页中播放FLV视频文件的代码
- 用PHP读取flv文件的播放时间长度
- C#获取 Flv视频文件播放时间长度等信息
- flash播放flv视频文件
- FLV视频文件格式分析
- c#读取视频文件的长度
- 关于其他视频文件向.flv文件转换的问题
- 视频文件转换为flv的完整解决方案(ffmpeg、mencoder)
- ASP.NET实现在线播放FLV视频文件的代码
- 解决FLV视频文件在服务器上无法播放的问题
- 两个做项目最常用功能操作的封装类 (1)
- MFC实例学习(1)----状态栏
- 两个做项目最常用功能操作的封装类 (2)
- Cookie使用中的一些要点及问题
- Tuscany SCA以独立应用方式运行的简单例子
- 如何读取Flv视频文件的时间
- 自己写的excel导入sqlserver函数
- 在weblogic中使用spring查找hibernate映射文件的陷阱
- ###页面如何能保持在点击位置而不回到页面顶部?
- 使用Today API
- 相见时难别亦难……CSDN Hero 2007 心情流水账结束篇
- C#中使用Excel
- Tomcat,出现乱码问题
- Web服务搜索与执行引擎(六)--基于Lucene的Web服务检索