2017-03-28 39 views
1

我在Coldfusion中有一個Web應用程序,它可以記錄視頻並向用戶提供視頻。通過Coldfusion服務mp4文件並使用jwplayer播放

該視頻在Android和桌面瀏覽器上正常工作,但它給我錯誤「IOS加載媒體:文件無法播放時出錯」錯誤。

這是我目前正在使用的JWPlayer代碼。

jwplayer("element").setup({ 
    file: "/video.cfm?token=4514_129_9B2F727D-5056-A85D-6EBE3E48FC2AB9C6", 
    image: "path/to/image", 
    width: 450, 
    height: 360, 
    type: "mp4", 
    logo: { 
    file: 'path/to/logo', 
    link: 'example.com', 
    hide : true 
    } 
}); 

這是我video.cfm覈實後服務器MP4。

<cfset videoFile = 'path\to\file'> 
<cfset fileInfo = GetFileInfo(videoFile)> 
<cfset length = fileInfo.size> 
<cfset start = 0> 
<cfset end = fileInfo.size - 1> 
<cfheader name="Content-type" value="video/mp4"> 
<cfheader name="Accept-Ranges" value="0-#length#"> 
<cfheader name="Content-Range" value="bytes #start#-#end#/#fileInfo.size#"> 
<cfheader name="Content-Length" value="#length#"> 
<cfcontent file="#videoFile#" type="video/mp4"> 

我嘗試了一些解決方案,通過添加一些標題。但那不行。任何人都可以幫我解決這個問題。

+0

如果您讓我們訪問該網站(至少是前端),我們可以幫助診斷它。我已經與CF,視頻和jwplayer一起交付了項目。 – Jules

+0

遠離你自己的應用程序,文件是否可以在你的iOS設備上播放?我的意思是確保文件數據本身可用於iOS回放。將一個文件從服務器保存到存儲並嘗試在某些媒體播放器應用中播放......會發生什麼情況?在不同的(規格/功率)iOS設備上測試過相同的文件? –

+0

@ VC.One。我在https://jwplayer-techy.fwd.wf/上添加了不同的演示。只有一個在IOS上工作的文件是通過hlshtml:true。你有沒有想法,我該如何使用這個參數從文件中運行mp4? –

回答

2

我能解決我的問題。 iOS使用部分內容標題來運行視頻。感謝這個可愛的解決方案rickward:Media Delivery to iPhones and iPads。我做了一些小改動,並開始爲我工作。

這裏是最終的video.cfm文件。

<cfset videoPath = 'path\to\mp4\file'> 
<cfif FileExists(videoPath)> 
    <cfset fileInfoVar = GetFileInfo(videoPath)> 
    <cfheader name="Last-Modified" value="#fileInfoVar.Lastmodified#"> 
    <cfheader name="ETag" value="#hash(videoPath, 'MD5')#"> 
    <cfheader name="Content-Location" value="http://example.com/video.cfm"> 

    <cfif structKeyExists(GetHttpRequestData().headers, 'Range')> 
     <cfset rangeDownload(videoPath)> 
    <cfelse> 
     <cffile action="readbinary" file="#videoPath#" variable="theData"> 
     <cfscript> 
      context = getPageContext(); 
      context.setFlushOutput(false); 
      response = context.getResponse().getResponse(); 
      response.setContentType("video/mp4"); 
      response.setContentLength(arrayLen(theData)); 

      out = response.getOutputStream(); 
      out.write(theData); 
      out.flush(); 
      out.close(); 
     </cfscript> 
    </cfif> 
</cfif> 

