如何用 c# 控制 youtube flash 播放器?

Posted

技术标签:

【中文标题】如何用 c# 控制 youtube flash 播放器?【英文标题】:How to control the youtube flash player with c#? 【发布时间】:2012-10-26 22:57:29 【问题描述】:

我的目标是制作一个可以通过全局媒体键控制的开源 YouTube 播放器。 我得到了解决的全球关键问题,但由于某种原因,YouTube 播放器和我的 Windows 窗体应用程序之间的通信无法正常工作。

到目前为止,这是我所拥有的:

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>");

不幸的是,这会返回:

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

我错过了什么?我应该加载不同的 URL 吗? The documentation 声明 YouTube 播放器使用 ExternalInterface 类javascript 或 AS3 控制它,所以 it should work with c#。

更新:


嵌入播放器的方法:http://www.youtube.com/watch?v=kg-z8JfOIKw

还尝试在 WebBrowser 控件中使用JavaScript-API,但没有运气(玩家只是没有响应 JavaScript 命令,甚至尝试将WebBrowser.url 设置为working demo,我成功的只是得到onYouTubePlayerReady() 使用简单的embedded object version 触发)

我认为可能存在一些我正在监督的安全问题,但我不知道。

更新 2:


喜欢的解决方案,请参阅下面的answer。

【问题讨论】:

所有 CPU 或 64 位可能适用于您的应用程序? 两个都试过了,都没有用...你设法让它工作了吗? 不,抱歉,只是我在使用 COM 时尝试过的一些事情。我猜你也将它设置为 x86 并尝试过。同时启动 ProcessMonitor (sysinternals) 并跟踪它正在查询的注册表项。可以指点一下。 我会试试的,我没有跟踪注册表的经验,我应该寻找什么? 这是我喜欢的:reg:"HKLM\SOFTWARE\Microsoft\CTF\KnownClasses" RegOpenKey NAME NOT FOUND 【参考方案1】:

听起来您正在尝试使用 Adob​​e Flash 作为界面;然后将某些变量传回 C#。

一个例子是这样的:

在 Flash 中;创建一个按钮... Actionscript:

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

然后Visual Studio你只需要添加COM对象引用:Shockwave Flash Object

然后设置embed为true;

然后在 Visual Studio 中你应该可以进入属性;找到 fs 命令。 fs 命令将允许您物理连接 Flash 电影中的值。

AxShockwaveFlashObjects._IShockwaveFlashEvents_FSCommandEvent 

收集;然后只需使用e.commande.arg 来让收集的物品做一些事情。

然后将这个添加到EventHandler中;

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

它正在将数据从 Flash 传输到 Visual Studio。不需要任何疯狂的困难套接字。

附带说明;如果你在 Visual Studio 中有 Flash,关键是要确保它的“嵌入设置为真”。这将保存 Flash 对象中的所有路径引用;以避免任何错误的路径。

我不确定这是否是您寻求的答案;或回答您的问题。但是没有关于你的目标/错误的更多细节。我帮不了你。

希望这会有所帮助。第一部分实际上应该向您展示将 Shockwave 嵌入 Visual Studio 的最佳方式。

确保添加正确的参考:

    在您的项目中打开 'Solution Explorer' 右键单击以“添加参考” 转到'COM 对象'

找到合适的对象;

COM Objects:
Shockwave ActiveX
Flash Accessibility
Flash Broker
Shockwave Flash

希望对您有所帮助。

听起来您没有正确嵌入它;所以你可以打电话给它。如果我稍微弄错了;或者这就是你的意思:

如果您遇到困难,Ryk 不久前有帖子;使用嵌入 YouTube 视频的方法:

