title: RSS Video Feed Enhancement - Need to get duration on items that dont include it in feed
body: <p>I have a working DNLA device (Xbox360, PSP...) RSS Video feed reader in C#. It parses .opml files to get the feed uri. </p>
  
  <p>Sometimes an RSS feed item will not have a duration value, so I am hard coding a default duration value when it doesn't. </p>
  
  <p>I want to get the true duration of the video file.</p>
  
  <p>My idea is to use httpWebRequest to get a byte stream and seek out the information in the files binary metaData, if available. I'm thinking it could be done, but can find no similar examples.</p>
  
  <p>The process must be fast and does not need to get the whole video file, because the duration value is only needed to build the menu. The files I am expecting to process this way are .flv, .m4v, and .mp4's. the example shown below is for a .flv file: </p>
  
  <pre><code>using System;
  using System.IO;
  using System.Text;
  using System.Net;
  
  namespace myRSSVideoReader
  {
      public static class FlvMetadataReader
      {
          private const int BufferLength = 1000;
          /// &lt;summary&gt;
          /// Reads the meta information (if present) in an FLV
          /// &lt;/summary&gt;
          /// &lt;param name="uri"&gt;The path to the FLV file&lt;/returns&gt;
          public static MediaMetadataInfo GetMetadataInfo(string uri)
          {
              bool hasMetaData = false;
              double duration = 0;
              double width = 0;
              double height = 0;
              double videoDataRate = 0;
              double audioDataRate = 0;
              double frameRate = 0;
              DateTime creationDate = DateTime.MinValue;
  
              WebRequest req = HttpWebRequest.Create(uri);
              WebResponse res = req.GetResponse();
  
              Stream s = res.GetResponseStream(); //Source
              MemoryStream ms = new MemoryStream((int)(res as HttpWebResponse).ContentLength); //Destination
  
              byte[] b = new byte[BufferLength]; //Buffer
              int cnt = 0;
  
              do
              {
                  //Read up to 1000 bytes from the response stream
                  cnt = s.Read(b, 0, BufferLength);
  
                  //Write the number of bytes actually read
                  ms.Write(b, 0, cnt);
              }
              while (cnt &gt; 0);
  
              try
              {
                  // read where "onMetaData"
                  byte[] bytes = new byte[10];
                  ms.Seek(27, SeekOrigin.Begin);
                  int result = ms.Read(bytes, 0, 10);
  
                  // if "onMetaData" exists then proceed to read the attributes
                  string onMetaData = ByteArrayToString(bytes);
                  if (onMetaData == "onMetaData")
                  {
                      hasMetaData = true;
                      // 16 bytes past "onMetaData" is the data for "duration" 
                      duration = GetNextDouble(ms, 16, 8);
  
                      // 8 bytes past "duration" is the data for "width"
                      width = GetNextDouble(ms, 8, 8);
  
                      // 9 bytes past "width" is the data for "height"
                      height = GetNextDouble(ms, 9, 8);
  
                      // 16 bytes past "height" is the data for "videoDataRate"
                      videoDataRate = GetNextDouble(ms, 16, 8);
  
                      // 16 bytes past "videoDataRate" is the data for "audioDataRate"
                      audioDataRate = GetNextDouble(ms, 16, 8);
  
                      // 12 bytes past "audioDataRate" is the data for "frameRate"
                      frameRate = GetNextDouble(ms, 12, 8);
  
                      // read in bytes for creationDate manually
                      ms.Seek(17, SeekOrigin.Current);
                      byte[] seekBytes = new byte[24];
                      result = ms.Read(seekBytes, 0, 24);
                      string dateString = ByteArrayToString(seekBytes);
                      // create .NET readable date string
                      // cut off Day of Week
                      dateString = dateString.Substring(4);
                      // grab 1) month and day, 2) year, 3) time
                      dateString = dateString.Substring(0, 6) + " " + dateString.Substring(16, 4) + " " + dateString.Substring(7, 8);
                      // .NET 2.0 has DateTime.TryParse
                      try
                      {
                          creationDate = Convert.ToDateTime(dateString);
                      }
                      catch(Exception) 
                      {
                          // no error handling
                      }
                  }
              }
              catch (Exception)
              {
                  // no error handling
              }
              finally
              {
                  ms.Close();
                  ms.Dispose();
              }
  
              Uri newUri = new Uri(uri);
              string filename = Path.GetFileName(newUri.AbsoluteUri);
  
              return new MediaMetadataInfo(hasMetaData, filename, duration, width, height, videoDataRate, audioDataRate, frameRate, creationDate);
          }
  
          private static Double GetNextDouble(MemoryStream ms, int offset, int length)
          {
              // move the desired number of places in the array
              ms.Seek(offset, SeekOrigin.Current);
  
              // create byte array
              byte[] bytes = new byte[length];
  
              // read bytes
              int result = ms.Read(bytes, 0, length);
  
              // convert to double (all flass values are written in reverse order)
              return ByteArrayToDouble(bytes, true);
          }
  
  
          private static String ByteArrayToString(byte[] bytes)
          {
              string byteString = string.Empty;
              foreach (byte b in bytes)
              {
                  byteString += Convert.ToChar(b).ToString();
              }
              return byteString;
          }
  
  
          private static Double ByteArrayToDouble(byte[] bytes, bool readInReverse)
          {
              if (bytes.Length != 8)
                  throw new Exception("bytes must be exactly 8 in Length");
              if (readInReverse)
                  Array.Reverse(bytes);
              return BitConverter.ToDouble(bytes, 0);
          }
      }
  }
  </code></pre>
  
  <p>Can this be done? I'm including an .flv uri from abc News RSS feed to use as an example:
  <a href="http://video-cdn.abcnew.go.com/090713_ann_skinnydip.flv" rel="nofollow noreferrer"><a href="http://video-cdn.abcnew.go.com/090713" rel="nofollow noreferrer">http://video-cdn.abcnew.go.com/090713</a><code>_ann</code>_skinnydip.flv</a>
  Any help would be appreciated.</p>