Cast image (photo) to Chromecast
Asked Answered
E

2

11

I'm following these (1, 2) guides to create a sender Android application for Chromecast and I'm only interested in sending pictures. There are a lot of informaton and samples how to cast Text, Audio and Video. But not a single word how to that with Pictures.

I belive in power of stackoferflow and someone should've faced such problem. Please give some good sample or tutorial. All I need is guide to cast fullscreen picture using Media Router and its features.

Thats how I was sending text message using custom channel:

 /**
 * Send a text message to the receiver
 */
private void sendMessage(String message) {
    if (mApiClient != null && mSmartBusChannel != null) {
        try {
            Cast.CastApi.sendMessage(mApiClient,
                    mSmartBusChannel.getNamespace(), message)
                    .setResultCallback(new ResultCallback<Status>() {
                        @Override
                        public void onResult(Status result) {
                            if (!result.isSuccess()) {
                                Log.e(TAG, "Sending message failed");
                            }
                        }
                    });
        } catch (Exception e) {
            Log.e(TAG, "Exception while sending message", e);
        }
    } else {
        Toast.makeText(this, message, Toast.LENGTH_SHORT)
                .show();
    }
}

Video is sending using RemotePlaybackClient.. Okay, what's about pictures?

Much thanks for any help.


EDIT:

I have found out method (on this blog) of how it is possible to send pictures from local storage. And yeah, that doesn't seem really working.

public final void openPhotoOnChromecast(String title, String url, String ownerName, String description) {
    try {
        Log.d(TAG, "openPhotoOnChromecast: " + url);
        JSONObject payload = new JSONObject();
        payload.put(KEY_COMMAND, "viewphoto");
        payload.put("fullsizeUrl", url);
        payload.put("ownerName", ownerName);
        payload.put("title", title);
        payload.put("description", description);

        sendMessage(payload);
    } catch (JSONException e) {
        Log.e(TAG, "Cannot parse or serialize data for openPhotoOnChromecast", e);
    } catch (IOException e) {
        Log.e(TAG, "Unable to send openPhotoOnChromecast message", e);
    } catch (IllegalStateException e) {
        Log.e(TAG, "Message Stream is not attached", e);
    }
}

P.S. this method uses sendMessage(...) from these libraries (from gradle):

compile files('libs/commons-io-2.4.jar')
compile files('libs/GoogleCastSdkAndroid.jar')
Ebro answered 4/6, 2015 at 12:30 Comment(0)
B
7

Looking here: Examples using CastCompanionLibrary to simply display an image There are really three options for sending images to a Chromecast.

  1. You can encode the image in a base64 string and send it over a data channel to the receiver. If it is too big, you can split it up and send it across in multiple messages. This is a really poor use of the cast technology and really you shouldn't do this, but it is possible.
  2. You could simply send a url to the Chromecast device and grab it from your sever inside the receiver app. This the the recommended way to send photos across to the Chromecast
  3. If you aren't downloading your images from a server you could set up your own server running inside your client Android app and send a url to the receiver to grab it from there. This is rather complicated for sending images across, but is a far more robust option than option 1.

The goal of Chromecast, according to Google, is to stream content from the cloud, which is why there isn't really any native support for sending local images. Developers should be encouraged to load images on the receiver application from a server.

Boatsman answered 4/6, 2015 at 13:45 Comment(3)
thanks for clear answer. I will try this approach out.Ebro
Okay, first approach didn't work for me. I'm going to try the third one. As far as I understood it would be working according to principle "device uploads - chromecast downloads". Is it needed Internet connection for such files transfering or it would be enough only WiFi between devices? And another question - do I need Custom Receiver for such approach or the Default one will deal with it? Some example would be great btw.Ebro
@Anz have you find a solution for this ?Poll
S
0

Here is a pretty well documented example of how to make a slideshow / serve images from a local folder in Linux / Ubuntu: https://github.com/sbow/pyCast

The directory / file types are specified at runtime - or default values can be used.

The code makes use of the module pychromecast & generates a simple webserver to make the images available to the Chromecast.

Code Examples

Create a local webserver

# Start webserver for current directory

def startServer(args, PORT=8000):
    os.chdir(args.directory)
    handler = http.server.SimpleHTTPRequestHandler
    with socketserver.TCPServer(("", PORT), handler) as httpd:
        print("Server started at localhost:" + str(PORT))
        httpd.serve_forever()

# Start new thread for webserver
daemon = threading.Thread(name='daemon_server',
                          target=startServer,
                          args=(args, PORT))
daemon.setDaemon(True) # Set as a daemon so it will be killed once the main thread is dead.
daemon.start()

Build URL's For Local Images

