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.
我的目标是制作一个开放源码的YouTube播放器,可以通过全球媒体键进行控制。我得到的全球关键问题是,但是YouTube播放器和我的Windows窗体应用程序之间的通信是不正常的。
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#.
我缺少什么?我应该加载不同的URL吗?该文档声明YouTube player使用ExternalInterface类从JavaScript或AS3控制它,因此应该使用c#。
UPDATED:
Method used to embed the player: http://www.youtube.com/watch?v=kg-z8JfOIKw
方法用于嵌入播放器: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 )
还尝试在WebBrowser控件中使用JavaScript api,但是没有运气(player只是没有响应JavaScript命令,甚至尝试设置WebBrowser。url到一个工作的演示,我所成功的是使用简单的嵌入式对象版本让onYouTubePlayerReady()启动)
I think there might be some security issues that I'm overseeing, don't know.
我想可能有一些安全问题我在监督,不知道。
UPDATE 2:
fond solution, see my answer below.
喜欢的解决办法,请看下面我的答案。
4 个解决方案
#1
5
It sounds like your trying to use Adobe Flash as your interface; then pass certain variables back into C#.
听起来你想用Adobe Flash作为你的界面;然后将某些变量传回c#。
An example would be this:
举个例子:
In Flash; create a button... Actionscript:
在Flash中;创建一个按钮……动作脚本:
on (press) {
fscommand("Yo","dude");
}
Then Visual Studio you just need to add the COM object reference: Shockwave Flash Object
然后Visual Studio只需要添加COM对象引用:Shockwave Flash对象。
Then set the embed to true;
然后将embed设置为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.
在Visual Studio中,你可以进入属性;找到fscommand。fscommand将允许您物理地连接Flash影片中的值。
AxShockwaveFlashObjects._IShockwaveFlashEvents_FSCommandEvent
That collects; then just use e.command
and e.arg
for example to have the collected item do something.
收集;然后使用e。command和e。例如,arg可以让收集的项目做一些事情。
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.
它把数据从Flash传输到Visual Studio。不需要任何疯狂的困难套接字。
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.
从一个方面说明;如果在Visual Studio中有Flash,关键是要确保它的“embed is set to true”。它将保存Flash对象中的所有路径引用;避免任何错误路径的错误。
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.
希望这个有帮助。第一部分实际上应该向您展示将Shockwave嵌入到Visual Studio的最佳方法。
Make sure you add the correct reference:
确保你添加了正确的参考:
- Inside your project open 'Solution Explorer'
- 在你的项目中打开“解决方案资源管理器”
- Right-Click to 'Add Reference'
- 右键单击“添加引用”
- Go to 'COM Object'
- 去“COM对象”
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:
如果你有困难,Ryk有一个帖子;用一种方法嵌入YouTube视频:
<% 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://*.com/questions/2547101/purify-embedding-youtube-videos-method-in-c-sharp
你可以在这里找到这个线程:https://*.com/questions/2547101/purifing -youtube-video -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:
c#编程语言沟通:
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.
然后在c#中;添加ActiveX控件的实例,并将内容添加到构造函数中。
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#:
c# ActionScript沟通:
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:
然后出现XML:
<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.
然后解析事件处理程序中的XML并在本地调用c#函数。
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.
现在它们都来回传递数据。这是一个基本的例子;但是通过使用ActionScript通信,您不应该对使用本机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:
创建一个新的Flash影片;ActionScript 3。然后在第一帧;应用如下:
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.
那么这个脚本到底在做什么呢?它使用本机API并使用ActionScript通信。下面我将分解每一行。
Security.allowDomain("www.youtube.com");
Without that line YouTube won't interact with the object.
如果没有这条线,YouTube将无法与该对象交互。
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.
你不能把一部电影放进电影里;我们将创建一个变量对象。您必须加载一个特殊的.swf,它将包含对这些代码的访问。以下;就是干这个的。你可以访问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.
我们现在根据他们的文档引用谷歌API。
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.
onLoaderInit函数将在初始化时触发。然后它的第一个任务将是my_loader来显示列表,以便显示视频。
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.
addChild(my_loader);是装载一个的;my_player = my_loader.content;将存储一个引用以方便访问对象。
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.
虽然已经初始化;你得再等一等……你用my_player。addEventListener(“onReady”,onPlayerReady);等待并侦听那些自定义事件。这将允许以后的函数处理。
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.
上面的函数开始非常基本的操作。最后一行my_player.loadVideoById(“_OBlgSz8sSM”,0);是指特定的视频。
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.
希望有帮助。
#2
2
I'd start by making sure that javascript can talk to your flash app.
首先,我要确保javascript可以与flash应用对话。
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).
确保在嵌入中设置了:allowScriptAccess=“sameDomain”(来自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.
您应该验证html->flash是否有效;然后C - > html;并逐步计算到C->你管的分量。在C和you-tube组件之间有很多潜在的失败点,很难同时处理所有这些点。
#3
2
After a lot of tries and head-hammering, I've found a solution:
经过多次尝试,我找到了一个解决办法:
Seems that the Error HRESULT E_FAIL...
happens when the flash dosen't understand the requested flash call. Also for the youtube external api to work, the js api needs to be enabled:
似乎错误HRESULT E_FAIL…当flash dosen不理解请求的flash调用时发生。同时,为了让youtube的外部api工作,js api需要启用:
player.movie = "http://www.youtube.com/v/VIDEO_ID?version=3&enablejsapi=1"
As I said in the question the whole program is open source, so you will find the full code at bitbucket.
Any advice, suggestions or collaborators are highly appreciated.
正如我在问题中提到的,整个程序是开源的,所以您可以在bitbucket中找到完整的代码。如有任何建议、建议或合作者,我们将不胜感激。
The complete solution:
Here is the complete guide for embedding and interacting with the YouTube player or any other flash object.
下面是嵌入和与YouTube播放器或任何其他flash对象交互的完整指南。
After following the video tutorial , set the flash player's FlashCall
event to the function that will handle the flash->c# interaction (in my example it's YTplayer_FlashCall
)
在完成本视频教程之后,将flash player的FlashCall事件设置为处理flash->c#交互的函数(在我的示例中是YTplayer_FlashCall)
the generated `InitializeComponent()` should be:
...
this.YTplayer = new AxShockwaveFlashObjects.AxShockwaveFlash();
this.YTplayer.Name = "YTplayer";
this.YTplayer.Enabled = true;
this.YTplayer.OcxState = ((System.Windows.Forms.AxHost.State)(resources.GetObject("YTplayer.OcxState")));
this.YTplayer.FlashCall += new AxShockwaveFlashObjects._IShockwaveFlashEvents_FlashCallEventHandler(this.YTplayer_FlashCall);
...
the FlashCall event handler
private void YTplayer_FlashCall(object sender, AxShockwaveFlashObjects._IShockwaveFlashEvents_FlashCallEvent e)
{
Console.Write("YTplayer_FlashCall: raw: "+e.request.ToString()+"\r\n");
// message is in xml format so we need to parse it
XmlDocument document = new XmlDocument();
document.LoadXml(e.request);
// get attributes to see which command flash is trying to call
XmlAttributeCollection attributes = document.FirstChild.Attributes;
String command = attributes.Item(0).InnerText;
// get parameters
XmlNodeList list = document.GetElementsByTagName("arguments");
List<string> listS = new List<string>();
foreach (XmlNode l in list){
listS.Add(l.InnerText);
}
Console.Write("YTplayer_FlashCall: \"" + command.ToString() + "(" + string.Join(",", listS) + ")\r\n");
// Interpret command
switch (command)
{
case "onYouTubePlayerReady": YTready(listS[0]); break;
case "YTStateChange": YTStateChange(listS[0]); break;
case "YTError": YTStateError(listS[0]); break;
default: Console.Write("YTplayer_FlashCall: (unknownCommand)\r\n"); break;
}
}
this will resolve the flash->c# communication
这将解决flash->c#通信
calling the flash external functions (c#->flash):
private string YTplayer_CallFlash(string ytFunction){
string flashXMLrequest = "";
string response="";
string flashFunction="";
List<string> flashFunctionArgs = new List<string>();
Regex func2xml = new Regex(@"([a-z][a-z0-9]*)(\(([^)]*)\))?", RegexOptions.Compiled | RegexOptions.IgnoreCase);
Match fmatch = func2xml.Match(ytFunction);
if(fmatch.Captures.Count != 1){
Console.Write("bad function request string");
return "";
}
flashFunction=fmatch.Groups[1].Value.ToString();
flashXMLrequest = "<invoke name=\"" + flashFunction + "\" returntype=\"xml\">";
if (fmatch.Groups[3].Value.Length > 0)
{
flashFunctionArgs = pars*emphasized text*eDelimitedString(fmatch.Groups[3].Value);
if (flashFunctionArgs.Count > 0)
{
flashXMLrequest += "<arguments><string>";
flashXMLrequest += string.Join("</string><string>", flashFunctionArgs);
flashXMLrequest += "</string></arguments>";
}
}
flashXMLrequest += "</invoke>";
try
{
Console.Write("YTplayer_CallFlash: \"" + flashXMLrequest + "\"\r\n");
response = YTplayer.CallFunction(flashXMLrequest);
Console.Write("YTplayer_CallFlash_response: \"" + response + "\"\r\n");
}
catch
{
Console.Write("YTplayer_CallFlash: error \"" + flashXMLrequest + "\"\r\n");
}
return response;
}
private static List<string> parseDelimitedString (string arguments, char delim = ',')
{
bool inQuotes = false;
bool inNonQuotes = false;
int whiteSpaceCount = 0;
List<string> strings = new List<string>();
StringBuilder sb = new StringBuilder();
foreach (char c in arguments)
{
if (c == '\'' || c == '"')
{
if (!inQuotes)
inQuotes = true;
else
inQuotes = false;
whiteSpaceCount = 0;
}else if (c == delim)
{
if (!inQuotes)
{
if (whiteSpaceCount > 0 && inQuotes)
{
sb.Remove(sb.Length - whiteSpaceCount, whiteSpaceCount);
inNonQuotes = false;
}
strings.Add(sb.Replace("'", string.Empty).Replace("\"", string.Empty).ToString());
sb.Remove(0, sb.Length);
}
else
{
sb.Append(c);
}
whiteSpaceCount = 0;
}
else if (char.IsWhiteSpace(c))
{
if (inNonQuotes || inQuotes)
{
sb.Append(c);
whiteSpaceCount++;
}
}
else
{
if (!inQuotes) inNonQuotes = true;
sb.Append(c);
whiteSpaceCount = 0;
}
}
strings.Add(sb.Replace("'", string.Empty).Replace("\"", string.Empty).ToString());
return strings;
}
adding Youtube event handlers:
private void YTready(string playerID)
{
YTState = true;
//start eventHandlers
YTplayer_CallFlash("addEventListener(\"onStateChange\",\"YTStateChange\")");
YTplayer_CallFlash("addEventListener(\"onError\",\"YTError\")");
}
private void YTStateChange(string YTplayState)
{
switch (int.Parse(YTplayState))
{
case -1: playState = false; break; //not started yet
case 1: playState = true; break; //playing
case 2: playState = false; break; //paused
//case 3: ; break; //buffering
case 0: playState = false; if (!loopFile) mediaNext(); else YTplayer_CallFlash("seekTo(0)"); break; //ended
}
}
private void YTStateError(string error)
{
Console.Write("YTplayer_error: "+error+"\r\n");
}
usage ex:
YTplayer_CallFlash("playVideo()");
YTplayer_CallFlash("pauseVideo()");
YTplayer_CallFlash("loadVideoById(KuNQgln6TL0)");
string currentVideoId = YTplayer_CallFlash("getPlaylist()");
string currentDuration = YTplayer_CallFlash("getDuration()");
The functions YTplayer_CallFlash
, YTplayer_FlashCall
should work for any flash-C# communication with minor adjustments like the YTplayer_CallFlash
's switch (command).
函数YTplayer_CallFlash、YTplayer_FlashCall应该适用于任何flash- c#通信,并进行一些微调,如YTplayer_CallFlash的开关(命令)。
#4
0
This stumped me for a number of hours.
这使我困惑了好几个小时。
Just add enable JS to your URL:
只需将enable JS添加到您的URL:
http://www.youtube.com/v/9bZkp7q19f0?version=3&enablejsapi=1
http://www.youtube.com/v/9bZkp7q19f0?version=3&enablejsapi=1
CallFunction works fine for me now! Also remove unrequired space in the call.
CallFunction现在对我来说很好!还要删除调用中不需要的空间。
#1
5
It sounds like your trying to use Adobe Flash as your interface; then pass certain variables back into C#.
听起来你想用Adobe Flash作为你的界面;然后将某些变量传回c#。
An example would be this:
举个例子:
In Flash; create a button... Actionscript:
在Flash中;创建一个按钮……动作脚本:
on (press) {
fscommand("Yo","dude");
}
Then Visual Studio you just need to add the COM object reference: Shockwave Flash Object
然后Visual Studio只需要添加COM对象引用:Shockwave Flash对象。
Then set the embed to true;
然后将embed设置为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.
在Visual Studio中,你可以进入属性;找到fscommand。fscommand将允许您物理地连接Flash影片中的值。
AxShockwaveFlashObjects._IShockwaveFlashEvents_FSCommandEvent
That collects; then just use e.command
and e.arg
for example to have the collected item do something.
收集;然后使用e。command和e。例如,arg可以让收集的项目做一些事情。
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.
它把数据从Flash传输到Visual Studio。不需要任何疯狂的困难套接字。
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.
从一个方面说明;如果在Visual Studio中有Flash,关键是要确保它的“embed is set to true”。它将保存Flash对象中的所有路径引用;避免任何错误路径的错误。
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.
希望这个有帮助。第一部分实际上应该向您展示将Shockwave嵌入到Visual Studio的最佳方法。
Make sure you add the correct reference:
确保你添加了正确的参考:
- Inside your project open 'Solution Explorer'
- 在你的项目中打开“解决方案资源管理器”
- Right-Click to 'Add Reference'
- 右键单击“添加引用”
- Go to 'COM Object'
- 去“COM对象”
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:
如果你有困难,Ryk有一个帖子;用一种方法嵌入YouTube视频:
<% 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://*.com/questions/2547101/purify-embedding-youtube-videos-method-in-c-sharp
你可以在这里找到这个线程:https://*.com/questions/2547101/purifing -youtube-video -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:
c#编程语言沟通:
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.
然后在c#中;添加ActiveX控件的实例,并将内容添加到构造函数中。
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#:
c# ActionScript沟通:
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:
然后出现XML:
<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.
然后解析事件处理程序中的XML并在本地调用c#函数。
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.
现在它们都来回传递数据。这是一个基本的例子;但是通过使用ActionScript通信,您不应该对使用本机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:
创建一个新的Flash影片;ActionScript 3。然后在第一帧;应用如下:
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.
那么这个脚本到底在做什么呢?它使用本机API并使用ActionScript通信。下面我将分解每一行。
Security.allowDomain("www.youtube.com");
Without that line YouTube won't interact with the object.
如果没有这条线,YouTube将无法与该对象交互。
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.
你不能把一部电影放进电影里;我们将创建一个变量对象。您必须加载一个特殊的.swf,它将包含对这些代码的访问。以下;就是干这个的。你可以访问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.
我们现在根据他们的文档引用谷歌API。
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.
onLoaderInit函数将在初始化时触发。然后它的第一个任务将是my_loader来显示列表,以便显示视频。
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.
addChild(my_loader);是装载一个的;my_player = my_loader.content;将存储一个引用以方便访问对象。
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.
虽然已经初始化;你得再等一等……你用my_player。addEventListener(“onReady”,onPlayerReady);等待并侦听那些自定义事件。这将允许以后的函数处理。
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.
上面的函数开始非常基本的操作。最后一行my_player.loadVideoById(“_OBlgSz8sSM”,0);是指特定的视频。
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.
希望有帮助。
#2
2
I'd start by making sure that javascript can talk to your flash app.
首先,我要确保javascript可以与flash应用对话。
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).
确保在嵌入中设置了:allowScriptAccess=“sameDomain”(来自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.
您应该验证html->flash是否有效;然后C - > html;并逐步计算到C->你管的分量。在C和you-tube组件之间有很多潜在的失败点,很难同时处理所有这些点。
#3
2
After a lot of tries and head-hammering, I've found a solution:
经过多次尝试,我找到了一个解决办法:
Seems that the Error HRESULT E_FAIL...
happens when the flash dosen't understand the requested flash call. Also for the youtube external api to work, the js api needs to be enabled:
似乎错误HRESULT E_FAIL…当flash dosen不理解请求的flash调用时发生。同时,为了让youtube的外部api工作,js api需要启用:
player.movie = "http://www.youtube.com/v/VIDEO_ID?version=3&enablejsapi=1"
As I said in the question the whole program is open source, so you will find the full code at bitbucket.
Any advice, suggestions or collaborators are highly appreciated.
正如我在问题中提到的,整个程序是开源的,所以您可以在bitbucket中找到完整的代码。如有任何建议、建议或合作者,我们将不胜感激。
The complete solution:
Here is the complete guide for embedding and interacting with the YouTube player or any other flash object.
下面是嵌入和与YouTube播放器或任何其他flash对象交互的完整指南。
After following the video tutorial , set the flash player's FlashCall
event to the function that will handle the flash->c# interaction (in my example it's YTplayer_FlashCall
)
在完成本视频教程之后,将flash player的FlashCall事件设置为处理flash->c#交互的函数(在我的示例中是YTplayer_FlashCall)
the generated `InitializeComponent()` should be:
...
this.YTplayer = new AxShockwaveFlashObjects.AxShockwaveFlash();
this.YTplayer.Name = "YTplayer";
this.YTplayer.Enabled = true;
this.YTplayer.OcxState = ((System.Windows.Forms.AxHost.State)(resources.GetObject("YTplayer.OcxState")));
this.YTplayer.FlashCall += new AxShockwaveFlashObjects._IShockwaveFlashEvents_FlashCallEventHandler(this.YTplayer_FlashCall);
...
the FlashCall event handler
private void YTplayer_FlashCall(object sender, AxShockwaveFlashObjects._IShockwaveFlashEvents_FlashCallEvent e)
{
Console.Write("YTplayer_FlashCall: raw: "+e.request.ToString()+"\r\n");
// message is in xml format so we need to parse it
XmlDocument document = new XmlDocument();
document.LoadXml(e.request);
// get attributes to see which command flash is trying to call
XmlAttributeCollection attributes = document.FirstChild.Attributes;
String command = attributes.Item(0).InnerText;
// get parameters
XmlNodeList list = document.GetElementsByTagName("arguments");
List<string> listS = new List<string>();
foreach (XmlNode l in list){
listS.Add(l.InnerText);
}
Console.Write("YTplayer_FlashCall: \"" + command.ToString() + "(" + string.Join(",", listS) + ")\r\n");
// Interpret command
switch (command)
{
case "onYouTubePlayerReady": YTready(listS[0]); break;
case "YTStateChange": YTStateChange(listS[0]); break;
case "YTError": YTStateError(listS[0]); break;
default: Console.Write("YTplayer_FlashCall: (unknownCommand)\r\n"); break;
}
}
this will resolve the flash->c# communication
这将解决flash->c#通信
calling the flash external functions (c#->flash):
private string YTplayer_CallFlash(string ytFunction){
string flashXMLrequest = "";
string response="";
string flashFunction="";
List<string> flashFunctionArgs = new List<string>();
Regex func2xml = new Regex(@"([a-z][a-z0-9]*)(\(([^)]*)\))?", RegexOptions.Compiled | RegexOptions.IgnoreCase);
Match fmatch = func2xml.Match(ytFunction);
if(fmatch.Captures.Count != 1){
Console.Write("bad function request string");
return "";
}
flashFunction=fmatch.Groups[1].Value.ToString();
flashXMLrequest = "<invoke name=\"" + flashFunction + "\" returntype=\"xml\">";
if (fmatch.Groups[3].Value.Length > 0)
{
flashFunctionArgs = pars*emphasized text*eDelimitedString(fmatch.Groups[3].Value);
if (flashFunctionArgs.Count > 0)
{
flashXMLrequest += "<arguments><string>";
flashXMLrequest += string.Join("</string><string>", flashFunctionArgs);
flashXMLrequest += "</string></arguments>";
}
}
flashXMLrequest += "</invoke>";
try
{
Console.Write("YTplayer_CallFlash: \"" + flashXMLrequest + "\"\r\n");
response = YTplayer.CallFunction(flashXMLrequest);
Console.Write("YTplayer_CallFlash_response: \"" + response + "\"\r\n");
}
catch
{
Console.Write("YTplayer_CallFlash: error \"" + flashXMLrequest + "\"\r\n");
}
return response;
}
private static List<string> parseDelimitedString (string arguments, char delim = ',')
{
bool inQuotes = false;
bool inNonQuotes = false;
int whiteSpaceCount = 0;
List<string> strings = new List<string>();
StringBuilder sb = new StringBuilder();
foreach (char c in arguments)
{
if (c == '\'' || c == '"')
{
if (!inQuotes)
inQuotes = true;
else
inQuotes = false;
whiteSpaceCount = 0;
}else if (c == delim)
{
if (!inQuotes)
{
if (whiteSpaceCount > 0 && inQuotes)
{
sb.Remove(sb.Length - whiteSpaceCount, whiteSpaceCount);
inNonQuotes = false;
}
strings.Add(sb.Replace("'", string.Empty).Replace("\"", string.Empty).ToString());
sb.Remove(0, sb.Length);
}
else
{
sb.Append(c);
}
whiteSpaceCount = 0;
}
else if (char.IsWhiteSpace(c))
{
if (inNonQuotes || inQuotes)
{
sb.Append(c);
whiteSpaceCount++;
}
}
else
{
if (!inQuotes) inNonQuotes = true;
sb.Append(c);
whiteSpaceCount = 0;
}
}
strings.Add(sb.Replace("'", string.Empty).Replace("\"", string.Empty).ToString());
return strings;
}
adding Youtube event handlers:
private void YTready(string playerID)
{
YTState = true;
//start eventHandlers
YTplayer_CallFlash("addEventListener(\"onStateChange\",\"YTStateChange\")");
YTplayer_CallFlash("addEventListener(\"onError\",\"YTError\")");
}
private void YTStateChange(string YTplayState)
{
switch (int.Parse(YTplayState))
{
case -1: playState = false; break; //not started yet
case 1: playState = true; break; //playing
case 2: playState = false; break; //paused
//case 3: ; break; //buffering
case 0: playState = false; if (!loopFile) mediaNext(); else YTplayer_CallFlash("seekTo(0)"); break; //ended
}
}
private void YTStateError(string error)
{
Console.Write("YTplayer_error: "+error+"\r\n");
}
usage ex:
YTplayer_CallFlash("playVideo()");
YTplayer_CallFlash("pauseVideo()");
YTplayer_CallFlash("loadVideoById(KuNQgln6TL0)");
string currentVideoId = YTplayer_CallFlash("getPlaylist()");
string currentDuration = YTplayer_CallFlash("getDuration()");
The functions YTplayer_CallFlash
, YTplayer_FlashCall
should work for any flash-C# communication with minor adjustments like the YTplayer_CallFlash
's switch (command).
函数YTplayer_CallFlash、YTplayer_FlashCall应该适用于任何flash- c#通信,并进行一些微调,如YTplayer_CallFlash的开关(命令)。
#4
0
This stumped me for a number of hours.
这使我困惑了好几个小时。
Just add enable JS to your URL:
只需将enable JS添加到您的URL:
http://www.youtube.com/v/9bZkp7q19f0?version=3&enablejsapi=1
http://www.youtube.com/v/9bZkp7q19f0?version=3&enablejsapi=1
CallFunction works fine for me now! Also remove unrequired space in the call.
CallFunction现在对我来说很好!还要删除调用中不需要的空间。