Subiendo y tocando videos en ASP.NET

Hace unos días un compañero me pidió que le ayudara a incluir la funcionalidad de cargar y ver video en un portal de venta de vehículo, los requerimientos eran los siguientes:

  • Permitir al usuario cargar al portal diferentes tipos de video, específicamente los más populares AVI, WMV, MPG, MP4.
  • Hacer encoding de los videos cargados para reducir su tamaño considerablemente a fin de que usuarios con poco ancho de banda puedan ver los videos.
  • Una vez cargado el video, permitir al usuario ver el video convertido.
  • El video cargado por el usuario no puede exceder los 50MB.
  • El típico requerimiento, que los componentes involucrados no alteren los costos del proyecto.

Haciendo una vista rápida de los requerimientos no parece difícil desarrollar este feature, pero la realidad es que aunque es muy popular ver video en los website no es tan fácil como parece. Primero porque hay pocos componentes gratuitos para estos fines, segundo la documentación para hacer esta tarea no es tan abundante en internet (por eso me anime a publicar este articulo) y tercero hacer el encoding en línea hace la tare un poco mas difícil.

Para desarrollar estos requerimientos utilicé las siguientes herramientas:

  1. Visual Studio 2008 (tambien puedes usar Visual Web Developer 2008).
  2. ASP.NET
  3. FFmpeg (para hacer encoding de los videos) la documentación la puede encontrar Aquí
  4. Flowplayer (para ver los videos convertidos a flv) la documentacion la puede encontrar Aquí

 

El “Website Project” creado contiene los directorios:

  • Player: contiene los archivos utilizados para visualizar un video.
  • Videos: almacena los videos, tanto el original cargado por el usuario, asi como tambien el convertido a flv.
  • ffmpeg.exe: el ejecutable utilizado para hacer el encoding a los videos.
  • Dos paginas que detallaremos a continuacion.

 

La primera página “UploadVideo.aspx” se encarga de permitirle al usuario cargar su propio video, esta se compone del HTML especificado más abajo.

 

<form id="form1" runat="server">
    <h1>
        Video Website - Upload Videos</h1>
    <div>
        <asp:FileUpload ID="videoFile" runat="server" />
        &nbsp;<asp:Button ID="btnUpload" runat="server" Text="Upload video" OnClick="btnUpload_Click" />
        <br />
    </div>
    <asp:Label ID="lblErrorVideo" runat="server" EnableViewState="False" CssClass="redbold"></asp:Label>
</form>

 

Si tiene experiencia cargando archivo desde ASP.NET sabrás que por defecto no se pueden cargar archivos que excedan los 4MB por lo que debemos de modificar el web.config de nuestro web.config, específicamente debajo del tag <system.web> de esta forma:

<system.web>
    <httpRuntime maxRequestLength="51200" />

 

El atributo “maxRequestLength” se especifica en KB.

Lo interesante de esta página ocurre en su code behind, observemos:

Variables globales utilzadas en el codigo (esto puede venir del web.config o del cualquier otra configuración).

    //Ruta en donde se van a guardar los videos.
    string videoOriginalPath = "~/Videos/Original/";
    string videoConvertedPath = "~/Videos/Converted/";
 
    //Variables utilizadas para manejar los nombres.
    string videoTmpName = string.Empty;
    string flv = ".flv";
    string videoConvertedName = string.Empty;

 

