ios - Serve mp4 file through coldfusion and play with jwplayer -
i have web application in coldfusion record videos , serve videos user.
the video working fine on android , desktop browsers giving me error "error loading media: file not played" in ios.
here jwplayer code working.
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 } });
here video.cfm server mp4 after verification.
<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">
i have tried solution adding header. doesn't work. can me sort out problem.
i able resolve problem. ios uses partial content header run videos. rickward lovely solution: media delivery iphones , ipads. have made little changes , started working me.
here final video.cfm file.
<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 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> <!--- we've gotten far without errors send accept range header /* @ moment support single ranges. * multiple ranges requires more work ensure works correctly * , comply spesifications: http://www.w3.org/protocols/rfc2616/rfc2616-sec19.html#sec19.2 * * multirange support annouces with: * header('accept-ranges: bytes'); * * multirange content must sent multipart/byteranges mediatype, * (mediatype = mimetype) * boundry header indicate 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 range string ---> <cfset l.range = listgetat(l.request.headers.range, 2, '=')> <!--- make sure client hasn't sent multibyte range ---> <cflog file="rangedownload" text="#l.range#" /> <cfif l.range contains ','> <!--- (?) should issued here, or should first range used? or should header ignored , output whole content? ---> <cfheader statuscode = "416" statustext = "requested range not satisfiable"> <cfheader name="content-range" value="bytes #l.start#-#l.end#/#l.size#"> <!--- (?) echo info client? ---> <cfabort> </cfif> <!--- if range starts '-' start beginning if not, forward file pointer , make sure end byte if specified ---> <cfif left(l.range, 1) eq '-'> <!--- n-number of last bytes 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 , val(l.rangearray[2]) gt 0> <cfset l.c_end = l.rangearray[2]> <cfelse> <cfset l.c_end = l.size> </cfif> </cfif> <!--- /* check range , make sure it's treated according specs. * http://www.w3.org/protocols/rfc2616/rfc2616-sec14.html */ // end bytes can not larger l.end. ---> <cfif l.c_end gt l.end> <cfset l.c_end = l.end> </cfif> <!--- validate requested range , return 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 info 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 client byte range we'll 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 portion requested out.write(l.thedata, javacast('int', l.start), javacast('int', l.length)); out.flush(); out.close(); </cfscript> </cffunction>
Comments
Post a Comment