# Build uri of first image for slideshow. This is sent to the chromecast. This
# ends up being a mash up of the host ip address, the webserver port, and the
# file name of the image to be displayed.
fileName = os.path.basename(filesAndPath[nStartFile])
fileUrl = urllib.parse.quote(fileName)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
ipAddr = s.getsockname()[0]
fileUri = 'http://'+ipAddr+':'+'8000/'+fileUrl

Setup Chromecast

# -- Setup chromecast --
# List chromecasts on the network, but don't connect
services, browser = pychromecast.discovery.discover_chromecasts()
# Shut down discovery
pychromecast.discovery.stop_discovery(browser)
chromecasts, browser = pychromecast.get_listed_chromecasts(
    friendly_names=[args.cast]
)

if not chromecasts:
    print(f'No chromecast with name "{args.cast}" discovered')
    sys.exit(1)

cast = chromecasts[0]
# Start socket client's worker thread and wait for initial status update
cast.wait()
print(f'Found chromecast with name "{args.cast}", attempting to play "{args.url}"')
cast.media_controller.play_media(fileUri, MEDIA_TAG)

# Wait for player_state PLAYING
player_state = None
has_played = False
# -- end Setup chromecast --

Infinite loop serving images from folder

# Enter the infinite loop where successive images are displayed via the
# chromecast, by sending it image uri's served by our scripts webserver,
# linking the chromecast to images in our directory.
iPhoto = nStartFile 
iPhotoMax = nFiles-1 
while True:
    try:
        if player_state != cast.media_controller.status.player_state:
            player_state = cast.media_controller.status.player_state
            print("Player state:", player_state)
        if player_state == "PLAYING":
            has_played = True
        if cast.socket_client.is_connected and has_played and player_state != "PLAYING":
            has_played = False
            cast.media_controller.play_media(args.url, "audio/mp3")

        time.sleep(args.pause)
        if args.do_random:
            nRandom = random.random()*nFiles
            iPhoto = round(nRandom)
        else:
            iPhoto = iPhoto + 1
            if iPhoto > iPhotoMax:
                iPhoto = 0
        fileName = os.path.basename(filesAndPath[iPhoto])
        fileUrl = urllib.parse.quote(fileName)
        fileUri = 'http://'+ipAddr+':'+'8000/'+fileUrl
        cast.media_controller.play_media(fileUri, MEDIA_TAG)

    except KeyboardInterrupt:
        break

Full program pyCast.py

"""
Play a slideshow on the chromecast
This program allows the user to cast images to their chromecast.
The images are of a particular type ie: ".JPEG" or ".jpg" or ".png",
and contained in a single folder. These parameters are provided,
among others, at command line invocation - or through tuning of
the default parameters below.
Arguments
__________
--show-debug : (none)
    Show debugging information. False if not provided.
--do-random : (none)
    Select image order at random. Ls order if not provided.
--media-flag : '*.jpeg'
    Indicate via a command line regex file type to show
--media-tag : 'image/jpeg'
    Indicate http object type
--cast : 'MyKitchenChromecast'
    Provide friendly name of chromecast
--directory : '/home/barack/SecretPix'
    Provide absolute path to directory for slideshow
--pause : 69
    Number of seconds to hold each image in slideshow
Returns
_______
does not return. Ctrl-C to exit, or launch with "&" and kill process
Examples
______
python pyCast.py --show-debug --media-flag '*.JPEG' --media-tag 'image/jpeg'
--cast 'MyChromecast' --directory '/home/dorthy/OzGirlSummerPics' --do-random
"""
# pylint: disable=invalid-name

import argparse
import logging
import sys
import time
import pychromecast
import pprint
import glob
import os
import urllib.parse
import socket
import http.server
import socketserver
import threading
import random

# Authorship information
__author__ = "Shaun Bowman"
__copyright__ = "Copywrong 2022, Mazeltough Project"
__credits__ = ["SoManyCopyPastes... sorry i dont know the names", "Mom"]
__license__ = "MIT"
__version__ = "0.420.69"
__maintainer__ = "Shaun Bowman"
__email__ = "[email protected]"
__status__ = "AlphaAF"

# Change to the friendly name of your Chromecast
CAST_NAME = 'ShaunsOfficeMonitor'

# Set webserver port
PORT = 8000

# Set time for photo
PAUSE = 120

# Set media type
MEDIA_FLAG = "*.JPEG"
MEDIA_TAG = "image/jpeg"