El código que ejecuta el evento Click del button Upload se encarga de validar la extensiones permitidas (línea 6), que el archivo no exceda los 50MB (línea 13)  y en la línea 26 se hace el encoding y si todo resulta bien, entonces direccionamos a la página de visualización de videos.

 

   1:   protected void btnUpload_Click(object sender, EventArgs e)
   2:      {
   3:          HttpPostedFile file = videoFile.PostedFile;
   4:   
   5:          //Validamnos la extension del archivo
   6:          if (!ValidateVideoExtension(file.FileName))
   7:          {
   8:              lblErrorVideo.Text = "La extension del archivo no es permitido.";
   9:              return;
  10:          }
  11:   
  12:          //Verificamos el tamano del archivo de que no exceda los 50MB.
  13:          if (file.InputStream.Length > 52428800)
  14:          {
  15:              lblErrorVideo.Text = "El video no puede exceder los 50MB";
  16:              return;
  17:          }
  18:   
  19:          //Guardamos el video
  20:          string saveAs = Server.MapPath(videoOriginalPath);
  21:          videoTmpName = Guid.NewGuid().ToString();
  22:          string originalVideo = saveAs + videoTmpName + new FileInfo(file.FileName).Extension;
  23:          file.SaveAs(originalVideo);
  24:   
  25:          //Hacemos el Encondding del video
  26:          if (EncodingVideo(originalVideo)){
  27:              Response.Redirect("MyVideos.aspx?Id=" + videoConvertedName);
  28:          }
  29:          else {
  30:              lblErrorVideo.Text = "Error convirtiendo el video, intente nuevamente";
  31:          }
  32:      }

 

La funcion “ValidateVideoExtension” se límita a verificar la extensión del archivo cargado:

 

   1:   private bool ValidateVideoExtension(string filename)
   2:      {        
   3:          FileInfo info = new FileInfo(filename);
   4:          switch (info.Extension.ToLower())
   5:          {
   6:              case ".mpg":
   7:              case ".wmv":
   8:              case ".avi":
   9:              case ".mp4":
  10:                  return true;
  11:              default:
  12:                  return false;
  13:          }
  14:      }

 

En la función “EncodingVideo” hacemos uso de la Clase “Process” bajo el namespace “System.Diagsnotics”, esta clase nos permite hacer ejecucion de procesos locales o remotos, en este caso la ejecución del ffmpeg.exe.  En la línea 8 se específican los parametros utilizados para el encoding,  la definicion de estos parámetros se encuentran en la documentación del ffmpeg,  un metodo que es imprescindible para este proceso en linea es “encoding.WaitForExit()” el cual espera a que el proceso concluya.  debajo el codigo de esta función.

 

   1:   private bool EncodingVideo(string originalVideo)
   2:      {
   3:          bool value = false;        
   4:          string saveAs = Server.MapPath(videoConvertedPath);
   5:          videoConvertedName = videoTmpName + flv;
   6:   
   7:          //Parametros que se le pasaran al ejecutable para fines de encoding.
   8:          string args = @" -i " + originalVideo + " -b 200 -r 24 -s 320x240 -deinterlace -ab 64k " + saveAs + videoConvertedName;
   9:   
  10:          //Hacemos uso de la clase proxy la cual nos provee acceso directo al ejecutable.
  11:          using (Process enconding = new Process())
  12:          {            
  13:              enconding.StartInfo.WorkingDirectory = Server.MapPath("~/");
  14:              enconding.StartInfo.FileName = Server.MapPath("ffmpeg.exe");
  15:              enconding.StartInfo.Arguments = args;
  16:              enconding.StartInfo.UseShellExecute = false;
  17:              enconding.StartInfo.CreateNoWindow = true;
  18:              enconding.StartInfo.RedirectStandardOutput = false;
  19:              enconding.Start();
  20:              //Como es un proceso en linea debemos esperar a que termine para mostrar el video sino el player dará un error de FileNotFound.
  21:              enconding.WaitForExit();
  22:              value = true;
  23:          }
  24:   
  25:          return value;
  26:   
  27:        }

 

Una vez concluido el proceso de “Encoding” tendremos en la carpeta /Videos/Converted/ el video flv, el cual mostraremos en la segunda página llamada “MyVideo.aspx”, el cual llamaremos pasandole por Querystrings el nombre del video a mostrar.  El HTML es este:

   1:  <head runat="server">
   2:      <title>My Videos Zone</title>
   3:      <!-- Hacemos referencia de la libreria que contiene el flowPlayer -->
   4:      <script src="Player/flowplayer-3.1.3.min.js" type="text/javascript"></script>
   5:  </head>
   6:  <body>
   7:    <h1>Video Website - My Video Zone</h1>
   8:      <form id="frmMain" runat="server">
   9:      <div>
  10:          <script type="text/javascript">
  11:              flowplayer("player", "player/flowplayer-3.1.3.swf");
  12:          </script>
  13:          <!-- player container-->
  14:          <a  id="player" runat="server" style="display: block; width: 320px;>
  15:              height: 240px;"
  16:              
  17:              <!-- Utilizado para colocar una mascara y evitar que el player toque el video automatico. -->
  18:              <img src="Player/flow_eye.jpg" alt="My Video Player" /> 
  19:          </a>
  20:          
  21:      </div>
  22:      </form>
  23:  </body>

 

