【问题标题】:RSS Video Feed Enhancement - Need to get duration on items that dont include it in feedRSS 视频提要增强 - 需要获取提要中不包含它的项目的持续时间
【发布时间】:2009-07-14 19:38:14
【问题描述】:

我有一个可用的 DNLA 设备(Xbox360、PSP...)C# 中的 RSS 视频提要阅读器。它解析 .opml 文件以获取提要 uri。

有时 RSS 提要项没有持续时间值,所以我硬编码一个默认的持续时间值,如果它没有。

我想获取视频文件的真实时长。

我的想法是使用 httpWebRequest 获取字节流并在文件二进制元数据中查找信息(如果可用)。我认为可以做到,但找不到类似的例子。

这个过程一定要快,不需要获取整个视频文件,因为duration值只需要构建菜单。我希望以这种方式处理的文件是 .flv、.m4v 和 .mp4。下面显示的示例适用于 .flv 文件:

using System;
using System.IO;
using System.Text;
using System.Net;

namespace myRSSVideoReader
{
    public static class FlvMetadataReader
    {
        private const int BufferLength = 1000;
        /// <summary>
        /// Reads the meta information (if present) in an FLV
        /// </summary>
        /// <param name="uri">The path to the FLV file</returns>
        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 > 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);
        }
    }
}

这可以吗?我包括一个来自 abc News RSS 提要的 .flv uri,以用作示例: http://video-cdn.abcnew.go.com/090713_ann_skinnydip.flv 任何帮助将不胜感激。

【问题讨论】:

    标签: c# flash httpwebrequest metadata byte


    【解决方案1】:

    您的代码看起来很有希望。困难的部分是为每种预期的文件格式编写解析器。这些文件也很有可能没有您需要的元数据。

    您还可以考虑使用request range 告诉服务器您只需要文件的一部分。只要服务器支持,这应该会加快速度。

    【讨论】:

    • 是的,我正在发现这一点。许多媒体文件没有元数据。所以我在我检查它之前在同一个地方,但是对于那些文件......
    • mp4 获取持续时间的技巧,您需要字节中的最后一个时间戳(第一个时间戳是 0:00:00)。有一些字节移位,但它可以工作并且速度很快。这只是持续时间。说如果你想要高度,宽度,那就是标题。还有带有减号 AddRange(-1024) 的 httpWebRequest,您从文件长度向后 1024 作为起点获取数据:到文件末尾。酷。
    【解决方案2】:

    知道了!至少对于 Flash 文件!在用户代理字符串中也包含了一条给管理员的小消息!

    using System;
    using System.IO;
    using System.Net;
    
    namespace myRSSVideoReader
    {
    public static class FlvMetadataReader
    {
        static string onMetaData = "";
        static string bytesToFile = "";
    
        /// <summary>
        /// Reads the meta information (if present) in an FLV
        /// </summary>
        /// <param name="uri">The uri to the FLV file</returns>
        public static MediaMetadataInfo GetMetadataInfo(string uri)
        {
            //needed for the file name only
            Uri newUri = new Uri(uri);
    
            Stream strm = null;
            StreamReader MyReader = null;
    
            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;
            int range = 800;
    
            try
            {
                //byte[] result;
                byte[] buffer = new byte[range];
                strm = GetURLStream(uri, range);
                if (strm != null)
                {
                    using (MemoryStream fileStream = new MemoryStream())
                    {
                        int count = 0;
                        do
                        {
                            count = strm.Read(buffer, 0, buffer.Length);
                            fileStream.Write(buffer, 0, count);
                        }
                        while (count != 0);
    
                        // read where "onMetaData" in flash, this indicates we've got maetadata
                        byte[] bytes = new byte[1000];
                        fileStream.Seek(27, SeekOrigin.Begin);
                        int result = fileStream.Read(bytes, 0, 1000);
    
                        // if "onMetaData" exists then proceed to read the attributes
                        bytesToFile = ByteArrayToString(bytes);
                        onMetaData = bytesToFile.Substring(0, 10);
                        if (onMetaData == "onMetaData")
                        {
                            hasMetaData = true;
                            duration = GetNextDouble(bytes, bytesToFile.IndexOf("duration") + 9, 8);
                            duration = Math.Round(duration);
    
                            width = GetNextDouble(bytes, bytesToFile.IndexOf("width") + 6, 8);
    
                            height = GetNextDouble(bytes, bytesToFile.IndexOf("height") + 7, 8);
    
                            videoDataRate = GetNextDouble(bytes, bytesToFile.IndexOf("videodatarate") + 14, 8);
    
                            audioDataRate = GetNextDouble(bytes, bytesToFile.IndexOf("audiodatarate") + 14, 8);
    
                            frameRate = GetNextDouble(bytes, bytesToFile.IndexOf("framerate") + 10, 8);
                        }
                        fileStream.Close();
                        fileStream.Dispose();
                    }                    
                }
            }
            catch {}
            finally
            {
                // do some cleanup
                if (MyReader != null)                
                    MyReader.Close();
    
                if (strm != null)                
                    strm.Close();                
            } 
    
            string filename = Path.GetFileName(newUri.AbsoluteUri);
    
            return new MediaMetadataInfo(hasMetaData, filename, duration, width, height, videoDataRate, audioDataRate, frameRate, creationDate);
        }
    
        /* ------------------------------------------------------------- */
    
        private static Stream GetURLStream(string strURL, int range)
        {
            WebRequest req;
            WebResponse res = null;
            Stream respStream;
    
            try
            {
                req = WebRequest.Create(strURL);
                ((HttpWebRequest)req).UserAgent = "myRSSVideoReader/1.0.0.12 (compatible; http://www.myrssvideoreader.com; Your RSS feeds need duration value;)";
                ((HttpWebRequest)req).AddRange(0, range * 2); 
    
                res = req.GetResponse();
                respStream = res.GetResponseStream();
    
                return respStream;
            }
            catch (Exception)
            {
                res.Close();
                return null;
            }
    
        }
    
        /* ------------------------------------------------------------- */
    
        private static Double GetNextDouble(Byte[] b, int offset, int length)
        {
            MemoryStream ms = new MemoryStream(b);
            // 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);
        }
    }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-09-17
      • 2011-05-27
      • 2021-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多