3

My question is, should I use the YouTube API to load the a video that I've recorded from glass and sent to my server as an attachment to a notification? Or, is there a mirror-api call that I should use instead?

For instance, the URL for the video that I am receiving looks like this: http://redirector.googlevideo.com/videoplayback?id=875f7e1335214880&itag=22&source=picasa&cmo=sensitive_content%3Dyes&ip=0.0.0.0&ipbits=0&expire=1384018362&sparams=id,itag,source,ip,ipbits,expire&signature=AB8FC431423D6C86024A36F170ECF20C6F02223C.3FA395F9092F2EE5D6B14ACF49A4C18725A8846B&key=lh1

I did check out this answer which is similiar: Displaying Video on Webpage from Google Glass, but wasn't sure if actually should use the YouTube API. If I should, could someone could point me in the right direction in terms of which calls I should investigate?

Thanks!

Quick Update to add more context, so if I record a 10 sec video and share to my server via a custom contact card, I immediately get the following (this is my own debugging output via error logs):

[error] Error Downloading Attachment - HTTP ResponseCode:404
[error] ContentUrl:         
[error] ContentType:        video/mp4
[error] id                  ps:5933350025312253298
[error] IsProcessing:       1

So, this totally makes sense as the video is still processing. Now, if I wait a couple minutes and re-share the video with my server, I get the following:

[error] Error Downloading Attachment - HTTP ResponseCode:302
[error] ContentUrl:         http://redirector.googlevideo.com/videoplayback?id=e0d5f76ca1fff29a&itag=22&source=picasa&cmo=sensitive_content%3Dyes&ip=0.0.0.0&ipbits=0&expire=1384058057&sparams=id,itag,source,ip,ipbits,expire&signature=CD41362EC3D3DDCD9EA3A63003B4C1A1F95D52C.BAE1608B827661FD47FC8D68DCBCE32F683A013D&key=lh1
[error] ContentType:        video/mp4
[error] id                  ps:5933350025312253298
[error] IsProcessing:       0

To contrast, Image attachments always work, and look like so:

[error] Downloading Attachment - HTTP ResponseCode:200
[error] ContentUrl:         https://www.googleapis.com/mirror/v1/timeline/7f13b01d-ee26-4b02-b6c3-7f885a452fc9/attachments/ps:5933353306000857698?alt=media
[error] ContentType:        image/jpeg
[error] id                  ps:5933353306000857698
[error] IsProcessing:       0

So that's the rub. I can't figure out a way to access the video data, partly because it's a redirect that (seems to??) require some sort auth exchange to handle, and I can't figure out which API to use to help me do that.

So, going back to my question... is there a suggested way for me to handle the redirector url to either download the video to my server, OR, even just keep it hosted where it is, but wrap a youtube'esque player around it like the G+ backup cloud player? My intent is that I make the video publicly viewable.

Thanks! Update: here is a gist of the code I'm using. I just started out with the sample PHP quickstart that the Glass Team provided:

https://gist.github.com/ozfarman/6953473

Community
  • 1
  • 1
ozfarman
  • 56
  • 1
  • 1
  • 6
  • Can you please share the code you are using to download the video attachment? – mimming Oct 12 '13 at 00:00
  • Hi Jenny, sure thing. Just updated the question with a gist link. As you'll see, it's all based on the code that you wrote for the quick-start project :) https://gist.github.com/ozfarman/6953473 – ozfarman Oct 12 '13 at 18:51

2 Answers2

2

You should use the Google API client to download attachment URLs, which will handle authorization and any redirects for you. Please see the examples provided in the Timeline.attachments.get documentation, for whichever language you're coding in.

Tony Allevato
  • 6,429
  • 1
  • 29
  • 34
  • Thanks Tony. Thats exactly what I'm doing. I've coded this in php and am using the download_attachment function in the examples. It works fine for images that are attachments from the Timeline, but for video, I get a 302 http response. My assumption is that because the video is stored on the googlevideo servers, that there is an additional round-robin of auth that I need to do. – ozfarman Oct 11 '13 at 03:57
2

Use Googles Mirror Api Client to check the status of the attachments associated with the timeline item. It can take up to a few minutes for the video to be available depending on its length. Oddly enough, if you follow the 302's from their redirect you end up in a Picasa domain, which is a bit bizarre considering it's video, but does indicate that Google is doing some pre-processing of your video before handing it over.