# Change to an audio or video url
MEDIA_URL ="http://192.168.0.222:8000/Screenshot%20from%202021-01-24%2023-11-40.png"
MEDIA_DIR = "./"
parser = argparse.ArgumentParser(
    description="Play a slideshow on Chromecast using all images of a given "+
    "type in a given directory."
)
parser.add_argument("--show-debug", help="Enable debug log", action="store_true")
parser.add_argument("--do-random", help="Pick media in dir at random, default false",
                    action="store_false")
parser.add_argument(
    "--media-flag", help="Media flag like *.JPEG or *.png", default=MEDIA_FLAG
)
parser.add_argument(
    "--media-tag", help="Media tag like 'image/jpeg' or 'image/png'",
    default=MEDIA_TAG
)
parser.add_argument(
    "--pause", help="Number of seconds per photograph during slideshow",
    default=PAUSE
)
parser.add_argument(
    "--cast", help='Name of cast device (default: "%(default)s")', default=CAST_NAME
)
parser.add_argument(
    "--url", help='Media url (default: "%(default)s")', default=MEDIA_URL
)
parser.add_argument(
    "--directory", help='Directory containing media to cast', default=MEDIA_DIR
)
args = parser.parse_args()

if args.show_debug:
    logging.basicConfig(level=logging.DEBUG)

# Start webserver for current directory
def startServer(args, PORT=8000):
    os.chdir(args.directory)
    handler = http.server.SimpleHTTPRequestHandler
    with socketserver.TCPServer(("", PORT), handler) as httpd:
        print("Server started at localhost:" + str(PORT))
        httpd.serve_forever()

# Start new thread for webserver
daemon = threading.Thread(name='daemon_server',
                          target=startServer,
                          args=(args, PORT))
daemon.setDaemon(True) # Set as a daemon so it will be killed once the main thread is dead.
daemon.start()

# Wait for stuff... maybe useless
time.sleep(2)

# Get list of files of specific type, in specific directory
pprint.pprint(glob.glob(args.directory+"/"+MEDIA_FLAG))
filesAndPath = glob.glob(args.directory+"/"+MEDIA_FLAG)
nFiles = len(filesAndPath)
if (nFiles==0):
    pprint.pprint("Error: No files found")
    sys.exit(1)

# Select starting point for slideshow
random.seed()
nRandom = random.random()*nFiles
nStartFile = round(nRandom)

# Build uri of first image for slideshow. This is sent to the chromecast. This
# ends up being a mash up of the host ip address, the webserver port, and the
# file name of the image to be displayed.
fileName = os.path.basename(filesAndPath[nStartFile])
fileUrl = urllib.parse.quote(fileName)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
ipAddr = s.getsockname()[0]
fileUri = 'http://'+ipAddr+':'+'8000/'+fileUrl

# -- Setup chromecast --
# List chromecasts on the network, but don't connect
services, browser = pychromecast.discovery.discover_chromecasts()
# Shut down discovery
pychromecast.discovery.stop_discovery(browser)
chromecasts, browser = pychromecast.get_listed_chromecasts(
    friendly_names=[args.cast]
)
if not chromecasts:
    print(f'No chromecast with name "{args.cast}" discovered')
    sys.exit(1)

cast = chromecasts[0]
# Start socket client's worker thread and wait for initial status update
cast.wait()
print(f'Found chromecast with name "{args.cast}", attempting to play "{args.url}"')
cast.media_controller.play_media(fileUri, MEDIA_TAG)

# Wait for player_state PLAYING
player_state = None
has_played = False
# -- end Setup chromecast --

# Enter the infinite loop where successive images are displayed via the
# chromecast, by sending it image uri's served by our scripts webserver,
# linking the chromecast to images in our directory.
iPhoto = nStartFile 
iPhotoMax = nFiles-1 
while True:
    try:
        if player_state != cast.media_controller.status.player_state:
            player_state = cast.media_controller.status.player_state
            print("Player state:", player_state)
        if player_state == "PLAYING":
            has_played = True
        if cast.socket_client.is_connected and has_played and player_state != "PLAYING":
            has_played = False
            cast.media_controller.play_media(args.url, "audio/mp3")

        time.sleep(args.pause)
        if args.do_random:
            nRandom = random.random()*nFiles
            iPhoto = round(nRandom)
        else:
            iPhoto = iPhoto + 1
            if iPhoto > iPhotoMax:
                iPhoto = 0
        fileName = os.path.basename(filesAndPath[iPhoto])
        fileUrl = urllib.parse.quote(fileName)
        fileUri = 'http://'+ipAddr+':'+'8000/'+fileUrl
        cast.media_controller.play_media(fileUri, MEDIA_TAG)

    except KeyboardInterrupt:
        break

# Shut down discovery
browser.stop_discovery()
Scapolite answered 12/1, 2022 at 16:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.