Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to control the youtube flash player with c#?

My goal is to make a open source YouTube player that can be controlled via global media keys. The global key issue I got it covered but the communication between the YouTube player and my Windows Forms application just doesn't work for some reason.

So far this is what I have:

private AxShockwaveFlashObjects.AxShockwaveFlash player;
player.movie = "http://youtube.googleapis.com/v/9bZkp7q19f0"
...
private void playBtn_Click(object sender, EventArgs e)
{
    player.CallFunction("<invoke name=\"playVideo\" returntype=\"xml\"></invoke>");
}

Unfortunately this returns:

"Error HRESULT E_FAIL has been returned from a call to a COM component."

What am I missing? Should I load a different URL?
The documentation states that YouTube player uses ExternalInterface class to control it from JavaScript or AS3 so it should work with c#.


UPDATED:


Method used to embed the player: http://www.youtube.com/watch?v=kg-z8JfOIKw

Also tried to use the JavaScript-API in the WebBrowser control but no luck (player just didn't respond to JavaScript commands, tried even to set WebBrowser.url to a working demo, all that I succeeded is to get the onYouTubePlayerReady() to fire using the simple embedded object version )

I think there might be some security issues that I'm overseeing, don't know.


UPDATE 2:


fond solution, see my answer below.

like image 229
Stefan Rogin Avatar asked Nov 06 '12 22:11

Stefan Rogin


2 Answers

It sounds like your trying to use Adobe Flash as your interface; then pass certain variables back into C#.

An example would be this:

In Flash; create a button... Actionscript:

on (press) {
    fscommand("Yo","dude");
}

Then Visual Studio you just need to add the COM object reference: Shockwave Flash Object

Then set the embed to true;

Then inside Visual Studio you should be able to go to Properties; find fscommand. The fscommand will allow you to physically connect the value from the Flash movie.

AxShockwaveFlashObjects._IShockwaveFlashEvents_FSCommandEvent 

That collects; then just use e.command and e.arg for example to have the collected item do something.

Then add this to the EventHandler;

lbl_Result.Text="The "+e.args.ToString()+" "+e.command.ToString()+" was clicked";

And boom it's transmitting it's data from Flash into Visual Studio. No need for any crazy difficult sockets.

On a side note; if you have Flash inside Visual Studio the key is to ensure it's "embed is set to true." That will hold all the path references within the Flash Object; to avoid any miscalling to incorrect paths.

I'm not sure if that is the answer your seeking; or answers your question. But without more details on your goal / error. I can't assist you.

Hope this helps. The first portion should actually show you the best way to embed your Shockwave into Visual Studio.

Make sure you add the correct reference:

  1. Inside your project open 'Solution Explorer'
  2. Right-Click to 'Add Reference'
  3. Go to 'COM Object'

Find Proper object;

COM Objects:
Shockwave ActiveX
Flash Accessibility
Flash Broker
Shockwave Flash

Hope that helps.

It sounds like you aren't embedding it correctly; so you can make the call to it. If I'm slightly mistaken; or is this what you meant:

If your having difficulty Ryk had a post awhile back; with a method to embed YouTube videos:

<% MyYoutubeUtils.ShowEmebddedVideo("<object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/gtNlQodFMi8&hl=en&fs=1"></param><param name="allowFullScreen" value="true"></param><embed src="http://www.youtube.com/v/gtNlQodFMi8&hl=en&fs=1" type="application/x-shockwave-flash" allowfullscreen="true" width="425" height="344"></embed></object>") %>

Or...

public static string ShowEmbeddedVideo(string youtubeObject)
{
    var xdoc = XDocument.Parse(youtubeObject);
    var returnObject = string.Format("<object type=\"{0}\" data=\{1}\"><param name=\"movie\" value=\"{1}\" />",
        xdoc.Root.Element("embed").Attribute("type").Value,
        xdoc.Root.Element("embed").Attribute("src").Value);
    return returnObject;
}

Which you can find the thread here: https://stackoverflow.com/questions/2547101/purify-embedding-youtube-videos-method-in-c-sharp

I do apologize if my post appears fragmented; but I couldn't tell if it was the reference, the variable, the method, or embed that was causing you difficulties. Truly hope this helps; or give me more details and I'll tweak my response accordingly.


C# to ActionScript Communication:

import flash.external.ExternalInterface;
ExternalInterface.addCallback("loadAndPlayVideo", null, loadAndPlayVideo);
function loadAndPlayVideo(uri:String):void
{
       videoPlayer.contentPath = uri;
}

Then in C#; add an instance of the ActiveX control and add the content into a Constructor.

private AxShockwaveFlash flashPlayer;
public FLVPlayer ()
{

      // Add Error Handling; to condense I left out.
      flashPlayer.LoadMovie(0, Application.StartupPath + "\\player.swf");
}

fileDialog = new OpenFileDialog();
fileDialog.Filter = "*.flv|*.flv";
fileDialog.Title = "Select a Flash Video File...";
fileDialog.Multiselect = false;
fileDialog.RestoreDirectory = true;

if (fileDialog.ShowDialog() == DialogResult.OK)
{
     flashPlayer.CallFunction("<invoke" + " name=\"loadAndPlayVideo\" returntype=\"xml">       <arguements><string>" + fileDialog.FileName + "</string></arguements></invoke>");
}

ActionScript Communication to C#:

import flash.external.ExternalInterface;
ExternalInterface.call("ResizePlayer", videoPlayer.metadata.width, videoPlayer.metadata.height);

flashPlayer.FlashCall += new _IShockwaveFlashEvents_FlashCallEventHandler(flashPlayer_FlashCall);

Then the XML should appear:

<invoke name="ResizePlayer" returntype="xml">
     <arguements>
            <number> 320 </number>
            <number> 240 </number>
     </arguments>
</invoke>

Then parse the XML in the event handler and invoke the C# function locally.

 XmlDocument document = new XmlDocument();
    document.LoadXML(e.request);
    XmlNodeList list = document.GetElementsByTagName("arguements");
    ResizePlayer(Convert.ToInt32(list[0].FirstChild.InnerText),   Convert.ToInt32(list[0].ChildNodes[1].InnerText));

Now they are both passing data back and forth. That is a basic example; but by utilizing the ActionScript Communication you shouldn't have any issues utilizing the native API.

Hope that is more helpful. You can expand on that idea by a utility class for reuse. Obviously the above code has some limitations; but hopefully it points you in the right direction. Was that direction you were attempting to go? Or did I still miss the point?


Create a new Flash Movie; in ActionScript 3. Then on the initial first frame; apply the below:

Security.allowDomain("www.youtube.com");
var my_player:Object;
var my_loader:Loader = new Loader();

my_loader.load(new URLRequest("http://www.youtube.com/apiplayer?version=3"))
my_loader.contentLoaderInfo.addEventListener(Event.INIT, onLoaderInit);

function onLoaderInit(e:Event):void{
addChild(my_loader);
my_player = my_loader.content;
my_player.addEventListener("onReady", onPlayerReady); 
} 

function onPlayerReady(e:Event):void{
my_player.setSize(640,360);
my_player.loadVideoById("_OBlgSz8sSM",0);
} 

So what exactly is that script doing? It is utilizing the native API and using ActionScript Communication. So below I'll break down each line.

Security.allowDomain("www.youtube.com");

Without that line YouTube won't interact with the object.

var my_player:Object;

You can't just load a movie into the movie; so we will create a variable Object. You have to load a special .swf that will contain access to those codes. The below; does just that. So you can access the API.

var my_loader:Loader = new Loader();
my_loader.load(new URLRequest("http://www.youtube.com/apiplayer?version=3")); 

We now reference the Google API per their documentation.

my_loader.contentLoaderInfo.addEventListener(Event.INIT, onLoaderInit);

But in order to actually work with our object; we need to wait for it to be fully initialized. So the Event Listener will wait; so we know when we can pass commands to it.

The onLoaderInit function will be triggered upon initialization. Then it's first task will be my_loader to display the list so that the video appears.

The addChild(my_loader); is what will load one; the my_player = my_loader.content; will store a reference for easy access to the object.

Though it has been initialized; you have to wait even further... You use my_player.addEventListener("onReady", onPlayerReady); to wait and listen for those custom events. Which will allow a later function to handle.

Now the player is ready for basic configuration;

function onPlayerReady(e:Event):void{
my_player.setSize(640,360);
} 

The above function starts very basic manipulation. Then the last line my_player.loadVideoById("_OBlgSz8sSM",0); is referencing the particular video.

Then on your stage; you could create two buttons and apply:

play_btn.addEventListener(MouseEvent.CLICK, playVid); 
function playVid(e:MouseEvent):void { 
my_player.playVideo(); 
} 
pause_btn.addEventListener(MouseEvent.CLICK, pauseVid); 
function pauseVid(e:MouseEvent):void { 
my_player.pauseVideo();
}

Which would give you a play and pause functionality. Some additional items you could use our:

loadVideoById() 
cueVideoById() 
playVideo() 
pauseVideo() 
stopVideo() 
mute()
unMute()

Keep in mind those can't be used or called until it has been fully initialized. But using that; with the earlier method should allow you to layout the goal and actually pass variables between the two for manipulation.

Hopefully that helps.

like image 165
Greg Avatar answered Sep 20 '22 00:09

Greg


I'd start by making sure that javascript can talk to your flash app.

make sure you have: allowScriptAccess="sameDomain" set in the embed (from http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/external/ExternalInterface.html#includeExamplesSummary).

you should validate that html->flash works; then C->html; and gradually work up to C->you-tube-component. you have a lot of potential points of failure between C and the you-tube-component right now and it's hard to address all of them at the same time.

like image 40
dtudury Avatar answered Sep 20 '22 00:09

dtudury