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

时间:2012-11-06 22:21:08

标签: c# .net flash youtube youtube-api

我的目标是制作一个可以通过全球媒体键控制的开源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,所有这些我成功的是使用简单的embedded object version

来激活onYouTubePlayerReady()

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


更新2:


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

4 个答案:

答案 0 :(得分:4)

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

一个例子是:

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

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

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

然后将embed设置为true;

然后在Visual Studio中,您应该可以转到属性;找到fscommand。 fscommand将允许您物理连接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,关键是要确保它的“embed设置为true”。这将保存Flash对象中的所有路径引用;避免误导错误路径。

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

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

确保添加正确的参考:

  1. 在项目内打开'解决方案资源管理器'
  2. 右键点击'添加参考'
  3. 转到'COM对象'
  4. 查找适当的对象;

    COM Objects:
    Shockwave ActiveX
    Flash Accessibility
    Flash Broker
    Shockwave Flash
    

    希望有所帮助。

    听起来你没有正确地嵌入它;所以你可以打电话给它。如果我有点误会;或者这就是你的意思:

    如果你有困难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>") %>
    

    或者...

    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://stackoverflow.com/questions/2547101/purify-embedding-youtube-videos-method-in-c-sharp

    如果我的帖子显得支离破碎,我会道歉;但我无法分辨是否是导致您遇到困难的参考,变量,方法或嵌入。真的希望这会有所帮助;或者给我更多详细信息,我会相应调整我的回复。


    C#to ActionScript Communication:

    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 Communication,您不应该使用本机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 Communication。所以下面我将分解每一行。

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

    如果没有该行,YouTube将不会与该对象进行互动。

    var my_player:Object;
    

    你不能只将电影加载到电影中;所以我们将创建一个变量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);
    

    但是为了真正使用我们的对象;我们需要等待它完全初始化。所以事件监听器会等待;所以我们知道何时可以将命令传递给它。

    初始化时将触发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()
    

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

    希望这会有所帮助。

答案 1 :(得分:2)

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

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

你应该验证html-&gt; flash工作;那么C-> html;并逐步完成C-> you-tube-component。你现在在C和你管组件之间有很多潜在的失败点,并且很难同时解决所有问题。

答案 2 :(得分:2)

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

当闪光灯不理解所请求的闪光通话时,似乎发生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-&gt; 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-&gt; c#通讯

调用flash外部函数(c# - &gt; 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");
}

用法ex:

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的开关(命令)。 />

答案 3 :(得分:0)

这让我困扰了好几个小时。

只需在您的网址中添加启用JS:

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

CallFunction现在可以正常使用!同时删除通话中不需要的空间。