Open Chromecast youtube video from android application

懵懂的女人 提交于 2019-11-29 05:19:12

I wrote an Android app that plays YouTube/Local media on VLC attached to a big screen TV last year. It was playing very nice but I always want to replace the VLC laptop with something more elegant. I was really excited when Chromecast was finally released with an official SDK. I too ran into the same problem when trying to launch YouTube receiver app to play YouTube video so I decided to delve into how VLC was able to do that (Is open source great :)) I found out that the YouTube video ID is just a JavaScript page with lots of stuff embedded inside. The trick is to pull out the correct info from it. Unfortunately, the VLC script is written in Lua so I spent a couple weeks learning enough Lua to navigate my way around the Lua script. You can google youtube.lua for the source code of the script.

I rewrote the script in Java and was able to modify CastVideos Android to play YouTube video at ease. Note that since Chromecast can only play mp4 video container format, video in other format may not play.

Here is my test code if anyone is interested. You can test the URL using CastHelloVideo-chrome load custom media.

Enjoy,

Danh

    package com.dql.urlexplorer;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

public class UrlExplore {

    private static final String URL_ENCODED_STREAM_MAP     = "\"url_encoded_fmt_stream_map\":";
    private static final String VIDEO_TITLE_KEYWORD               = "<meta name=\"title\"";
    private static final String VIDEO_DESCRIPTION_KEYWORD  = "<meta name=\"description\"";
    private static final String VIDEO_THUMBNAIL_KEYWORD    = "<meta property=\"og:image\"" ;
    private static final String CONTENT_VALUE_KEYWORD        = "content=\"";

    //private static final String TEST_URL = "http://www.youtube.com/watch?v=JtyCM4BTbYo";
    private static final String YT_UTRL_PREFIX = "http://www.youtube.com/watch?v=";

    public static void main(String[] args) throws IOException {

        while (true) {
               String videoId = getVideoIdFromUser();

                String urlSite = YT_UTRL_PREFIX + videoId;
                System.out.println("URL =  " + urlSite);
                System.out.println("===============================================================");
                System.out.println("Getting video site content");
                System.out.println("===============================================================");

                CloseableHttpClient httpclient = HttpClients.createDefault();
                try {
                    HttpGet httpget = new HttpGet(urlSite);

                    System.out.println("Executing request " + httpget.getRequestLine());


                    // Create a custom response handler
                    ResponseHandler<String> responseHandler = new ResponseHandler<String>() {

                        public String handleResponse(
                                final HttpResponse response) throws ClientProtocolException, IOException {
                            int status = response.getStatusLine().getStatusCode();
                            if (status >= 200 && status < 300) {
                                HttpEntity entity = response.getEntity();
                                return entity != null ? EntityUtils.toString(entity) : null;
                            } else {
                                throw new ClientProtocolException("Unexpected response status: " + status);
                            }
                        }

                    };
                    String responseBody = httpclient.execute(httpget, responseHandler);

                    if (responseBody.contains(VIDEO_TITLE_KEYWORD)) {
                        // video title
                        int titleStart = responseBody.indexOf(VIDEO_TITLE_KEYWORD);
                        StringBuilder title = new StringBuilder();
                        char ch;
                        do {
                            ch = responseBody.charAt(titleStart++);
                            title.append(ch);
                        }
                        while (ch != '>');
                        String videoTitle = getKeyContentValue(title.toString());
                         System.out.println("Video Title =  " + videoTitle);
                    }
                    if (responseBody.contains(VIDEO_DESCRIPTION_KEYWORD)) {
                        // video description
                        int descStart = responseBody.indexOf(VIDEO_DESCRIPTION_KEYWORD);
                        StringBuilder desc = new StringBuilder();
                        char ch;
                        do {
                            ch = responseBody.charAt(descStart++);
                            desc.append(ch);
                        }
                        while (ch != '>');
                        String videoDesc = getKeyContentValue(desc.toString());
                         System.out.println("Video Description =  " + videoDesc);                       
                    }
                    if (responseBody.contains(VIDEO_THUMBNAIL_KEYWORD)) {
                        // video thumbnail
                        int thumbnailStart = responseBody.indexOf(VIDEO_THUMBNAIL_KEYWORD);
                        StringBuilder thumbnailURL = new StringBuilder();
                        char ch;
                        do {
                            ch = responseBody.charAt(thumbnailStart++);
                            thumbnailURL.append(ch);
                        }
                        while (ch != '>');
                        String videoThumbnail= getKeyContentValue(thumbnailURL.toString());
                         System.out.println("Video Thumbnail =  " + videoThumbnail);                        
                    }
                    if (responseBody.contains(URL_ENCODED_STREAM_MAP)) {
                        // find the string we are looking for
                        int start = responseBody.indexOf(URL_ENCODED_STREAM_MAP) + URL_ENCODED_STREAM_MAP.length() + 1;  // is the opening "
                        String urlMap = responseBody.substring(start);
                        int end = urlMap.indexOf("\"");
                        if (end > 0) {
                            urlMap = urlMap.substring(0, end);
                        }
                        String path = getURLEncodedStream(urlMap);
                        System.out.println("Video URL = " + path);
                    }

                }
                finally {
                    httpclient.close();
                }
                System.out.println( "===============================================================");
                System.out.println("Done: ");
                System.out.println("===============================================================");      
        }

    }