<% MyYoutubeUtils.ShowEmebddedVideo("<object  ><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"  ></embed></object>") %>

或者……

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;

你可以在这里找到主题:https://***.com/questions/2547101/purify-embedding-youtube-videos-method-in-c-sharp

如果我的帖子显得支离破碎,我深表歉意;但我不知道是引用、变量、方法还是嵌入给你带来了困难。真的希望这会有所帮助;或者给我更多细节,我会相应地调整我的回复。


C# 到 ActionScript 的通信:

import flash.external.ExternalInterface;
ExternalInterface.addCallback("loadAndPlayVideo", null, loadAndPlayVideo);
function loadAndPlayVideo(uri:String):void

       videoPlayer.contentPath = uri;

然后在 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>");

与 C# 的 ActionScript 通信:

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

flashPlayer.FlashCall += new _IShockwaveFlashEvents_FlashCallEventHandler(flashPlayer_FlashCall);

然后应该出现 XML:

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

然后在事件处理程序中解析 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));

现在它们都在来回传递数据。这是一个基本的例子;但是通过使用 ActionScript 通信,使用本机 API 应该不会有任何问题。

希望对您有所帮助。您可以通过实用程序类扩展该想法以供重用。显然上面的代码有一些限制;但希望它为您指明正确的方向。是你试图去的那个方向吗?还是我还是没抓住重点?


创建一个新的 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);
 

那么这个脚本到底在做什么呢?它利用本机 API 并使用 ActionScript 通信。所以下面我将分解每一行。

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

没有这条线,YouTube 将不会与对象交互。

var my_player:Object;

您不能只将电影加载到电影中;所以我们将创建一个变量对象。您必须加载包含对这些代码的访问权限的特殊 .swf。下面;就是这样做的。这样您就可以访问 API。

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

我们现在根据他们的文档引用 Google API。

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

但是为了实际使用我们的对象;我们需要等待它完全初始化。所以 Event Listener 会等待;所以我们知道什么时候可以向它传递命令。

onLoaderInit 函数将在初始化时触发。然后它的第一个任务将是my_loader 显示列表以便视频出现。

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); 引用特定视频。

然后在你的舞台上;您可以创建两个按钮并应用:

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();

这将为您提供播放和暂停功能。您可以使用我们的一些其他项目:

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

请记住,在完全初始化之前不能使用或调用它们。但是使用它;使用较早的方法应该允许您布局目标并在两者之间实际传递变量以进行操作。

希望这会有所帮助。

【讨论】:

嵌入不是问题,youtube 视频播放,一切都很好,但我想从 c# 控制播放器,然后出现错误。这就是我所在的位置:http://www.youtube.com/watch?v=kg-z8JfOIKw 另外,fscommand 似乎可用于将数据从闪存发送到 c# 但不能返回。我需要一个 2 路通信系统,所以我可以向 Flash 播放器发送命令。如果可能的话,我想使用原始的youtube player api,因为它更容易维护。 在这种情况下,您可以使用 ActionScript 通信文件;这将允许您使用本机 API。但随后传递给 C#,以便可以在本地处理。我将编辑我的回复以反映我的意思;我会添加到底部。 是的,这就是我正在尝试的,但我认为 YouTube 播放器已经嵌入了这个,它使用它与 JavaScript 或其他 AS3/AS2 脚本进行通信,但 flashPlayer.CallFunction 给了我一个错误。 我概述的方式应该可行; YouTube 实际上使用了一个在运行时加载的特殊文件。然后你只需使用 Loader 类;这将允许任何 YouTube 视频播放。我将添加到我编辑的帖子中......【参考方案2】:

我首先要确保 javascript 可以与您的 Flash 应用程序对话。