This code is part of a queued process I wrote to handle checking back with Google about the processing status of a timeline item. The callback from Google gets inserted into my queue server and picked up by the worker that proactively checks the status every X seconds to determine if the media is ready, if it exceeds a number of loops it just requeues the job to be picked up by another worker. Proactively checking instead of returning a non 200 code in your callback is highly beneficial because Google does exponential backoff on their api calls, so for a video that takes some time to get into the right state you may end up with very long waiting periods between callbacks from Google.

public function run($data) { $timeline_item_id = $data['timeline_item_id'];

    try{
        $glassUtils = new Google_Glass_Utilities();
        $mirrorClient = new Google_Glass_MirrorClient();
        $client = $mirrorClient->get_google_api_client();
        $client->setAccessToken($data['credentials']);
        $mirror_service = new Google_MirrorService($client);
        echo "\nTIMELINE ITEM ID: " . $data['timeline_item_id'] . "\n";
        $timeline_item = $mirror_service->timeline->get($timeline_item_id);
        $caption = $timeline_item->getText();
    }catch (Exception $e){
        echo "ERROR";
        echo $e->getMessage();
        return true;
    }

    //Blocker that waits for the item to be in the active state
    //Should be faster than waiting for extra callbacks from Google
    try{
        $checkCount = 1;
        while(true){
            $blnProceed = true;

            echo "Check " . $checkCount . " of " . $this->maxSearchChecks . " for attachments on timeline item " . $timeline_item_id . "\n";

            $attachments = $mirror_service->timeline_attachments->listTimelineAttachments($timeline_item_id);
            foreach ($attachments->getItems() as $attachment) {
                echo "Attachment content type: " . $attachment->getContentType() . "\n";
                //echo "Attachment content URL: " . $attachment->getContentUrl();
                if($attachment->getIsProcessingContent() && $attachment->getContentType() == 'video/mp4'){
                    $blnProceed = false;
                }
            }

            if(!$blnProceed){
                echo "Attachments were not ready\n";
                if($checkCount == $this->maxSearchChecks){
                    echo "Job hit max checks, requeueing\n";
                    $task = new BackgroundTask();
                    $task->addTask('GlassVideoImport', $saveData);
                    $task->submit();
                    GearmanPearManager::$LOG[] = "Success";
                    return true;
                }else{
                    $checkCount += 1;
                    echo "Sleeping for " . $this->sleepSecs . " seconds before recheck\n";
                    sleep($this->sleepSecs);
                }
            }else{
                echo "GOT THE TIMELINE ITEM AND ATTACHMENT IS READY\n\n\n\n";
                //Continue
                break;
            }
        }
    }catch (Exception $e){
        echo "ERROR";
        echo $e->getMessage();
        return true;
    }

    //Got here so now go get the attachment
    try{
        $attachment = $mirror_service->timeline_attachments->get($data['timeline_item_id'], $data['timeline_attachment_id']);
        $attachmentBinary = $this->downloadAttachment($data['timeline_item_id'], $attachment);

        //Do something with the binary of the attachment


        GearmanPearManager::$LOG[] = "Success";
        return true;
    }
    catch( Exception $e ) {
        echo $e->getMessage() . "\n";
        @unlink($fileRes['localFile']);
        GearmanPearManager::$LOG[] = "Failure";
        return true;
    }
}

private function downloadAttachment($itemId, $attachment) {
    $request = new Google_HttpRequest(
    $attachment->getContentUrl(), 'GET', null, null);
    $httpRequest = Google_Client::$io->authenticatedRequest($request);
    if ($httpRequest->getResponseHttpCode() == 200) {
        return $httpRequest->getResponseBody();
    } else {
        return null;
    }
}
Tim Flack
  • 66
  • 4
  • Thanks Tim! One quick followup question for you. Once you have the timeline item and the attachment is ready, how are you actually pulling the data sitting at the contentUrl down to your server? Is the URL actually still a googlevideo url? – ozfarman Oct 12 '13 at 17:33
  • See my updated response above, includes the code for getting the binary content of the attachment – Tim Flack Oct 14 '13 at 03:23
  • Thanks Tim! I've been actually using the same download_attachment function. So I think the solution is to ignore the isProcessing flag, and keep trying with a worker / cron like you have setup. Thanks again! – ozfarman Oct 14 '13 at 17:07