    static String getURLEncodedStream(String stream) throws UnsupportedEncodingException {
        // replace all the \u0026 with &
         String str = stream.replace("\\u0026", "&");
        //str = java.net.URLDecoder.decode(stream, "UTF-8");
        //System.out.println("Raw URL map = " + str);
        String urlMap = str.substring(str.indexOf("url=http") + 4);
        // search urlMap until we see either a & or ,
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < urlMap.length(); i++) {
            if ((urlMap.charAt(i) == '&') || (urlMap.charAt(i) == ','))
                break;
            else
                sb.append(urlMap.charAt(i));
        }
        //System.out.println(java.net.URLDecoder.decode(sb.toString(),"UTF-8"));
        return java.net.URLDecoder.decode(sb.toString(),"UTF-8");

    }

    static String getKeyContentValue(String str) {
        StringBuilder contentStr = new StringBuilder();
        int contentStart = str.indexOf(CONTENT_VALUE_KEYWORD) + CONTENT_VALUE_KEYWORD.length();
        if (contentStart > 0) {
            char ch;
            while (true) {
                ch = str.charAt(contentStart++);
                if (ch == '\"')
                    break;
                contentStr.append(ch);
            }
        }
        try {
            return java.net.URLDecoder.decode(contentStr.toString(),"UTF-8");
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    /*
     * Prompt the user to enter a video ID.
     */
    private static String getVideoIdFromUser() throws IOException {

        String videoId = "";

        System.out.print("Please enter a YouTube video Id: ");
        BufferedReader bReader = new BufferedReader(new InputStreamReader(System.in));
        videoId = bReader.readLine();

        if (videoId.length() < 1) {
            // Exit if the user doesn't provide a value.
            System.out.print("Video Id can't be empty! Exiting program");
            System.exit(1);
        }

        return videoId;
    }

}`enter code here`

I recently wrote a library to solve this problem. chromecast-sender. It is an extension library for the android-youtube-player library and makes it easy to cast videos from an Android app to a Google Cast device.

The receiver uses the YouTube IFrame player API. Sender and Receiver communicate through a custom channel.

You cannot do that with the official SDK. Some folks have used iframe approach but there is varying reports of success.

We can join with live session usign current chromecast device: Use the below call back and let me know if you want the same as below then i will send remaining part of the code.

private final GoogleApiClient.ConnectionCallbacks connectionCallback = new GoogleApiClient.ConnectionCallbacks() {
        @Override
        public void onConnected(Bundle bundle) {
            // SDK confirms that GoogleApiClient is connected: GoogleApiClient.ConnectionCallbacks.onConnected
            Trace.d(TAG, "GoogleApiClient.ConnectionCallbacks # onConnected()");

            try {
                // Sender app launches or join the receiver app: Cast.CastApi.launchApplication
                Cast.CastApi.joinApplication(mApiClient).setResultCallback(connectionResultCallback);
            } catch (Exception e) {
                Trace.d(TAG, "Failed to join application");
            }
        }

        @Override
        public void onConnectionSuspended(int i) {
            Trace.d(TAG, "GoogleApiClient.ConnectionCallbacks # onConnectionSuspended()");
            try {
                Cast.CastApi.leaveApplication(mApiClient);
            } catch (Exception e) {
                Trace.d(TAG, "Failed to join application");
            }
        }
    };
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!