I have a long term ongoing problem of sometimes getting black video, with sound in a Three.js texture on mobile and sometimes desktop.
I've been around the houses trying to solve it, and this is what I have so far:
if(!video || video == null){
video = document.createElement( 'video' );
source = document.createElement('source');
video.crossOrigin = "anonymous";
video.preload = 'auto';
video.setAttribute('webkit-playsinline', 'true');
source.setAttribute('type',"video/mp4");
}
if(isIOS() || isIE11())
source.setAttribute('src',"http://" + document.domain + "/cdn/" + sceneObject.video);
else
source.setAttribute('src',cdnPrefix + "/" + sceneObject.video);
video.appendChild(source);
video.load();
(function () {
THREE.noVideoTextureSupport = isIE11();
THREE.VideoTexture = (function () {
var _videoTexture = THREE.VideoTexture;
var _ieVideoTexture = function ( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
if (THREE.noVideoTextureSupport) {
var scope = this;
scope.video = video;
scope.ctx2d = document.createElement('canvas').getContext('2d');
var canvas = scope.ctx2d.canvas;
canvas.width = 2048;
canvas.height = 1024;
scope.ctx2d.drawImage(scope.video, 0, 0, canvas.width, canvas.height);
THREE.Texture.call( scope, scope.ctx2d.canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
scope.generateMipmaps = false;
function update() {
requestAnimationFrame( update );
if ( video.readyState >= video.HAVE_CURRENT_DATA ) {
scope.ctx2d.drawImage(scope.video, 0, 0, canvas.width, canvas.height);
scope.needsUpdate = true;
}
}
update();
}
};
return (THREE.noVideoTextureSupport ? _ieVideoTexture : _videoTexture);
})();
THREE.VideoTexture.prototype = Object.create( THREE.Texture.prototype );
THREE.VideoTexture.prototype.constructor = THREE.VideoTexture;
})();
if(!isMobile)
panoVideoPlay();
else if(!firstPlay)
panoVideoPlay();
else{
$('body').append('<div id="play-button" class="playButton"><i class="fa fa-play"></i></div>');
$('#preloaderItems').remove();
window.addEventListener('touchstart', function videoStart() {
panoVideoPlay();
$("body").scrollTop(1);
$('#preloader').remove();
if(firstPlay){
$("#play-button").remove();
firstPlay = false;
showLoader();
}
this.removeEventListener('touchstart', videoStart);
});
}
}
function panoVideoPlay(){
makeVideoPlayableInline(video);
video.play();
checkPlayBack();
}
var checkPlayBack = function(event){
console.log("panoVideo.checkPlayBack()");
var panoPlayBackInterval = setInterval(function(){
if (video.currentTime > 0 || video.readyState > 0){
clearInterval(panoPlayBackInterval);
hideLoader();
showVideo(video);
}
},10);
}
function showVideo(video){
console.log("panoVideo.showVideo()");
geometry = new THREE.SphereGeometry( 500, 60, 40 );
texture = new THREE.VideoTexture( video );
texture.minFilter = THREE.LinearFilter;
texture.magFilter = THREE.LinearFilter;
texture.format = THREE.RGBFormat;
material = new THREE.MeshBasicMaterial( { map : texture } );
panoVideoMesh = new THREE.Mesh( geometry, material );
panoVideoMesh.scale.x = -1;
panoVideoMesh.rotation.y = Math.PI / 2;
loadScene();
scene.remove(box);
scene.add(panoVideoMesh);
addLights();
}
The video is encoded as such in FFMPEG
out.mp4 -vcodec libx264 -profile:v baseline -preset slow -pix_fmt yuv420p -b:v 5000k -maxrate 5000k -bufsize 2200k -s 1920:1080 -threads 0 -b:a 128k -movflags faststart out2K.mp4
As you can see, I've run into countless problems on IE and iOS, so I've done a nasty hack on IE which I found on the Three.js forums, and for iOS and IE I proxy the files through the server from the CDN to get around the countless security issues I was facing.
Chrome is usually fine (but I've had reports of Black screen with sound on Chrome on Android on a Samsung S5), however on the Android Note 3 I have here I'm having the same issue in the Android Stock Browser.
Usually when it goes wrong there is a usually an unidentified Script error on every render. Hard to debug on iOS and Android Stock Browser without Chrome:inspect!
On the Android stock browser if I use the CDN I get black video, sound and lots of errors - if I use the proxy files I get black screen and nothing loading..
I'm using Amazon EC2 as the Server and CloudFront for distribution, where I've had cross domain issues I've had to resort to a Apache Proxy to serve the files via the EC2 server.
I've done everything I can think of to get Cross Domain to work,
S3 has the following CORS configuration
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>https://*</AllowedOrigin>
<AllowedOrigin>http://*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>HEAD</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>Authorization</AllowedHeader>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
CloudFront has the forward headers behaviours set with Origin, Access Control Headers & Method etc.
I've set Mod_Headers on the server .htaccess
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "http://cdn.example.com"
</IfModule>
When I CURL the files from the host it seems OK
i.e.
curl -I -H "Origin: http://example.com" http://cdn.example.com/videofile.mp4
HTTP/1.1 200 OK
Content-Type: video/mp4
Content-Length: 38150681
Connection: keep-alive
Date: Wed, 21 Sep 2016 20:55:25 GMT
Access-Control-Allow-Origin: http://example.com
Access-Control-Allow-Methods: GET, HEAD
Access-Control-Max-Age: 3000
Access-Control-Allow-Credentials: true
Last-Modified: Fri, 08 Jul 2016 02:45:32 GMT
ETag: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
x-amz-meta-md5-hash: XXXXXXXXXXXXXXXXXXXXXXXXXX
Accept-Ranges: bytes
Server: AmazonS3
Vary: Origin
Age: 1094
X-Cache: Hit from cloudfront
Via: 1.1 XXXXXXXXXXXXXXXXXXXXXX.cloudfront.net (CloudFront)
X-Amz-Cf-Id: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
But when I try the other way
curl -I -H "Origin: http://cdn.example.com/videoFile.mp4" http://example.com/file/from/java/server
I get
HTTP/1.1 405 Request method 'HEAD' not supported
Date: Wed, 21 Sep 2016 21:15:05 GMT
Server: Jetty(8.0.4.v20111024)
Access-Control-Allow-Origin: http://cdn.example.com
Access-Control-Allow-Credentials: true
Allow: GET
Content-Type: text/html;charset=ISO-8859-1
Cache-Control: must-revalidate,no-cache,no-store
Content-Length: 1431
Vary: User-Agent,Accept-Encoding
Connection: close
I'm not sure if that Request method 'HEAD' not supported is going to be an issue.
I've spent A LOT of time on this, and I seem to be getting somewhere but just now can't see what to try next.
If anyone can help me I'd super appreciate it!
Adding crossorigin="anonymous" to the video element worked for me.
For example:
<video src="https://video.url" loop muted playsinline crossorigin="anonymous" />
Related
Everything seems to be working as I do not get any error but I get garbage code instead of the image itself. The code is very simple in the controller:
// get image & resize
$img = ImgMgr::make('http://pathToImage.jpg')->resize(200,100);
// send HTTP header and output image data
echo $img->response('jpg', 70);
Then I get : HTTP/1.0 200 OK Cache-Control: no-cache, private Content-Length: 2900 Content-Type: image/jpeg Date: Wed, 21 Jul 2021 16:05:21 GMT ����JFIF``��;CREATOR: gd-jpeg v1.0 (using IJG JPEG v90), quality = 70 ��C #%$""!&+7/&)4)!"0A149;>>>%.DIC;��C ;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;��dd"��
What am I missing?
Here is the solution...
$img = ImgMgr::make('http://pathToImage.jpg')->resize(200,100);
$img->response('jpg', 70);
$type = 'png';
$base64 = 'data:image/' . $type . ';base64,' . base64_encode($img);
<img src="{!! $base64 !!}">
I'm working on an API that would return an image. In case any error is encountered in the API, though I can issue a HTTP - 500 response (or similar error codes) with text content or no content at all, I need to be able to return an Image Content with the error represented inside the image itself. In other words, when any error is encountered, I create an image representation of the error text and return the image, with the http status code at as 500 - Internal Server Error. I'm using ASP.net Web API and I'm able to create a HTTP 500 Response with Image content and mime type as "image/jpg".
Http 500 with plain text response:
HTTP/1.1 500 Internal Server Error
Content-Length: 14
Content-Type: text/plain; charset=utf-8
Server: Microsoft-HTTPAPI/2.0
Date: Mon, 24 Jul 2017 06:43:55 GMT
Error Occured!
Http 500 with Image Content:
HTTP/1.1 500 Internal Server Error
Content-Length: 622485
Content-Type: image/jpg
Server: Microsoft-HTTPAPI/2.0
Date: Mon, 24 Jul 2017 06:44:56 GMT
<<ImageContent>>
Though it is possible, I need to know if this approach is OK as per the best practices of web API or not. Thanks.
Best-practice ("everybody does it") is to return HTML, with a Content-Type: text/html, even if the request was for an image.
You can refer to this site here
Below you can take look at piece of code from shared link:
var result = new HttpResponseMessage(HttpStatusCode.OK);
String filePath = HostingEnvironment.MapPath("~/Images/HT.jpg");
FileStream fileStream = new FileStream(filePath, FileMode.Open);
Image image = Image.FromStream(fileStream);
MemoryStream memoryStream = new MemoryStream();
image.Save(memoryStream, ImageFormat.Jpeg);
result.Content = new ByteArrayContent(memoryStream.ToArray());
result.Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
return result;
I use Laravel 5.1.
A jQuery ajax call is made like that:
$('#export_selected').click(function(){
var checked = $('.select_rows:checked');
var ids = [];
$.each(checked, function(index, value){
ids.push(value.id);
})
$.ajax({
method : "POST",
url : "{{URL::to('/spot/exportTable')}}",
data : {ids:ids}
});
});
And then the php method is defined that way:
public function exportTable(Request $req) {
$spots = array_flatten($req->all());
$res = Spot::whereIn('id', $spots)->get();
Excel::create('Spots', function($excel) use($res) {
$excel->setTitle('Title goes here');
$excel->setCreator('Creator Goes Here')->setCompany('Company Goes Here');
$excel->sheet('Excel sheet', function($sheet) use($res) {
$sheet->setOrientation('landscape');
$sheet->fromArray($res);
});
})->store('csv', storage_path('/exports', true));
$file = base_path() . '/storage/exports/Spots.csv';
$headers = ['Content-Type: application/csv', 'Content Description: File Transfer', 'Cache-Control: must-revalidate, post-check=0, pre-check=0'];
return response()->download($file, 'Spots.csv' , $headers);
}
Chrome developer console prints the results as raw lines.
The file is successfully exported and created in the disk.
The path to file is correct.
But the download is never started.
Echoing the response gives:
HTTP/1.0 200 OK
0: Content-Type: application/csv
Cache-Control: public
Content-Disposition: attachment; filename="Spots.csv"
Date: Mon, 26 Oct 2015 16:08:26 GMT
Last-Modified: Mon, 26 Oct 2015 16:08:26 GMT
1: Content-Description: File Transfer
2: Cache-Control: must-revalidate, post-check=0, pre-check=0
I put the answer here for everybody having the same issue.
#manix figured it out: I'm trying to download via Ajax, which needs to be done in another way, not the way I wrote my code
I'm trying to connect to Parse.com 's REST-API via NSURLConnection to track AppOpened metadata.
I get 200 OK back from the API and the headers are the same to the cURL headers but my API calls are not being represented in the data browser on Parse.com . Is NSURLConnection doing something silly I don't know of? API response is the same but one request gets represented while the other one isn't.
NSLog output:
<NSHTTPURLResponse: 0x7ff5eb331ca0> { URL: https://api.parse.com/1/events/AppOpened } { status code: 200, headers {
"Access-Control-Allow-Methods" = "*";
"Access-Control-Allow-Origin" = "*";
Connection = "keep-alive";
"Content-Length" = 3;
"Content-Type" = "application/json; charset=utf-8";
Date = "Sun, 04 Jan 2015 22:42:54 GMT";
Server = "nginx/1.6.0";
"X-Parse-Platform" = G1;
"X-Runtime" = "0.019842";
} }
cURL output:
HTTP/1.1 200 OK
Access-Control-Allow-Methods: *
Access-Control-Allow-Origin: *
Content-Type: application/json; charset=utf-8
Date: Sun, 04 Jan 2015 23:03:51 GMT
Server: nginx/1.6.0
X-Parse-Platform: G1
X-Runtime: 0.012325
Content-Length: 3
Connection: keep-alive
{}
It's the same output. What am I doing wrong? Has anyone experience with this?
Turns out Parse was showing funny API keys the moment I copied them out of the cURL example they provide in their lovely docs. Don't know whose analytics I screwed over but I'm terribly sorry and it wasn't my fault!
Always copy your API keys out of [Your-Parse-App-Name]->Settings->Keys
It probably was just a stupid glitch that happened on the Server.
I need the server-time for "user-is-online" stats in my CouchApp. I work with jquery.couch.js and would prefer to have a url, e.g. /db/_design/app/time - which gets me a timestamp.
How do I realize this?
A show function could do that:
function(doc, req) {
// _design/myapp/_show/now
// First version possibly incompatible with some spidermonkey versions.
//var now = new Date();
var now = new Date().getTime();
var output = JSON.parse(JSON.stringify(now)) + "\n";
return { code: 200
, headers: { "Content-Type": "text/plain"
}
, body:output
};
}
The server also includes a Date header that you might want to use.
$ curl -D- http://localhost:5984
HTTP/1.1 200 OK
Server: CouchDB/1.1.0 (Erlang OTP/R14B)
Date: Fri, 27 May 2011 00:28:31 GMT
Content-Type: text/plain;charset=utf-8
Content-Length: 40
Cache-Control: must-revalidate
{"couchdb":"Welcome","version":"1.1.0"}