最经公司有一个小项目需要把视频转换成FLASH文件,效果就是像用户注册youku网一样,自己可以视频上传,转换成flash格式播放。
苦于以前没有做过,于是马上搜索了相关的文章,看了
http://www.cnblogs.com/xiucai/ 和
http://www.cnblogs.com/seebook/关于这方面的文章,对我帮助很大。今天第一天开博,我就记录下它们。
现在出现很多的在线视频网站,其实其文件播放的格式都是.FLV格式(开始还以为是swf了)。
首先,新建一个工程,然后我们部署一下文件夹。在工程的目录下新建几个文件夹如下图:
UpFiles文件夹是要保存你上传的文件(未转换的原始视频文件)
PlayFiles文件夹是用于你转换后保存下的文件(这个转完了就是.flv的格式了,用于网上播放)
ImgFile文件夹是保存截取视频文件的图片
至于mencoder和ffmpeg文件夹。则是视频转换必须的工具引擎。没有mencoder+ffmpeg就根本没办法视频转换了.
(ffmpeg最新版本的下载地址:
http://ffdshow.faireal.net/mirror/ffmpeg/
Mencoder新版本的下载地址:
http://www5.mplayerhq.hu/MPlayer/releases/win32/)
测试过了,我就是从这里下的。
下面开始正题。
首先,在配置文件中给这些文件夹进行路径的配置.如下
<
appSettings
>
<!--
工具文件夹
-->
<
add
key
="ffmpeg"
value
="ffmpeg/ffmpeg.exe"
/>
<
add
key
="mencoder"
value
="mencoder/mencoder.exe"
/>
<
add
key
="mplayer"
value
="mencoder/mplayer.exe"
/>
<!--
上传文件的路径
-->
<
add
key
="upfile"
value
="UpFiles"
/>
<!--
上专文件图片路径
-->
<
add
key
="imgfile"
value
="ImgFile"
/>
<!--
上传文件图片大小
-->
<
add
key
="CatchFlvImgSize"
value
="240x180"
/>
<
add
key
="widthSize"
value
="400"
/>
<
add
key
="heightSize"
value
="350"
/>
<!--
转换后文件路径
-->
<
add
key
="playfile"
value
="PlayFiles"
/>
</
appSettings
>
在上传.ASPX页面中
标题:
<
asp:TextBox
ID
="txtTitle"
runat
="server"
Width
="358px"
></
asp:TextBox
>
<
asp:RequiredFieldValidator
ID
="RequiredFieldValidator2"
runat
="server"
ControlToValidate
="txtTitle"
ErrorMessage
="标题不为空"
></
asp:RequiredFieldValidator
>
<
br
/>
<
asp:FileUpload
ID
="FileUpload1"
runat
="server"
Width
="339px"
/>
<
asp:Button
ID
="btnUpload"
runat
="server"
OnClick
="btnUpload_Click"
Text
="上传视频"
Width
="70px"
/>
文件类型
<
span
style
="color:Red;"
>
(.asf|.flv|.avi|.mpg|.3gp|.mov|.wmv|.rm|.rmvb)
</
span
>
<
asp:RegularExpressionValidator
ID
="imagePathValidator"
runat
="server"
ErrorMessage
="文件类型不正确"
ValidationGroup
="vgValidation"
Display
="Dynamic"
ValidationExpression
="^[a-zA-Z]:(\\.+)(.asf|.flv|.avi|.mpg|.3gp|.mov|.wmv|.rm|.rmvb)$"
ControlToValidate
="FileUpload1"
>
</
asp:RegularExpressionValidator
>
<
asp:RequiredFieldValidator
ID
="RequiredFieldValidator1"
runat
="server"
ControlToValidate
="FileUpload1"
ErrorMessage
="文件不为空"
></
asp:RequiredFieldValidator
></
div
>
<
div
style
=" height:0px; border-top:solid 1px red; font-size:0px;"
></
div
>
<
div
>
上传列表.
</
div
>
程序工作的原理是:视频先上传上去,然后跟着就是开始转换.
所以.在CS 文件中有
这里为了方便我是用sqlDatasource数据控件做数据的操作.
using
System;
using
System.Data;
using
System.Configuration;
using
System.Web;
using
System.Web.Security;
using
System.Web.UI;
using
System.Web.UI.WebControls;
using
System.Web.UI.WebControls.WebParts;
using
System.Web.UI.HtmlControls;
public
partial
class
_Default : System.Web.UI.Page
{
//
扩展名定义
string
[] strArrFfmpeg
=
new
string
[] {
"
asf
"
,
"
avi
"
,
"
mpg
"
,
"
3gp
"
,
"
mov
"
};
string
[] strArrMencoder
=
new
string
[] {
"
wmv
"
,
"
rm
"
,
"
rmvb
"
};
protected
void
Page_Load(
object
sender, EventArgs e)
{
}
//
protected
void
btnUpload_Click(
object
sender, EventArgs e)
{
string
upFileName
=
""
;
if
(
this
.FileUpload1.HasFile)
{
string
fileName
=
PublicMethod.GetFileName(
this
.FileUpload1.FileName);
//
GetFileName();
if
((
string
)Session[
"
file
"
]
==
fileName)
{
return
;
}
upFileName
=
Server.MapPath(PublicMethod.upFile
+
fileName);
this
.FileUpload1.SaveAs(upFileName);
string
saveName
=
DateTime.Now.ToString(
"
yyyyMMddHHmmssffff
"
) ;
string
playFile
=
Server.MapPath(PublicMethod.playFile
+
saveName);
string
imgFile
=
Server.MapPath(PublicMethod.imgFile
+
saveName);
//
System.IO.File.Copy(Server.MapPath(PublicMethod.playFile + "00000002.jpg"), Server.MapPath(PublicMethod.imgFile+"aa.jpg"));
PublicMethod pm
=
new
PublicMethod();
string
m_strExtension
=
PublicMethod.GetExtension(
this
.FileUpload1.PostedFile.FileName).ToLower();
if
(m_strExtension
==
"
flv
"
)
{
//
直接拷贝到播放文件夹下
System.IO.File.Copy(upFileName, playFile
+
"
.flv
"
);
pm.CatchImg(upFileName, imgFile);
}
string
Extension
=
CheckExtension(m_strExtension);
if
(Extension
==
"
ffmpeg
"
)
{
pm.ChangeFilePhy(upFileName, playFile, imgFile);
}
else
if
(Extension
==
"
mencoder
"
)
{
pm.MChangeFilePhy(upFileName, playFile, imgFile);
}
InsertData(
this
.txtTitle.Text, fileName,saveName);
Session[
"
file
"
]
=
fileName;
}
}
//
private
string
CheckExtension(
string
extension)
{
string
m_strReturn
=
""
;
foreach
(
string
var
in
this
.strArrFfmpeg)
{
if
(var
==
extension)
{
m_strReturn
=
"
ffmpeg
"
;
break
;
}
}
if
(m_strReturn
==
""
)
{
foreach
(
string
var
in
strArrMencoder)
{
if
(var
==
extension)
{
m_strReturn
=
"
mencoder
"
;
break
;
}
}
}
return
m_strReturn;
}
#region
插入数据到数据库中
private
void
InsertData(
string
MediaName,
string
fileName,
string
saveName)
{
//
string name=fileName.Substring(0, fileName.LastIndexOf('.'));
string
imgName
=
saveName
+
"
.jpg
"
;
//
图片文件名;
string
playName
=
saveName
+
"
.flv
"
;
string
sqlstr
=
"
insert into Media(FMediaName,FMediaUpPath,FMediaPlayPath,FMediaImgPath) values(@MName,@MUppath,@MPlaypath,@MImgpath)
"
;
//
string constr = ConfigurationManager.ConnectionStrings["sqlcon"].ToString();
SqlDataSource1.InsertCommand
=
sqlstr;
SqlDataSource1.InsertCommandType
=
SqlDataSourceCommandType.Text;
//
CommandType.Text;
SqlDataSource1.InsertParameters.Add(
"
MName
"
,MediaName);
SqlDataSource1.InsertParameters.Add(
"
MUppath
"
,PublicMethod.upFile
+
fileName);
SqlDataSource1.InsertParameters.Add(
"
MPlaypath
"
,PublicMethod.playFile
+
playName);
SqlDataSource1.InsertParameters.Add(
"
MImgpath
"
,PublicMethod.imgFile
+
imgName);
SqlDataSource1.Insert();
}
#endregion
}
PublicMethod类如下:
在这个类里面主要是做文件转换和保存,在转换文件的时候CPU的利用率可以达100%.
它的主要原理是另起一个进程在转换的时候你会发现你的进程里多了一个.
using
System;
using
System.Configuration;
///
<summary>
///
Summary description for PublicMethod
///
</summary>
public
class
PublicMethod:System.Web.UI.Page
{
public
PublicMethod()
{
}
//
文件路径
public
static
string
ffmpegtool
=
ConfigurationManager.AppSettings[
"
ffmpeg
"
];
public
static
string
mencodertool
=
ConfigurationManager.AppSettings[
"
mencoder
"
];
public
static
string
mplayertool
=
ConfigurationManager.AppSettings[
"
mplayer
"
];
public
static
string
upFile
=
ConfigurationManager.AppSettings[
"
upfile
"
]
+
"
/
"
;
public
static
string
imgFile
=
ConfigurationManager.AppSettings[
"
imgfile
"
]
+
"
/
"
;
public
static
string
playFile
=
ConfigurationManager.AppSettings[
"
playfile
"
]
+
"
/
"
;
//
文件图片大小
public
static
string
sizeOfImg
=
ConfigurationManager.AppSettings[
"
CatchFlvImgSize
"
];
//
文件大小
public
static
string
widthOfFile
=
ConfigurationManager.AppSettings[
"
widthSize
"
];
public
static
string
heightOfFile
=
ConfigurationManager.AppSettings[
"
heightSize
"
];
//
//
//
获取文件的名字
public
static
string
GetFileName(
string
fileName)
{
int
i
=
fileName.LastIndexOf(
"
\\
"
)
+
1
;
string
Name
=
fileName.Substring(i);
return
Name;
}
//
获取文件扩展名
public
static
string
GetExtension(
string
fileName)
{
int
i
=
fileName.LastIndexOf(
"
.
"
)
+
1
;
string
Name
=
fileName.Substring(i);
return
Name;
}
//
#region
//
运行FFMpeg的视频解码,(这里是绝对路径)
///
<summary>
///
转换文件并保存在指定文件夹下面(这里是绝对路径)
///
</summary>
///
<param name="fileName">
上传视频文件的路径(原文件)
</param>
///
<param name="playFile">
转换后的文件的路径(网络播放文件)
</param>
///
<param name="imgFile">
从视频文件中抓取的图片路径
</param>
///
<returns>
成功:返回图片虚拟地址; 失败:返回空字符串
</returns>
public
string
ChangeFilePhy(
string
fileName,
string
playFile,
string
imgFile)
{
//
取得ffmpeg.exe的路径,路径配置在Web.Config中,如:<add key="ffmpeg" value="E:\51aspx\ffmpeg.exe" />
string
ffmpeg
=
Server.MapPath(PublicMethod.ffmpegtool);
if
((
!
System.IO.File.Exists(ffmpeg))
||
(
!
System.IO.File.Exists(fileName)))
{
return
""
;
}
//
获得图片和(.flv)文件相对路径/最后存储到数据库的路径,如:/Web/User1/00001.jpg
string
flv_file
=
System.IO.Path.ChangeExtension(playFile,
"
.flv
"
);
//
截图的尺寸大小,配置在Web.Config中,如:<add key="CatchFlvImgSize" value="240x180" />
string
FlvImgSize
=
PublicMethod.sizeOfImg;
System.Diagnostics.ProcessStartInfo FilestartInfo
=
new
System.Diagnostics.ProcessStartInfo(ffmpeg);
FilestartInfo.WindowStyle
=
System.Diagnostics.ProcessWindowStyle.Hidden;
FilestartInfo.Arguments
=
"
-i
"
+
fileName
+
"
-ab 56 -ar 22050 -b 500 -r 15 -s
"
+
widthOfFile
+
"
x
"
+
heightOfFile
+
"
"
+
flv_file;
//
ImgstartInfo.Arguments = " -i " + fileName + " -y -f image2 -t 0.05 -s " + FlvImgSize + " " + flv_img;
try
{
//
转换
System.Diagnostics.Process.Start(FilestartInfo);
//
截图
CatchImg(fileName, imgFile);
//
System.Diagnostics.Process.Start(ImgstartInfo);
}
catch
{
return
""
;
}
//
return
""
;
}
//
public
string
CatchImg(
string
fileName,
string
imgFile)
{
//
string
ffmpeg
=
Server.MapPath(PublicMethod.ffmpegtool);
//
string
flv_img
=
imgFile
+
"
.jpg
"
;
//
string
FlvImgSize
=
PublicMethod.sizeOfImg;
//
System.Diagnostics.ProcessStartInfo ImgstartInfo
=
new
System.Diagnostics.ProcessStartInfo(ffmpeg);
ImgstartInfo.WindowStyle
=
System.Diagnostics.ProcessWindowStyle.Hidden;
//
ImgstartInfo.Arguments
=
"
-i
"
+
fileName
+
"
-y -f image2 -ss 2 -vframes 1 -s
"
+
FlvImgSize
+
"
"
+
flv_img;
try
{
System.Diagnostics.Process.Start(ImgstartInfo);
}
catch
{
return
""
;
}
//
if
(System.IO.File.Exists(flv_img))
{
return
flv_img;
}
return
""
;
}
#endregion
//
#region
//
运行FFMpeg的视频解码,(这里是(虚拟)相对路径)
///
<summary>
///
转换文件并保存在指定文件夹下面(这里是相对路径)
///
</summary>
///
<param name="fileName">
上传视频文件的路径(原文件)
</param>
///
<param name="playFile">
转换后的文件的路径(网络播放文件)
</param>
///
<param name="imgFile">
从视频文件中抓取的图片路径
</param>
///
<returns>
成功:返回图片虚拟地址; 失败:返回空字符串
</returns>
public
string
ChangeFileVir(
string
fileName,
string
playFile,
string
imgFile)
{
//
取得ffmpeg.exe的路径,路径配置在Web.Config中,如:<add key="ffmpeg" value="E:\51aspx\ffmpeg.exe" />
string
ffmpeg
=
Server.MapPath(PublicMethod.ffmpegtool);
if
((
!
System.IO.File.Exists(ffmpeg))
||
(
!
System.IO.File.Exists(fileName)))
{
return
""
;
}
//
获得图片和(.flv)文件相对路径/最后存储到数据库的路径,如:/Web/User1/00001.jpg
string
flv_img
=
System.IO.Path.ChangeExtension(Server.MapPath(imgFile),
"
.jpg
"
);
string
flv_file
=
System.IO.Path.ChangeExtension(Server.MapPath(playFile),
"
.flv
"
);
//
截图的尺寸大小,配置在Web.Config中,如:<add key="CatchFlvImgSize" value="240x180" />
string
FlvImgSize
=
PublicMethod.sizeOfImg;
System.Diagnostics.ProcessStartInfo FilestartInfo
=
new
System.Diagnostics.ProcessStartInfo(ffmpeg);
System.Diagnostics.ProcessStartInfo ImgstartInfo
=
new
System.Diagnostics.ProcessStartInfo(ffmpeg);
FilestartInfo.WindowStyle
=
System.Diagnostics.ProcessWindowStyle.Hidden;
ImgstartInfo.WindowStyle
=
System.Diagnostics.ProcessWindowStyle.Hidden;
//
此处组合成ffmpeg.exe文件需要的参数即可,此处命令在ffmpeg 0.4.9调试通过
//
ffmpeg -i F:\01.wmv -ab 56 -ar 22050 -b 500 -r 15 -s 320x240 f:\test.flv
FilestartInfo.Arguments
=
"
-i
"
+
fileName
+
"
-ab 56 -ar 22050 -b 500 -r 15 -s
"
+
widthOfFile
+
"
x
"
+
heightOfFile
+
"
"
+
flv_file;
ImgstartInfo.Arguments
=
"
-i
"
+
fileName
+
"
-y -f image2 -t 0.001 -s
"
+
FlvImgSize
+
"
"
+
flv_img;
try
{
System.Diagnostics.Process.Start(FilestartInfo);
System.Diagnostics.Process.Start(ImgstartInfo);
}
catch
{
return
""
;
}
/**/
///
注意:图片截取成功后,数据由内存缓存写到磁盘需要时间较长,大概在3,4秒甚至更长;
///
这儿需要延时后再检测,我服务器延时8秒,即如果超过8秒图片仍不存在,认为截图失败;
///
此处略去延时代码.如有那位知道如何捕捉ffmpeg.exe截图失败消息,请告知,先谢过!
if
(System.IO.File.Exists(flv_img))
{
return
flv_img;
}
return
""
;
}
#endregion
#region
//
运行mencoder的视频解码器转换(这里是(绝对路径))
public
string
MChangeFilePhy(
string
vFileName,
string
playFile,
string
imgFile)
{
string
tool
=
Server.MapPath(PublicMethod.mencodertool);
//
string mplaytool = Server.MapPath(PublicMethod.ffmpegtool);
if
((
!
System.IO.File.Exists(tool))
||
(
!
System.IO.File.Exists(vFileName)))
{
return
""
;
}
string
flv_file
=
System.IO.Path.ChangeExtension(playFile,
"
.flv
"
);
//
截图的尺寸大小,配置在Web.Config中,如:<add key="CatchFlvImgSize" value="240x180" />
string
FlvImgSize
=
PublicMethod.sizeOfImg;
System.Diagnostics.ProcessStartInfo FilestartInfo
=
new
System.Diagnostics.ProcessStartInfo(tool);
FilestartInfo.WindowStyle
=
System.Diagnostics.ProcessWindowStyle.Hidden;
FilestartInfo.Arguments
=
"
"
+
vFileName
+
"
-o
"
+
flv_file
+
"
-of lavf -lavfopts
i_certify_that_my_video_stream_does_not_use_b_frames -oac mp3lame -lameopts abr:br=56 -ovc lavc
-lavcopts vcodec=flv:vbitrate=200:mbd=2:mv0:trell:v4mv:cbp:last_pred=1:dia=-1:cmp=0:vb_strategy=1
-vf scale=
"
+
widthOfFile
+
"
:
"
+
heightOfFile
+
"
-ofps 12 -srate 22050
"
;
try
{
System.Diagnostics.Process.Start(FilestartInfo);
CatchImg(flv_file, imgFile);
}
catch
{
return
""
;
}
//
return
""
;
}
#endregion
}
全文的主要内容就在这里了
此DEMO的源文件可以
点击这里下载.
数据库:
先创建 数据库 test
USE [test]
GO
/****** 对象: Table [dbo].[Media] 脚本日期: 12/22/2007 10:16:06 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Media](
[FMediaName] [varchar](200) COLLATE Chinese_PRC_CI_AS NULL,
[FMediaUpPath] [varchar](200) COLLATE Chinese_PRC_CI_AS NULL,
[FMediaPlayPath] [varchar](200) COLLATE Chinese_PRC_CI_AS NULL,
[FMediaImgPath] [varchar](200) COLLATE Chinese_PRC_CI_AS NULL,
[FID] [int] IDENTITY(1,1) NOT NULL,
[FPostDate] [varchar](200) COLLATE Chinese_PRC_CI_AS NULL,
[FContent] [varchar](500) COLLATE Chinese_PRC_CI_AS NULL,
CONSTRAINT [PK_Media] PRIMARY KEY CLUSTERED
(
[FID] ASC
) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF