0

C# で動作する DNLA デバイス (Xbox360、PSP...) の RSS ビデオ フィード リーダーがあります。.opml ファイルを解析してフィード URI を取得します。

RSS フィード アイテムには継続時間の値がない場合があるため、デフォルトの継続時間の値をハードコーディングしています。

ビデオファイルの実際の長さを取得したい。

私の考えは、httpWebRequest を使用してバイト ストリームを取得し、利用可能な場合はバイナリ メタデータ ファイル内の情報を探すことです。私はそれができると思っていますが、同様の例は見つかりません。

継続時間の値はメニューを構築するためにのみ必要なため、プロセスは高速である必要があり、ビデオ ファイル全体を取得する必要はありません。この方法で処理する予定のファイルは、.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 助けていただければ幸いです。

4

2 に答える 2

0

あなたのコードは有望に見えます。難しい部分は、予想されるファイル形式ごとにパーサーを作成することです。ファイルに必要なメタデータがない可能性も十分にあります。

リクエスト範囲を使用して、ファイルの一部のみが必要であることをサーバーに伝えることもできます。サーバーがサポートしている限り、速度が向上するはずです。

于 2009-07-15T19:34:10.743 に答える
0

とった!少なくとも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);
    }
}
}
于 2009-07-16T03:45:24.763 に答える