如何从SQL数据库流式传输.flv文件

12

我想把.flv文件存储在数据库中而不是文件系统中。

目前的情况:
使用ffmpeg成功将.wmv和.mpeg转换为.flv。
将图像存储在SQL Server中,并通过httphandler在我的页面上显示它们。
.avi和.mpeg视频也是如此。(但用户的软件可以查看)
如果文件位于文件系统而不是数据库中,则可以在浏览器中播放.flv文件。

我不能做的是:
直接从数据库向JW Player流式传输.flv视频。(以二进制数据存储)

我已经在互联网上搜索了两天,但无法使其正常工作。 JW Player会打开并开始“缓冲”,但没有任何反应。

我知道没有简单的答案,但如果有人以前已经做过这个或类似的事情,我想知道你是如何做的。我感觉我有太多的代码要发布在这里。

提前致谢!


4
非常有趣的问题!(“wicked”在这里是加强语气的意思,可以翻译为“非常”) - jcolebrand
你能发一段代码或者讨论一下当.flv文件在文件系统中时如何进行流式传输吗? - Cameron Jordan
只需使用我的答案中的代码,但将SqlDataReader()替换为FileStream()。 - Niklas
3个回答

4
我已经让它工作了,但我不知道它的效率如何。从连接、效率和负载等方面来看,从文件系统流还是从数据库流更好呢?我需要一些指导!
我在这里使用JW Player,因此需要使用“swfobject.js”和“player.swf”。
httpHandler:
public class ViewFilm : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        try
        {
            // Check if id was given
            if (context.Request.QueryString["id"] != null)
            {
                string movId = context.Request.QueryString["id"];

                // Connect to DB and get the item id
                using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["ApplicationServices"].ConnectionString))
                using (SqlCommand cmd = new SqlCommand("GetItem", con))
                {
                    cmd.CommandType = CommandType.StoredProcedure;
                    SqlParameter sqlParam = cmd.Parameters.Add("@itemId", SqlDbType.Int);
                    sqlParam.Value = movId;

                    con.Open();
                    using (SqlDataReader dr = cmd.ExecuteReader())
                    {
                        if (dr.HasRows)
                        {
                            dr.Read();
                            // Add HTTP header stuff: cache, content type and length
                            context.Response.Cache.SetCacheability(HttpCacheability.Public);
                            context.Response.Cache.SetLastModified(DateTime.Now);
                            context.Response.AppendHeader("Content-Type", "video/x-flv");
                            context.Response.AppendHeader("Content-Length", ((byte[])dr["data"]).Length.ToString());
                            context.Response.BinaryWrite((byte[])dr["data"]);
                        }
                    }
                }
            }
        }
        catch (Exception ex)
        {
            throw new Exception(ex.ToString());
        }
    }

    public bool IsReusable
    {
        get { return false; }
    }
}

Javascript
该函数将播放器添加到 <div id="video1"> 中,可以在用户单击按钮时调用。

<script type='text/javascript' src='swfobject.js'></script>
<script type="text/javascript" language="javascript">
function vid() {
  var s1 = new SWFObject('player.swf', 'player1', '480', '270', '9');
  s1.addParam('allowfullscreen', 'true');
  s1.addParam('allowscriptaccess', 'always');
  s1.addVariable('file', encodeURIComponent('ViewFilm.ashx?id=10'));
  s1.addVariable('type', 'video');
  s1.write(document.getElementById("video1"));
}
</script>

关于您的处理程序,以下是一些提示:
  1. try ... catch 目前只是丢弃信息,应该删除,因为允许错误传播会提供更多信息。
  2. 对于您的 SqlConnection、SqlCommand、SqlDataReader 实例,应使用 using 语句确保始终处置(关闭)所有内容,即使抛出异常也是如此。
  3. 您目前正在将整个文件读入内存,这不会扩展;为了扩展,您可以在命令上使用 SequentialAccess,然后反复从读取器中的缓冲区获取字节并将其写入响应中。
- Cameron Jordan
我无法让它正常工作,所以我将其发布为另一个问题: http://stackoverflow.com/questions/4468944/how-to-add-sequential-access-in-httphandler-for-video-stream - Niklas
一和二点已经更新。但是顺序访问仍然是个谜。 - Niklas

2

不确定“直接从数据库流式传输”应该如何理解,但是将JW播放器的源文件设置为“ServeFLV.aspx?id=123”,并让ServeFLV.aspx从数据库中检索字节,然后在响应中写出无标记的字节,这样是否可行?


2
我认为你离正确答案很近了。不要使用包含所有相关页面生命周期的aspx文件,而是使用ashx处理程序。它更简单、更快,并且专门为这种类型的事情构建。 - NotMe

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接