Google's Chromecast is a pretty useful device. It plugs into the HDMI port of a TV and allows users to "cast" content to it via a smartphone, Chrome browser, etc. This content is mostly assumed to be streaming services like Youtube, Spotify, or Netflix, but for someone who doesn't really buy into the whole cloud revolution like myself, it's still perfectly capable of playing local content as well.
The one downside of the Chromecast is that when it's not being used, instead of going into a low-power state and/or turning off the TV, it instead enters Ambient Mode. This shows some useful information overlaid on a changing backdrop of featured photos downloaded from Google Photos. The issue with this is that the images are high-resolution, not cached, and are continually being downloaded 24/7 even when the TV is turned off. Although I haven't personally measured it, the general consensus seems to be that it uses around 15GB of data per month from just being plugged in.
What I'll be going over here is reducing the data the Chromecast uses by configuring it to only download some tiny black 1x1 px images to use as a backdrop.
The short version
- Make a tiny black PNG (pixel.png)
- Make a slightly different tiny PNG to avoid deduplication (pixel_alt1.png)
- Upload both to an album in Google Photos
- Mark both images as favorites
- Configure the Chromecast to only pull images from your specific album every 10 minutes
If you like details, keep reading...
Making a small image
I ended up creating a 1x1 solid black image in GIMP, saving it as a PNG, hacking out as much data as
possible using a hex editor, then using pngcrush
to attempt to optimize the data
that was left.
As I was working on the PNG file, I used a small script based on the Python construct library to visualize the chunks and structure of it so I could figure out what to cut.
To install construct
and download the example PNG specification:
1 2 3 4 |
|
Create pngview.py
:
1 2 3 4 5 6 7 |
|
Running it on the PNG exported from GIMP using the default settings gives:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
|
After removing the unneeded pHYs
, tIME
, and tEXt
chunks using a hex editor, it looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
At this point, all that's left to optimize is the image data itself. This is where pngcrush
shines. After running pngcrush -brute -ow pixel.png
we see:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
The 2 byte savings in the data seem to have come from setting the color_type
to greyscale
instead of truecolor
. To view what actually changed in the data, we can un-deflate
it using Python:
1 2 3 4 5 6 7 8 |
|
This makes sense since, according to the PNG spec, when using truecolor
, each pixel is an RGB
triple, requiring 3 bytes. For greyscale
, only a single byte representing luminance is needed. The
first byte is the filtering method, which isn't relevant here since we only have a single pixel.
Interestingly enough, in both cases we would actually be much better off if we could opt to not use
compression, but alas, the spec does not allow for anything except deflate
.
But I digress, we now have a black 1x1 px PNG image that's just 67 bytes (pixel.png).
Generating multiple unique small images
So now we have the small PNG we want to display. Since the Chromecast's ambient mode requires at least 2 different images in an album to cycle through, all we need to to do is upload 2 copies of this PNG and we're done right? Almost.
Since Google Photos will automatically deduplicate uploaded images, we need to find a way to make the second image slightly different. Normally this would involve tweaking a comment or something, but in this case, the image has already been stripped down to its bare essentials.
My strategy was attempt to abuse the data compression to see if I could generate an image that
compressed the same data into the same number of bytes, but differently. Fortunately, pngcrush
can
be told to use specific compression strategies (there are currently 177 of them). My hope is that at
least one of these will achieve the same results, but in a different way. For starters we'll try the
first 9:
1 2 3 |
|
A quick ls -l
reveals that all of the pixel_alt*.png
files are still 67 bytes. Now we just need
to find one that has different data. sha1sum
is the perfect utility for this:
1 2 3 4 5 6 7 8 9 10 11 |
|
pixel_alt1.png
looks like a good candidate, let's see what changed:
1 2 3 4 5 6 7 |
|
There's the same amount of data, but it's different. Let's check if it decompresses to the same image data:
1 2 3 4 5 6 |
|
Yep, this means that pixel_alt1.png is the exact same image with the exact same size, but won't be deduplicated when uploading it to Google Photos since the compressed data is different.
Final touches
Now that we have 2 different tiny images, we can upload them to Google Photos and put them in an album so they can be pulled down by the Chromecast. Something to note is that you may have to mark the images as favorites to get them to be displayed. There seems to be some sort of AI-fueled "we know better than you" algorithm that initially refused to display my images until I starred them.
Now just set your ambient mode to display the album with your images in it (or your favorites album), set the slideshow speed to its maximum value (change image every 10 mins), and you're done.