<cffunction name="rangeDownload" returnType="void" output="yes"> 
    <cfargument name="file" type="string" required="true" hint="path to file"> 

    <cfset var l = {}> 
    <cfset l.request = GetHttpRequestData()> 

    <cffile action="readbinary" file="#ARGUMENTS.file#" variable="l.theData"> 

    <cfset l.size = arrayLen(l.theData)> 
    <cfset l.length = l.size> 
    <cfset l.start = 0> 
    <cfset l.end = l.size - 1> 

    <!--- Now that we've gotten so far without errors we send the accept range header 
    /* At the moment we only support single ranges. 
    * Multiple ranges requires some more work to ensure it works correctly 
    * and comply with the spesifications: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2 
    * 
    * Multirange support annouces itself with: 
    * header('Accept-Ranges: bytes'); 
    * 
    * Multirange content must be sent with multipart/byteranges mediatype, 
    * (mediatype = mimetype) 
    * as well as a boundry header to indicate the various chunks of data. 
    */ 
    ---> 
    <cfheader name="Accept-Ranges" value="0-#l.length#"> 
    <!---<cfheader name="Accept-Ranges" value="bytes"> ---> 
    <!--- 
     multipart/byteranges 
     http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2 ---> 
    <cfif structKeyExists(l.request.headers, 'Range')> 

     <cfset l.c_start = l.start> 
     <cfset l.c_end = l.end> 

     <!--- Extract the range string ---> 
     <cfset l.range = ListGetAt(l.request.headers.range, 2, '=')> 
     <!--- Make sure the client hasn't sent us a multibyte range ---> 
     <cflog file="rangeDownload" text="#l.range#" /> 
     <cfif l.range contains ','> 
      <!--- (?) Should this be issued here, or should the first 
      range be used? Or should the header be ignored and 
      we output the whole content? 
      ---> 
      <cfheader statusCode = "416" statusText = "Requested Range Not Satisfiable"> 
      <cfheader name="Content-Range" value="bytes #l.start#-#l.end#/#l.size#"> 
      <!--- (?) Echo some info to the client? ---> 
      <cfabort> 
     </cfif> 
     <!--- If the range starts with an '-' we start from the beginning 
      If not, we forward the file pointer 
      And make sure to get the end byte if specified ---> 
     <cfif Left(l.range, 1) eq '-'> 
     <!--- The n-number of the last bytes is requested ---> 
      <cfset l.c_start = l.size - Mid(l.range, 2, Len(l.range))> 
     <cfelse> 
      <cfset l.rangeArray = ListToArray(l.range, '-')> 
      <cfset l.c_start = l.rangeArray[1]> 
      <cfif ArrayLen(l.rangeArray) eq 2 and val(l.rangeArray[2]) gt 0> 
       <cfset l.c_end = l.rangeArray[2]> 
      <cfelse> 
       <cfset l.c_end = l.size> 
      </cfif> 
     </cfif> 
     <!--- 
     /* Check the range and make sure it's treated according to the specs. 
     * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html 
     */ 
     // End bytes can not be larger than l.end. ---> 
     <cfif l.c_end gt l.end> 
      <cfset l.c_end = l.end> 
     </cfif> 

     <!--- Validate the requested range and return an error if it's not correct. ---> 
     <cfif l.c_start gt l.c_end || l.c_start gt (l.size - 1) || l.c_end gte l.size> 
      <cfheader statusCode = "416" statusText = "Requested Range Not Satisfiable"> 
      <cfheader name="Content-Range" value="bytes #l.start#-#l.end#/#l.size#"> 
      <!--- (?) Echo some info to the client? ---> 
      <cfabort> 
     </cfif> 

     <cfset l.start = l.c_start> 
     <cfset l.end = l.c_end> 
     <cfset l.length = l.end - l.start + 1><!--- Calculate new content length ---> 


     <cfscript> 
      context = getPageContext(); 
      context.setFlushOutput(false); 
      response = context.getResponse().getResponse(); 
      response.setContentType("video/mp4"); 
      response.setContentLength(l.length); 
     </cfscript> 
     <cfheader statusCode = "206" statusText = "Partial Content"> 

    </cfif> 

    <!--- Notify the client the byte range we'll be outputting ---> 
    <cfheader name="Content-Range" value="bytes #l.start#-#l.end#/#l.size#"> 
    <cfheader name="Content-Length" value="#l.length#"> 

    <cfscript> 
     // Start buffered download 
     out = response.getOutputStream(); 
     // write the portion requested 
     out.write(l.theData, javacast('int', l.start), javacast('int', l.length)); 
     out.flush(); 
     out.close(); 
    </cfscript> 
</cffunction> 
+0

很高興你知道了。小建議,你可能簡化了第一個'',並使用''。另外,不要忘記'var/local'作用域中函數中的所有變量,包括'context,response,out'等等。 – Leigh

+0

@Leigh。感謝您的建議。我會根據你的建議改變它。 :) –

相關問題