4

ビデオを提供するために取り組んできたコードに少し問題があります。コードは以下のとおりです。

public ResumingFileStreamResult GetMP4Video(string videoID)
    {
        if (User.Identity.IsAuthenticated)
        {
            string clipLocation = string.Format("{0}\\Completed\\{1}.mp4", ConfigurationManager.AppSettings["VideoLocation"].ToString(), videoID);

            FileStream fs = new FileStream(clipLocation, FileMode.Open, FileAccess.Read);

            ResumingFileStreamResult fsr = new ResumingFileStreamResult(fs, "video/mp4");

            return fsr;
        }
        else
        {
            return null;
        }
    }

これは私のHTMLコードです:

<video controls preload poster="@Url.Content(string.Format("~/Videos/{0}_2.jpg", Model.VideoID))">
    <source src="@Url.Action("GetMP4Video", "Video", new { videoID = Model.VideoID })" type="video/mp4" />
    <source src="@Url.Action("GetWebMVideo", "Video", new { videoID = Model.VideoID })" type="video/webm" />

        <object id="flowplayer" data="@Url.Content("~/Scripts/FlowPlayer/flowplayer-3.2.14.swf")" type="application/x-shockwave-flash" width="640" height="360">
            <param name="movie" value="@Url.Content("~/Scripts/FlowPlayer/flowplayer-3.2.14.swf")" />
            <param name="allowfullscreen" value="true" />
            <param name="flashvars" value="config={'playlist':['@Url.Content(string.Format("~/Videos/{0}_2.jpg", Model.VideoID))',{'url':'@Url.Action("GetMP4Video", "Video", new { videoID = Model.VideoID })','autoPlay':false}]}" />
        </object>
</video>

私の問題は、この設定がデスクトップのすべてのブラウザで正常に機能しているように見えることですが、iPadまたはiPhoneを使用してページを読み込もうとすると、再生できないことを示す線が付いた再生アイコンが表示されます。mp4ビデオのソースをmp4ビデオへの直接リンクに変更してみたところ、すぐにiPadで再生が開始されました。

メソッドをiDeviceと互換性のあるものにするために、見逃してしまった特別なことはありますか?これに関する助けをいただければ幸いです。

4

3 に答える 3

4

iOSデバイスでビデオを再生できるようにするには、バイト範囲(または部分的)要求のサポートを実装する必要があります。これらのタイプのリクエストでは、コンテンツ全体ではなく、チャンクごとに部分的にダウンロードできます(通常のストリーミング)。そして、これがiOSデバイスがページ上のビデオを取得して再生する唯一の方法です。

部分的なリクエストはRangeヘッダーを使用して、サーバーに次のチャンクの位置とサイズを通知します。反対側のサーバーは、206 Partial Contentチャンクの内容を要求して応答します。

インターネットで部分的な要求を処理できるASP.NETハンドラーの実装がいくつかあります。これにはStaticFileHandlerを使用することをお勧めします。インストールが簡単で、すぐに使用できるキャッシュ機能もあります。Nuget経由で配信することもできますが、パッケージの名前はTalifun.Webです。

StaticFileHandlerを構成するには、mp4ファイルのweb.configにハンドラーを登録し、別の構成セクションで構成します。

<configuration>
  <configSections>
    <section name="StaticFileHandler" type="Talifun.Web.StaticFile.Config.StaticFileHandlerSection, Talifun.Web" requirePermission="false" allowDefinition="MachineToApplication"/>
  </configSections>

  <StaticFileHandler webServerType="NotSet">
    <!-- The defaults to use when an extension is found that does not have a specific rule  -->
    <fileExtensionDefault name="Default" serveFromMemory="true" maxMemorySize="100000" compress="true"/>
    <!-- Specific rules for extension types -->
    <fileExtensions>
        <fileExtension name="VideoStaticContent" extension="3gp, 3g2, asf, avi, dv, flv, mov, mp4, mpg, mpeg, wmv" serveFromMemory="true" maxMemorySize="100000" compress="false"/>
    </fileExtensions>
  </StaticFileHandler>

  <system.webServer>
    <handlers>
      <add name="StaticContentHandler" verb="GET,HEAD" path="*.mp4" type="Talifun.Web.StaticFile.StaticFileHandler, Talifun.Web"/>
    </handlers>
  </system.webServer>
</configuration>

StaticFileManagerASP.NETハンドラーを作成して直接呼び出すことにより、承認やカスタムビデオファイルソースなどのカスタムロジックを簡単に適用することもできます。

public class MyOwnVideoHandler : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        // Authorization or any other stuff.
        ...

        // Get file from your storage.
        FileInfo file = ...;

        // Serve the file with StaticFileHandler.
        StaticFileManager.Instance.ProcessRequest(new HttpContextWrapper(context), file);
    }
}

また、詳細の部分的なリクエストに関するScott Mitchellの記事を見て、その作者によって書かれたハンドラーを使用することができます。それは私にとってはうまくいきましたが、キャッシュ機能はありません。

于 2012-08-25T23:56:35.720 に答える
3

@whyleeeは正しいです。StaticFileHandlerがどれほど優れているかについて話すことはできませんが、私自身も同じ問題に直面していて、それが私を夢中にさせていました。これを正しく機能させるには、ヘッダーとヘッダーを含める必要Rangeがあります。たとえば、自分のハンドラーからのコードを使用してコードを少し変更すると、次のようになります(これは.ashxハンドラーを使用していることに注意してください)。RequestResponse

//First, accept Range headers.
context.Response.AddHeader("Accept-Ranges", "bytes")

//Then, read all of the bytes from the file you are requesting.
Dim file_info As New System.IO.FileInfo(clipLocation)
Dim bytearr As Byte() = File.ReadAllBytes(file_info.FullName)

//Then, you will need to check for a range header, and then serve up a 206 Partial Content status code in your response.
Dim startbyte As Integer = 0
If Not context.Request.Headers("Range") Is Nothing Then
    //Get the actual byte range from the range header string, and set the starting byte.
    Dim range As String() = context.Request.Headers("Range").Split(New Char() {"="c, "-"c})
    startbyte = Convert.ToInt64(range(1))

    //Set the status code of the response to 206 (Partial Content) and add a content range header.
    context.Response.StatusCode = 206
    context.Response.AddHeader("Content-Range", String.Format(" bytes {0}-{1}/{2}", startbyte, bytearr.Length - 1, bytearr.Length))
End If

//Finally, write the video file to the output stream, starting from the specified byte position.
context.Response.OutputStream.Write(bytearr, startbyte, bytearr.Length - startbyte)

私が言ったように、これは.ashxハンドラーのコードであるため、状況にどの程度当てはまるかはわかりませんが、お役に立てば幸いです。

于 2012-08-26T07:26:57.743 に答える
3

返信ありがとうございます。提供された情報は非常に役に立ちました。最後に、次のソリューションを使用してバイト範囲要求を実装しました。

于 2012-08-29T21:14:54.083 に答える