Skip to content

Instantly share code, notes, and snippets.

@ryanamaral
Forked from eyecatchup/0_localcast.md
Created December 8, 2015 21:24
Show Gist options
  • Save ryanamaral/5459c6c335e3be21d35a to your computer and use it in GitHub Desktop.
Save ryanamaral/5459c6c335e3be21d35a to your computer and use it in GitHub Desktop.
How-To cast any mp4 file from Android to Chromecast.

Cast any (local & remote) mp4 file from Chrome for Android to Chromecast


> If you prefer a _magazine-style_ formatting to read [this gist](https://gist.github.com/eyecatchup/10706409), [click here](http://gist.io/10706409).
A few days ago (April 10th 2014) I was very surprised when I've read on Engadget.com the headline [*"Chrome beta for Android makes it easy to send web video to Chromecast"*](http://j.mp/1gzphu7).

The post attached to this headline refered to a blog post by the Chrome Release team, which was published the same day - April 10th 2014 - and announced the beta release of Chrome 35 for Android. And, indeed, as one of the new features the Chrome team listed

  • Support for casting some videos with Chromecast.

Now, one may ask, why was I "very surprised" when I read the Engadget.com headline?!

It was the term "web". And after checking some other news resources, I was even more surprised - by the fact, that it wasn't just Engadget.com, but the whole community was soley refering to remote playback support.

I thought "What da heck are you all talking about!? I'm casting local videos from my Nexus 5 via Chrome for Android Beta to my Chromecast-equipped TV since a couple of weeks now too.".

More specifically, after I spotted the cast functionality while playing a web video in fullscreen mode in mid of March, I decompiled the Chrome for Android beta apk and found some nice classes living in the namespace com.google.android.apps.chrome.videofling. And after playing a bit with it, I tweeted the very basic idea of what I'm sharing here now on March 28th 2014.

So, basically Google (and several high-traffic blogs) announced the release of a new beta version [of Chrome for Android], with remote video playback support for Chromecast round about 2 weeks after I tweeted and 3 weeks after I first stumbled upon remote and local video playback support for Chromecast?!

That's why I was surprised. It was soley reported about casting remote video files but nobody ever mentioned local video files?!


So let me put it clear: With Chrome Beta for Android you can send any remote or local mp4 file to Chromecast. And for the latter, you don't need any Here is how.


Cast local videos with a Chrome desktop version

If you wanted to cast local videos from your computer to your Chromecast, you'd simply

However, this method has some downsides - one is quality. To quote from an article on techhive that I recently stumbled upon:

Chromecast works best when it’s streaming Netflix and YouTube videos directly from the Internet, with your phone or tablet serving as a remote control. It’s not quite as reliable when you’re using the “Google Cast” Chrome extension to mirror browser tabs. Depending on the strength of your wireless network and the power of your computer, you may have trouble casting videos from Chrome without the audio falling out of sync with the video.

If this happens to you, chances are you can solve the problem by turning down the video quality of the stream. Click the Cast button in Chrome and then click Options. Under Tab projection quality, select Standard (480p).

And that's true. Tab casting sucks; especially for video (in the best case there's still a limit at 720p).


Cast local videos with Chrome for Android

But forget about the video quality for a minute. There's another, nastier problem!

If you recall the steps on a desktop Chrome; Have you ever tried to open a file://-URL (such as file:///sdcard/Download/video.mp4) in your Chrome for Android browser? If so, you'll know it. Otherwise, take this: It won't work!


Okay, let's quickly recap what was written in the news or what you should know so far:

  1. One can cast any local and remote video with a desktop Chrome browser by using the Google Cast extension for Chrome (not at best quality though).
  2. One can use the file://-URI scheme with a desktop Chrome browser in order to request local files on a cum.
  3. One can use the http://-URI scheme with a desktop Chrome browser in order to request remote files.
  4. One can cast "some videos" with the Chrome Beta for Android browser (at least as of version 35).
  5. One can not use the file://-URI scheme with the Chrome Beta for Android browser in order to request local files.

But is this really it? Does Chrome for Android Beta only support "some web videos"? In addition to the headline, the Engadget article says:

Google has rolled out a Chrome 35 beta that lets you deliver "some" clips from the browser to a Chromecast-equipped TV. The company hasn't said just which videos are compatible, but it notes that YouTube support is rough around the edges.

Well, (most of) the answers to these questions can be found in the com.google.android.apps.chrome.videofling namespace.


The videocast support in Chrome for Android Beta works roughly as follows:

Whenever you enter video fullscreen mode in Chrome for Android beta, the function com.google.android.apps.chrome.videofling.FullscreenMediaRouteButton.setButtonVisibility() will display the cast icon in the upper left corner of the screen if

  1. the video URL is not a YouTube URL (!UrlUtilities.sameDomainOrHost(paramString, "http://www.youtube.com", false)) - which gets special treatment,
  2. the mime type is "video/mp4" (this value is hardcoded; no webm so far) and
  3. remote playback is enabled - which is simply achieved by using the "enable-cast" switch:
package com.google.android.apps.chrome.videofling;
//imports
public class RemoteMediaPlayerController
  implements MediaRouteController.Listener, MediaUrlResolver.Delegate
{
  //code..
  
  public static boolean isRemotePlaybackEnabled()
  {
    return CommandLine.getInstance().hasSwitch("enable-cast");
  }
  
  //code..
}