En la línea 4 se hace referencia a la libreria de FlowPlayer, línea 10 se coloca el player, línea 14 el link sobre cual video hace referencia el player, este se asignará en el code behind de la siguiente manera:

 

   1:   protected void Page_Load(object sender, EventArgs e)
   2:      {
   3:          if (Request["Id"] != string.Empty)
   4:          {
   5:              string video = "~/Videos/Converted/" + Request["Id"].ToString();
   6:              player.HRef = video;
   7:          }
   8:      }

 

El resultado es genial un archivo WMV de 25MB puede ser reducido a 666KB, el proyecto en ejecución se veria

de esta forma

Upload[1] ViewVideo[1]

El codigo fuente puede ser descardo desde Aquí:

Technorati Tags: ,,,

18 comentarios en “Subiendo y tocando videos en ASP.NET”

  1. Genial el ejemplo, desconocía FFmpeg.

    Lo único que cambiaría un poco es la llamada al encoding.Start, que pondría en un thread a parte para que el usuario no tenga que esperar a que se transforme el vídeo. Eso puede tomar su tiempo e incluso producir timeouts no crees?

  2. Muy bueno Ronny.

    Como comentario sólo decir que es interesante comprobar el MIME type del fichero que sube el usuario, no sólo su extensión.

    Saludos 🙂

  3. Hola Ronny, en primer lugar gracias.
    Mi problema sucede cuando subo el video no se genera el flv y no se reproduce el video la carpeta de los vidos flvs, aclaro que SÏ se genera el video en mpg, avi, etc.
    que me falta???
    gracias de nuevo.

  4. Hola, Gracias por tu codigo Ronny me sirvio de mucho y me serviva para el futuro. Ya solucione mi gran problema, mi error era que me faltaban las comillas dobles(“) en las direcciones “C:User…..palyerOriginal…..flv” y “C:User…..palyerConverted…..flv” en la parte:

    string args = @” -i “” + originalVideo + “” -b 200 -r 24 -s 320×240 -deinterlace -ab 64k “” + saveAs + videoConvertedName + “””;
    y listo ahora puedo crear las flvs.

    Gracias otra ves Ronny.

  5. Se ve muy interesante, lo probare! Busco algo parecido a esto, a ver si le puedo hacer unas cuantas adecuaciones…Mas me importa la parte de reproducir el video…

  6. Error 68 No se permiten nodos secundarios. (C:EscritorioVideosWebsiteVideosWebsiteweb.config line 105)
    ************+q tal amigo sabs me sale este error recien estoy interesandom por asp porfa ayudame kon este rror muchas gracias y diskulpa la molestia

  7. hola mi problema es el siguiente utilizo ffmpeg para convertir video avi a flv, pero almaceno temporalmente mi el video original(avi) en un carpeta especial para eso, luego ejecuto shell para realizar la conversion del video y hasta una foto, enseguida de eso creo una funcion para eliminar el video original, pero resulta, que se tarda un poco en convertirlo, vi un ejemplo para que el sistema reconozca el tiempo que se tarda en ejecutarlo pero me marca un error, alguien sabe como podia hacer para que se detenga primero conviertiendo el video y despues continue el proceso normal y se vaya a la funcion de eliminar el video origina, se lo agradeceria mucho

  8. Hola, esta genial pero tengo un problema, al momento de suvir el video, es decir, al momento de apretar upload video firefox me da el siguiente error La conexión al servidor fue reiniciada mientras la página se cargaba, por que pasa eso ?

  9. Hola, yo e intentado poner el mismo codigo en vs2010 pero no funciona no hace la conversion, cosa q si en vs2008, alguien me puede ayudar ???? gracias.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *