2017-03-28 35 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。感谢您的建议。我会根据你的建议改变它。 :) –

相关问题