Now, becaue a) a local URL is not a YouTube URL and b) the default video recording format of the stock camera **is** mp4, we _should_ actually be able to fling any local video that we recorded (as long as it is mp4, of course) to our Chromecast-equipped TVs - as long as we set the "enable-cast" switch and find a way to access the local file URL in Chrome for Android (beta).

Setting the "enable-cast" switch is as simple as typing into the URL..- sorry- Omnibar chrome://flags/#enable-cast, clicking the "enable"-link and restarting the browser.

So, how to access the local file now from within Chrome for Android, when the file://-URI scheme is disabled? Well, a local webserver. A webserver? Yes, a webserver.


Even if you're somehow _"into Android"_, you might be surprised that 99.9% of rooted phones have already a very simple webserver on-board: `busybox`'s `httpd`.

In order to start a local webserver at the root of your external device storage, you can type the following from your Android terminal (assuming busybox installed):

$ su
# busybox httpd -p 1234 -h /sdcard/

Assuming your device's local IP is 192.168.1.3, you could access a video, recorded with your camera, by the URL http://192.168.1.3:1234/DCIM/Camera/VID_YYYYMMDD.mp4 now. If httpd would have included the mime type for mp4 files by default. But because it doesn't, we need to add it ourself using a config file for httpd having the following content:

# httpd-chromecast.conf
.mp4:video/mp4

Assuming you saved this file in /sdcard/httpd-chromecast.conf, we need to adjust the command line to start the httpd web server as follows (note: we'll also slightly adjust the home directory):

# busybox httpd -c "/sdcard/httpd-chromecast.conf" -p 1234 -h /sdcard/DCIM/Camera/

Now you can access videos, that you just recorded with the phone's camera, by the URL http://192.168.1.3:1234/VID_YYYYMMDD.mp4 (where VID_YYYYMMDD.mp4 is the filename of the video that you recorded) in Chrome for Android beta. Chrome will open the built-in player for you to play the file. The basic player menu lets you switch to fullscrenn mode - and there you go: the cast icon shows up. From there on, you know what to do. ;-)


GREAT!

You can access, play and cast local mp4 files from Chrome for Android now - just with a single busybox (/httpd) call in advance.


Advanced Usage

For the ease of use, you can now hack a few lines of shell script. For example, you can save this file as localcast in /system/xbin and chmod it executable. Now, whenever you want to cast local videos from your Android to your Chromecast, just open a terminal and type localcast -p [IP:]PORT and you can access - and cast - all local mp4 videos from within Chrome for Android by their local URLs.

Finally, to even save the localcast command line call, you could add a custom init script to auto-start the web server daemon on boot - something like this.


Test it yourself - step by step

Pre-Requirements

  1. A rooted Android device
  2. Busybox installed
  3. Command-line interface to your Android (via ADB from your computer or any Terminal App)

Get started

Open a terminal on your Android and type:

$ su
# echo ".mp4:video/mp4" > "/sdcard/httpd-chromecast.conf"
# wget http://87.238.197.24:666/bunny.mp4 -O /sdcard/test.mp4
# busybox httpd -c "/sdcard/httpd-chromecast.conf" -p 192.168.1.4:1234 -h /sdcard/

That's it. You're ready to cast now.


Open 192.168.1.4:1234/test.mp4 in your Chrome for Android Beta App - you should see the following:

Go fullscreen and you'll see the cast icon in the upper left corner:

Click it and select your Chromecast:

If all went well, you'll see:

#!/system/bin/sh
# (c) 2014 Stephan Schmitz - https://github.com/eyecatchup
EXTBASE="/storage/emulated/0"
CONFFILE="$EXTBASE/httpd-chromecast.conf"
HOMEDIR="$EXTBASE"
BB="/system/xbin/busybox"
help_me() {
echo "Usage: localcast [-p [IP:]PORT]"
echo ""
echo "The following commands may be given as the first argument:"
echo " -p [IP:]PORT Bind to IP:PORT (default *:80)."
echo " -ps List process ids of running httpd instances."
echo " -kill Kill running httpd processes."
echo ""
}
if [ $# == 0 ];
then
echo -e "You can't run localcast by itself."
help_me
exit
fi;
case $1
in
"-ps")
ps | grep "busybox" | awk '{print $2}'
exit;
;;
"-kill")
PID=`ps | grep "busybox" | awk '{print $2}'`
read -p "Kill process id $PID (y|n)? " answer
if [ "$answer" == "y" ]; then
kill -9 $PID
exit;
fi;
exit;
;;
"-p")
if [ $# -ne 2 ];
then
echo -e "Invalid usage."
help_me
exit
fi;
BINDADRESS=$2
$BB httpd -c "$CONFFILE" -p $BINDADRESS -h "$HOMEDIR"
exit;
;;
"--help")
help_me
exit;
;;
*)
echo -e "Invalid usage."
echo -e ""
help_me
exit;
;;
esac;
exit;
#!/system/bin/sh
# add your favorite port here
DEFAULTPORT=1234
/system/xbin/localcast -p $DEFAULTPORT &
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment