On our platform (based on Laravel 5.1) we provide audio and video content to registered users. The media files are stored outside the docroot of course.
So I use a method to provide the requested content. That works well on any browser and OS except Android (native or chrome). Android uses a byte range request for audio and video tags. The following code worked in the beginning and stopped working a while ago. I have no clue why. Any:
public function loadfile(Request $request, $type, $filename="")
{
$filepath = $mediadirectory . $filename;
if (File::isFile($filepath)) {
$file = File::get($filepath);
$mimetype = File::mimeType($filepath);
$size = File::size($filepath);
if ($mimetype=="audio/mpeg" || $mimetype=="video/mp4") {
$stream = fopen($filepath, "r");
$start = 0;
$length = $size;
$status = 200;
$headers = ['Content-Type' => $mimetype, 'Content-Length' => $size, 'Accept-Ranges' => 'bytes'];
if (false !== $range = $request->server('HTTP_RANGE', false)) {
list($param, $range) = explode('=', $range);
if (strtolower(trim($param)) !== 'bytes') {
header('HTTP/1.1 400 Invalid Request');
exit;
}
list($from, $to) = explode('-', $range);
if ($from === '') {
$end = $size - 1;
$start = $end - intval($from);
} elseif ($to === '') {
$start = intval($from);
$end = $size - 1;
} else {
$start = intval($from);
$end = intval($to);
}
$length = $end - $start + 1;
$status = 206;
$headers['Content-Range'] = sprintf('bytes %d-%d/%d', $start, $end, $size);
$headers['Connection'] = "keep-alive";
}
$response=new StreamedResponse(function() use ($stream, $start, $length) {
fseek($stream, $start, SEEK_SET);
echo fread($stream, $length);
fclose($stream);
}, $status, $headers);
return $response->send();
} else {
return response($file, 200)->header('Content-Type', $mimetype)->header('Content-Length', $size)->header('Content-Disposition', 'filename="' . $filename . '"');
}
}
}
The html is straight forward html5:
<audio controls preload="auto">
<source src="/loadfile/principiante.mp3" type="audio/mpeg">
</audio>
Related
I'm trying to create android application using Kohana API (kohana 3.1) (with module kohana-restful-api).
And I have problem with making session stay at application (No cookies in apk). I have wrote this controller which I think is a problem:
class Controller_Restapi_Login extends Controller_Restapi_Default{
public function action_create(){
// Jeżeli przesłano dane z formularza
$post = $this->request->post();
if(!empty($post))
{
// zapisanie informacji do ciastka, użytkownik będzie zalgowany nawet po wyłączeniu i ponownym włączeniu przeglądarki
if( Auth::instance()->login($this->request->post('adm_login'), $this->request->post('adm_haslo')) )
{
// Logowanie zdarzenia
$objWiLog = ORM::factory('Orm_WiaLogi');
$objWiLog->log_akcjaID = 2;
$objWiLog->save();
$sessionID = Auth::instance()->get_user()->adm_id;
$wiadomosc = $sessionID;
$this->response->body(json_encode($wiadomosc));
}
else
{
try {
// Logowanie zdarzenia (nieudane logowanie)
$objWiLog = ORM::factory('Orm_WiaLogi');
$objWiLog->log_akcjaID = 4;
$objWiLog->log_adminID = ORM::factory('Orm_WiaAdministratorzy')->where('adm_login', '=', $this->request->post('adm_login'))->find()->adm_id;
$objWiLog->log_opis = 'Próba logowania przy użyciu loginu: '.$this->request->post('adm_login');
$objWiLog->save();
}
catch(ORM_Validation_Exception $e) {
//
}
catch(Database_Exception $e) {
// Nieprawidłowy login
}
$arrRespons = array(
'id'=> 1,
'type'=>'e',
'message' => 'Nieprawidłowy login lub hasło ',
'action'=>'gotoLogin',
);
$this->response->body(json_encode($arrRespons));
}
} else {
$this->response->body(json_encode('Błąd Logowania - Brak Loginu'));
}
}
}
Sorry for bad english, I hope someone understands.
my project is normal in web browser, HTML5 version is work.
But after compile to apk by command 'cocos run -p android', socket.io is useless server side cannot receive any information.
I know something is improper, but I cannot find a concrete solution. Please help me.THANKS
server.js as follow:
var io = require('socket.io').listen(3000);
console.log('Server on port 3000.');
var player = new Array();
var player_data = {
name: "",
kill: 0,
dead: 0
}
io.sockets.on('connection', function (socket){
console.log("come in");
socket.on('join_success', function (name){
console.log("name is"+name);
player_data.name=name;
player.push(player_data);
io.sockets.emit("updateAllPlayerData", player);
});
});
app.js as follow
var basicLayer = cc.Layer.extend({
ctor: function(){
this._super();
var size = cc.director.getWinSize();
var ball = new cc.Sprite(res.png1);
ball.x = 100;
ball.y = 100;
var ui = new GameUI;
sio_client= SocketIO.connect("http://localhost:3000");
sio_client.on("updateAllPlayerData", function(data){
alert(data);
playerNum = data.length;
for(var i=0; i<data.length; i++){
playerName.push(data[i].name);
killNum.push(data[i].kill);
deadNum.push(data[i].dead);
}
ui.updateInfo();
});
sio_client.on("connect",function(){
console.log("connect_success ");
var name=prompt("input your name","");
while(name==null || name==""){
name=prompt("input your name","");
}
sio_client.emit("join_success", name);
});
this.addChild(ball, 10, 100);
this.addChild(ui,2);
return true;
}
});
I am making api's for my android app using Slim framework.But when i upload video to local server from my android app by calling api,it generates white thumbnail for video in my app.How can i get the thumbnail for the uploaded video.
My code for making api is:
$app->post('/do_upload', 'authentication', function () use ($app) {
verifyRequiredParams(array('albumId'));
global $user_id;
$response = array();
$file_path = "../uploads/$user_id/photo_gallery/thumbnails/";
if (!file_exists($file_path)) {
mkdir($file_path, 0777, true);
}
$thumbnail = $user_id . "/photo_gallery/thumbnails/";
$response = array();
if (isset($_FILES["files"])) {
$temp = explode(".", $_FILES['files']['name']);
$detectedType = $_FILES["files"]["name"];
$filetype = substr($detectedType, strpos($detectedType, ".") + 1);
$newfilename = 'shared_' . rand(1, 99999) . '.' . end($temp);
$file_path = $file_path . basename($newfilename);
$thumbnail = "$user_id/photo_gallery/thumbnails/" . $newfilename;
$filename = "$user_id/photo_gallery/thumbnails/" . $newfilename;
$mobile_thumbnail = "$user_id/photo_gallery/thumbnails/" . $newfilename;
if (move_uploaded_file($_FILES['files']['tmp_name'], $file_path)) {
}
$albumId = urldecode($app->request->post('albumId'));
$caption = urldecode($app->request->post('caption'));
$db = new DbHandler();
if (($filetype == "gif")
|| ($filetype == "png")
|| ($filetype == "jpeg")
|| ($filetype == "jpg")
|| ($filetype == "JPEG")
|| ($filetype == "PNG")
|| ($filetype == "GIF")
|| ($filetype == "JPG")
) {
$type = "image";
$result = $db->SharedImage($albumId, $user_id, $caption, $filename, $thumbnail, $mobile_thumbnail, $type);
} else {
$type = "video";
$result = $db->SharedImage($albumId, $user_id, $caption, $filename, $thumbnail, $mobile_thumbnail, $type);
}
if ($result != "null") {
while ($res = $result->fetch_assoc()) {
$response = array();
$response["id"] = $res["id"];
$response["event_id"] = $res["event_id"];
$response["album_id"] = $res["album_id"];
$response["status"] = $res["status"];
$response["filename"] = $res["filename"];
$response["contributedby_id"] = $res["contributedby_id"];
$response["guest_id"] = $res["guest_id"];
$response["thumbnail"] = $res["thumbnail"];
$response["mobile_thumbnail"] = $res["mobile_thumbnail"];
$response["order_id"] = $res["order_id"];
$response["created"] = $res["created"];
$response["updated"] = $res["updated"];
$response["title"] = $res["title"];
$response["type"] = $res["type"];
$response["caption"] = $res["caption"];
$response["taken"] = $res["taken"];
$response["copied_from"] = $res["copied_from"];
$response["media_size"] = $res["media_size"];
$response["thumbnail_size"] = $res["thumbnail_size"];
echoRespnse(200, $response);
}
} else {
$response["message"] = "response contain no data";
echoRespnse(200, $response["message"]);
}
} else {
$response ["error"] = true;
$response ["message"] = "Please select a file to upload";
echoRespnse(200, $response);
}
});
Please tell me why the thumbnail of video uploded is white and how can i get the video cover.
Using ffmpeg ,My problem was solved.Here is the code exec('ffmpeg -y -i '.$file_path.' -vcodec mjpeg -ss 00:00:01 -vframes 1 -an -s 620x440 -f rawvideo '.$image.'',$thumb_stdout, $retval);
This created a thumbnail at path $image of size 620*440.
I'm trying to play multi-language audio tracks on chromecast. It plays the video/audio files but it does not switch from English to Spanish. I can switch using the same file in a silverlight player. I've set my chromecast player language and my android phone language to be spanish. In the Google Cast SDK Developer console, I added spanish as an alternate track.
I've added my custom player using the code specified in the google guides, however the code in the guides does not appear to work from a straight copy and paste. Can someone direct me as to why protocol.getStreamCount() is 0? Is the timing of the call correct? Here's the entire player that I'm using, pay particular attention to window.changeLanguage = function()... and the changeLanguage call. Any help is extremely appreciated!
<html>
<head>
<title>Test Player</title>
<script type="text/javascript" src="//www.gstatic.com/cast/sdk/libs/receiver/2.0.0/cast_receiver.js"></script>
<script type="text/javascript" src="//www.gstatic.com/cast/sdk/libs/mediaplayer/1.0.0/media_player.js"></script>
<link rel="stylesheet" type="text/css" href="chromecast.css" />
</head>
<body>
<video id='vid' />
<script type="text/javascript">
if (window.location.href.indexOf('Debug=true') != -1) {
cast.receiver.logger.setLevelValue(cast.receiver.LoggerLevel.DEBUG);
cast.player.api.setLoggerLevel(cast.player.api.LoggerLevel.DEBUG);
}
var mediaElement = document.getElementById('vid');
var protocol = null;
// Create the media manager. This will handle all media messages by default.
window.mediaManager = new cast.receiver.MediaManager(mediaElement);
window.defaultOnLoad = mediaManager.onLoad;
mediaManager.onLoad = function (event) {
if (window.player !== null) {
player.unload(); // Must unload before starting again.
window.player = null;
}
if (event.data['media'] && event.data['media']['contentId']) {
console.log('Starting media application');
var url = event.data['media']['contentId'];
window.host = new cast.player.api.Host({'mediaElement':mediaElement, 'url':url});
var ext = url.substring(url.lastIndexOf('.'), url.length);
var initStart = event.data['media']['currentTime'] || 0;
var autoplay = event.data['autoplay'] || true;
mediaElement.autoplay = autoplay; // Make sure autoplay get's set
if (url.lastIndexOf('.m3u8') >= 0)
{
// HTTP Live Streaming
protocol = cast.player.api.CreateHlsStreamingProtocol(host);
}
else if (url.lastIndexOf('.mpd') >= 0)
{
// MPEG-DASH
protocol = cast.player.api.CreateDashStreamingProtocol(host);
}
else if (url.indexOf('.ism/') >= 0)
{
// Smooth Streaming
protocol = cast.player.api.CreateSmoothStreamingProtocol(host);
}
// How to override a method in Host. I know that it's safe to just provide this
// method.
host.onError = function(errorCode) {
console.log("Fatal Error - " + errorCode);
if (window.player) {
window.player.unload();
window.player = null;
}
};
console.log("we have protocol " + ext);
if (protocol !== null) {
console.log("Starting Media Player Library");
window.player = new cast.player.api.Player(host);
window.player.load(protocol, initStart);
changeLanguage();
}
else {
window.defaultOnLoad(event); // do the default process
}
}
}
window.changeLanguage = function() {
var currentLanguage = null;
var streamCount = protocol.getStreamCount();
console.log("streamCount: " + streamCount);
var streamInfo;
for (var i = 0; i < streamCount; i++) {
console.log("isStreamEnabled " + i + "? " + protocol.isStreamEnabled(i));
if (protocol.isStreamEnabled(i)) {
streamInfo = protocol.getStreamInfo(i);
console.log("streamInfo isAudio? " + streamInfo.mimeType.indexOf('audio'));
if (streamInfo.mimeType.indexOf('audio') === 0) {
if (streamInfo.language) {
console.log("streamInfo.language: " + streamInfo.language);
currentLanguage = i;
break;
}
}
}
}
if (currentLanguage === null) {
currentLanguage = 0;
}
i = currentLanguage + 1;
console.log("i: " + i);
console.log("currentLanguage: " + currentLanguage);
while (i !== currentLanguage) {
if (i === streamCount) {
console.log("resetting i to 0");
i = 0;
}
streamInfo = protocol.getStreamInfo(i);
if (streamInfo.mimeType.indexOf('audio') === 0) {
protocol.enableStream(i, true);
protocol.enableStream(currentLanguage, false);
console.log("Enabling: " + i);
console.log("Disabling: " + currentLanguage);
break;
}
i++;
}
if (i !== currentLanguage) {
console.log("reloading window player" + window.player);
window.player.reload();
}
};
window.player = null;
console.log('Application is ready, starting system');
window.castReceiverManager = cast.receiver.CastReceiverManager.getInstance();
castReceiverManager.start();
</script>
</body>
</html>
Chromecast Console:
Application is ready, starting system
Starting media application
we have protocol .ism/manifest
Starting Media Player Library
streamCount: 0
i: 1
currentLanguage: 0
EDIT
I went into console and post loading called the following command:
this.protocol.getStreamCount()
2
So this is clearly a timing issue. I need to call changeLanguage once the stream has fully loaded. I'm investigating when the appropriate time to call it is. I'd appreciate any help but I'll try to google this answer now that I'm positive it's a timing issue.
Answer is:
host.onManifestReady = function() {
changeLanguage();
};
This will provide the correct timing for when to pull the alternate audio tracks.
var style1 = document.createElement("link");
style1.id = "rel";
style1.rel = "stylesheet";
style1.href = "http://www.mysite.com/css.css";
style1.onload = function(){document.body.innerHTML+="fffffff";};
document.getElementsByTagName("head")[0].appendChild(style1);
This code works in Chrome/Firefox, and yet stock browsers on my Froyo (2.3) and Jellybean (4.1) Android devices will print nothing. What's the problem? I'd like if I could execute some js onload of a link. Anything else would in my case amount to a hack. :/
The problem isn't innerHTML. Try it with alerts if you want (at your own peril).
Another answer mentions checking for this functionality by doing
var huh = 'onload' in document.createElement('link');
..but this is true in both stock browsers! wtf guys?
Android browser doesn't support "onload" / "onreadystatechange" events for element: http://pieisgood.org/test/script-link-events/
But it returns:
"onload" in link === true
So, my solution is to detect Android browser from userAgent and then wait for some special css rule in your stylesheet (e.g., reset for "body" margins).
If it's not Android browser and it supports "onload" event- we will use it:
var userAgent = navigator.userAgent,
iChromeBrowser = /CriOS|Chrome/.test(userAgent),
isAndroidBrowser = /Mozilla\/5.0/.test(userAgent) && /Android/.test(userAgent) && /AppleWebKit/.test(userAgent) && !iChromeBrowser;
addCssLink('PATH/NAME.css', function(){
console.log('css is loaded');
});
function addCssLink(href, onload) {
var css = document.createElement("link");
css.setAttribute("rel", "stylesheet");
css.setAttribute("type", "text/css");
css.setAttribute("href", href);
document.head.appendChild(css);
if (onload) {
if (isAndroidBrowser || !("onload" in css)) {
waitForCss({
success: onload
});
} else {
css.onload = onload;
}
}
}
// We will check for css reset for "body" element- if success-> than css is loaded
function waitForCss(params) {
var maxWaitTime = 1000,
stepTime = 50,
alreadyWaitedTime = 0;
function nextStep() {
var startTime = +new Date(),
endTime;
setTimeout(function () {
endTime = +new Date();
alreadyWaitedTime += (endTime - startTime);
if (alreadyWaitedTime >= maxWaitTime) {
params.fail && params.fail();
} else {
// check for style- if no- revoke timer
if (window.getComputedStyle(document.body).marginTop === '0px') {
params.success();
} else {
nextStep();
}
}
}, stepTime);
}
nextStep();
}
Demo: http://codepen.io/malyw/pen/AuCtH