确保您在嵌入中设置了:allowScriptAccess="sameDomain"(来自 http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/external/ExternalInterface.html#includeExamplesSummary)。

您应该验证 html->flash 是否有效;然后 C->html;并逐渐工作到 C->you-tube-component。你现在在 C 和 youtube 组件之间有很多潜在的故障点,很难同时解决所有这些问题。

【讨论】:

这就是我想要的。 html->flash 有效(在 chrome/firefox/ie9 中但不在 webBrowser 组件中)所以这就是我想通过 AxShockwaveFlash 组件嵌入的原因。所以现在我将尝试获取 c->flash 并看看它是如何进行的。 c->youtube 失败 如果你能做C->JS和JS->flash,看来你一定是对youtube组件有误解。我很确定如果你不能从 flash 中控制他们的 flash 组件,现在有人会注意到 :) 祝你好运! WebBrowser 的 JS 不能正常工作,所以 webBrowserJS->Flash 不行(问题描述的问题)。 C#->webBrowserJS->flash 也是错误的方法。我已经设法让 c#->flash 工作,并将很快发布完整的回复。 啊,太糟糕了。我的专业领域完全在你的范围内,所以我的反馈主要是想知道我是否可以提供任何支持......对不起,我不能提供更多帮助 别担心,所有反馈都很有帮助:)【参考方案3】:

经过多次尝试和锤击,我找到了解决方案:

似乎Error HRESULT E_FAIL... 发生在闪存不理解请求的闪存调用时。此外,要使 youtube 外部 api 正常工作,还需要启用 js api:

player.movie = "http://www.youtube.com/v/VIDEO_ID?version=3&enablejsapi=1"

正如我在问题中所说,整个程序是开源的,因此您可以在 bitbucket 找到完整代码。 非常感谢任何建议、建议或合作者。

完整的解决方案:

这里是嵌入 YouTube 播放器或任何其他 Flash 对象并与之交互的完整指南。

关注video tutorial后 ,将 flash 播放器的 FlashCall 事件设置为将处理 flash->c# 交互的函数(在我的示例中为 YTplayer_FlashCall

生成的`InitializeComponent()`应该是:

...
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);
...

FlashCall 事件处理程序

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;
    

这将解决 flash->c# 通信

调用flash外部函数(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;

添加 Youtube 事件处理程序:

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");

用法示例:

YTplayer_CallFlash("playVideo()");
YTplayer_CallFlash("pauseVideo()");
YTplayer_CallFlash("loadVideoById(KuNQgln6TL0)");
string currentVideoId = YTplayer_CallFlash("getPlaylist()");
string currentDuration = YTplayer_CallFlash("getDuration()");

YTplayer_CallFlashYTplayer_FlashCall 函数应适用于任何 flash-C# 通信,只需稍作调整,例如 YTplayer_CallFlash 的开关(命令)。

【讨论】:

很高兴您找到了解决方案;我的帖子有帮助吗? 不幸的是,我在回答之前就已经从在线研究中知道了这些信息,而且它并不是针对我的问题的。请参阅the *** answering guide 的“回答问题”部分 你写的是parceDelimitedString而不是parseDelimitedString 我收到错误 HRESULT E_FAIL... 虽然我启用了 enablejsapi。 YouTube 似乎不再支持 Flash。 :(。 不知道,我已经4年没有测试过了,谷歌似乎已经弃用了flash+jsapi,你应该检查它是否在浏览器中工作。【参考方案4】:

这让我难过了几个小时。

只需将启用 JS 添加到您的 URL:

http://www.youtube.com/v/9bZkp7q19f0?version=3&enablejsapi=1

CallFunction 现在对我来说很好用!同时删除通话中不需要的空格。

【讨论】:

我知道,想通了,请参阅下面的答案 :) :"要使 youtube 外部 api 工作, js api 需要启用"

以上是关于如何用 c# 控制 youtube flash 播放器?的主要内容,如果未能解决你的问题,请参考以下文章

C# Package Tyrrrz/YoutubeExplode 为 YouTube html5 视频返回错误 403,但不为 flash 视频返回错误

如何用C#设计上位机(小白篇)

如何用JavaScript捕获CSS3的动画事件

如何用火狐浏览器下载youtube上的视屏

unity中如何用c#脚本控制fbx模型骨骼节点的移动?求具体代码

如何用HTML5 的Canvas制作3D动画效果