Rose debug info
---------------

Flash Video (FLV) на ASP.NET

Сейчас на микрософтовских блогах вовсю пропогандируется Silverlight, кстати уже версии 2.0, не дав пожить версии 1.1 даже трёх недель, ну что ж, возможно через несколько лет эта технология и убъет Flash, как они обещали еще года 2 назад, но на данный момент, flash все-таки рулит.

Недавно мне была поставлена задача — создать некое подобие YouTube. Сейчас я над ней работаю, и на нее можно время от времени поглядывать, следя за изменениями: мертвая ссылка. Скоро проект будет завершени и переедет на хостинг заказчика, ну а как внедрять потоковое видео (Flash Video) в ASP.NET приложения я все хочу показать.

Для начала, нужно на IIS выставить настройки, чтобы он обрабатывала запросы на файлы .FLV: в свойствах сайта нужно выбрать «Home Directory» и ткнуть в «Configuration».

Потом ткунть Add и прописать Extension:.flv, Executable:aspnet_isapi.dll, Verbs:Get,Head,Post,Debug

Теперь файлы .flv будут «цепляться» ASP.NET, но он не знает что с этим добром делать и нужно добавить в Web.config хэндлер ручками:

<httpHandlers>        
        <add verb="*" path="*.flv" type="FLVStreaming" />
    </httpHandlers>

И в закинуть в папку App_Code файл FLVStreaming.cs

using System;
using System.IO;
using System.Web;
	
public class FLVStreaming : IHttpHandler

{

    // FLV header

    private static readonly byte[] _flvheader = HexToByte("464C5601010000000900000009");

    public FLVStreaming()

    {

    }

    public void ProcessRequest(HttpContext context)

    {

        try

        {

            int pos;

            int length;

            // Check start parameter if present

            string filename = Path.GetFileName(context.Request.FilePath);

            using (FileStream fs = new FileStream(context.Server.MapPath(filename), FileMode.Open, FileAccess.Read, FileShare.Read))

            {

                string qs = context.Request.Params["start"];

                if (string.IsNullOrEmpty(qs))

                {

                    pos = 0;

                    length = Convert.ToInt32(fs.Length);

                }

                else

                {

                    pos = Convert.ToInt32(qs);

                    length = Convert.ToInt32(fs.Length - pos) + _flvheader.Length;

                }

                // 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", length.ToString());

                // Append FLV header when sending partial file

                if (pos > 0)

                {

                    context.Response.OutputStream.Write(_flvheader, 0, _flvheader.Length);

                    fs.Position = pos;

                }

                // Read buffer and write stream to the response stream

                const int buffersize = 16384;

                byte[] buffer = new byte[buffersize];

                

                int count = fs.Read(buffer, 0, buffersize);

                while (count > 0)

                {

                    if (context.Response.IsClientConnected)

                    {

                        context.Response.OutputStream.Write(buffer, 0, count);

                        count = fs.Read(buffer, 0, buffersize);

                    }

                    else

                    {

                        count = -1;

                    }

                }

            }

        }

        catch (Exception ex)

        {

            System.Diagnostics.Debug.WriteLine(ex.ToString());

        }

    }

    public bool IsReusable

    {

        get { return true; }

    }

    private static byte[] HexToByte(string hexString)

    {

        byte[] returnBytes = new byte[hexString.Length / 2];

        for (int i = 0; i < returnBytes.Length; i++)

            returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);

        return returnBytes;

    }

}

Всё что осталось сделать дальше, это добавить SWF плеер на ваши ASP.NET страницы, например, FLV-Scrubber

<object 
  classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" 
  codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,19,0"  width="336"  height="297">    
  <param name="movie" value="scrubber.swf?file=http://&bufferTime=3&autoStart=false" />    
  <param name="quality" value="high" />    
  <embed src="scrubber.swf?file=http://&bufferTime=3&autoStart=false" 
    quality="high" 
    pluginspage="http://www.macromedia.com/go/getflashplayer" 
    type="application/x-shockwave-flash" 
    width="336" 
    height="297"></embed>  
</object>

В проекте Автомания-ТВ мы используем свой самописный плеер. Для кодирования из форматов AVI мы пользуемся ffmpeg и flvtool2 для добавления корректных метаданных в файл .flv.

1 комментарий
г-н Тараканофф 2010

Спасибо! Очень пригодилось! Особенно, подробное описание, как обрабатывать сам запрос от проигрываетеля в хэндлере.