André Alves de Lima

Talking about Software Development and more…

Exibindo vídeos do Vimeo e Youtube no Windows Forms e WPF

Hoje em dia é bastante comum gravarmos vídeos mostrando o funcionamento dos nossos aplicativos. Esses vídeos normalmente servem muito bem para o processo de vendas, já que o potencial comprador consegue entender se a aplicação vai suprir ou não as necessidades do seu negócio.

Porém, não é só para isso que servem esses vídeos. Muitas vezes esse tipo de gravação também pode ser útil para treinarmos os usuários que compraram a nossa aplicação. Já pensou que legal seria se publicássemos esses vídeos no Youtube e depois incorporássemos dentro do próprio aplicativo na janela de ajuda? Bem legal, não é mesmo?

Eu tive essa ideia quando um leitor me perguntou como exibir vídeos do Vimeo no Windows Forms. Fui pesquisar e descobri que não existe um componente pronto para isso, mas nós podemos facilmente reproduzir esses tipos de vídeo dentro de um controle WebBrowser.

No artigo de hoje eu vou mostrar para você como exibir vídeos do Vimeo e Youtube no Windows Forms e WPF.

Vimeo no Windows Forms

Como eu mencionei anteriormente, não existe um controle que podemos utilizar especialmente para exibirmos vídeos do Vimeo ou Youtube no Windows Forms ou WPF. A alternativa nesse caso é utilizarmos um controle WebBrowser com o código de embed do vídeo.

Vamos começar criando um projeto do tipo “Windows Forms Application” e, dentro do formulário, vamos adicionar um controle WebBrowser:

Em seguida, no construtor do formulário (ou no evento “Load” caso você esteja trabalhando com VB.NET), temos que configurar a propriedade DocumentText do WebBrowser com um código HTML que exiba o “iframe” contendo o código de embed do Vimeo. Para isso, precisamos primeiramente descobrir o código de embed no site do Vimeo. Você consegue encontrar o código abrindo o vídeo desejado no browser e clicando no botão de compartilhar:

Na janela que se abre, você encontrará o código de embed. Porém, eu recomendo que você customize o código de forma que ele fique o mais simples e enxuto possível. Fazemos isso clicando no botão “Show options” e desmarcando as opções desnecessárias (como “Show text link underneath this video“):

Agora sim, temos o código embed que utilizaremos na nossa aplicação:

Com o código embed em mãos, podemos exibi-lo no nosso controle WebBrowser. Porém, não basta somente configurarmos a propriedade DocumentText do controle com o código de embed. Temos que criar um documento HTML propriamente dito (com as tags html, head, title e body). Veja como podemos montar essa estrutura:

        // C#
        public Form1()
        {
            InitializeComponent();

            var cabecalhoHtml = "<html><head><title></title></head><body>{0}</body></html>";
            var codigoEmbed = @"<iframe src=""https://player.vimeo.com/video/182970337\"" width=""640"" height=""360"" frameborder=""0"" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>";
            webBrowser1.DocumentText = string.Format(cabecalhoHtml, codigoEmbed);
        }
    ' VB.NET
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim CabecalhoHtml = "<html><head><title></title></head><body>{0}</body></html>"
        Dim CodigoEmbed = "<iframe src=""https://player.vimeo.com/video/182970337\"" width=""640"" height=""360"" frameborder=""0"" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>"
        WebBrowser1.DocumentText = String.Format(CabecalhoHtml, CodigoEmbed)
    End Sub

Simples, não? Vamos executar a aplicação para vermos o resultado?

Como você pode perceber, apesar do vídeo ter sido carregado e reproduzido corretamente, alguns scripts do mecanismo do Vimeo não são executados com sucesso no controle WebBrowser do .NET. Como esses scripts não interferem em nada na reprodução do vídeo, o mais fácil é desabilitarmos essas mensagens de erro do controle WebBrowser. Faremos isso configurando a propriedade “ScriptErrorsSuppressed” como “true” antes de setarmos o DocumentText:

            // C#
            webBrowser1.ScriptErrorsSuppressed = true;
            webBrowser1.DocumentText = string.Format(cabecalhoHtml, codigoEmbed);
        ' VB.NET
        WebBrowser1.ScriptErrorsSuppressed = True
        WebBrowser1.DocumentText = String.Format(CabecalhoHtml, CodigoEmbed)

E com essa pequena alteração, ao executarmos o projeto novamente, nós não receberemos mais aquela mensagem de erro que recebemos anteriormente:

OK, o vídeo foi carregado e conseguimos reproduzi-lo, mas será que não dá para dar uma melhorada nesse player? Por exemplo, será que nós não conseguimos ajustar o tamanho do player de forma que ele ocupe todo o espaço disponível do WebBrowser? Sim, isso é possível!

Para fazermos isso, basta configurarmos os elementos “width” e “height” do código embed, levando em consideração o tamanho do nosso controle WebBrowser. Veja só como fica o código:

            // C#
            var cabecalhoHtml = "<html><head><title></title></head><body>{0}</body></html>";
            var codigoEmbed = @"<iframe src=""https://player.vimeo.com/video/182970337\"" width=""{0}"" height=""{1}"" frameborder=""0"" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>";
            codigoEmbed = string.Format(codigoEmbed, webBrowser1.Width - 50, webBrowser1.Height - 50);
            webBrowser1.ScriptErrorsSuppressed = true;
            webBrowser1.DocumentText = string.Format(cabecalhoHtml, codigoEmbed);
        ' VB.NET
        Dim CabecalhoHtml = "<html><head><title></title></head><body>{0}</body></html>"
        Dim CodigoEmbed = "<iframe src=""https://player.vimeo.com/video/182970337\"" width=""{0}"" height=""{1}"" frameborder=""0"" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>"
        CodigoEmbed = String.Format(CodigoEmbed, WebBrowser1.Width - 50, WebBrowser1.Height - 50)
        WebBrowser1.ScriptErrorsSuppressed = True
        WebBrowser1.DocumentText = String.Format(CabecalhoHtml, CodigoEmbed)

E veja só o resultado:

Nota: como o tamanho do player não leva em consideração os controles, temos que descontar alguns pixels para que não tenhamos barras de rolagem no WebBrowser. No código acima, eu descontei 50 pixels na altura e no comprimento.

Youtube no Windows Forms

Agora que já vimos como exibimos vídeos do Vimeo, vamos ver como fazer o mesmo para vídeos do Youtube? A ideia é exatamente a mesma. Nós só temos que pegar o código de embed do vídeo desejado e substituirmos na variável “codigoEmbed“. Por exemplo:

            // C#
            var cabecalhoHtml = "<html><head><title></title></head><body>{0}</body></html>";
            var codigoEmbed = @"<iframe width=""{0}"" height=""{1}"" src=""https://www.youtube.com/embed/WwC-WOqUaIk"" frameborder=""0"" allowfullscreen></iframe>";
            codigoEmbed = string.Format(codigoEmbed, webBrowser1.Width - 50, webBrowser1.Height - 50);
            webBrowser1.ScriptErrorsSuppressed = true;
            webBrowser1.DocumentText = string.Format(cabecalhoHtml, codigoEmbed);
        ' VB.NET
        Dim CabecalhoHtml = "<html><head><title></title></head><body>{0}</body></html>"
        Dim CodigoEmbed = "<iframe width=""{0}"" height=""{1}"" src=""https://www.youtube.com/embed/WwC-WOqUaIk"" frameborder=""0"" allowfullscreen></iframe>"
        CodigoEmbed = String.Format(CodigoEmbed, WebBrowser1.Width - 50, WebBrowser1.Height - 50)
        WebBrowser1.ScriptErrorsSuppressed = True
        WebBrowser1.DocumentText = String.Format(CabecalhoHtml, CodigoEmbed)

Veja o resultado:

E no WPF, como fica?

O controle WebBrowser do WPF é um pouquinho diferente do controle no Windows Forms. A ideia continua sendo a mesma, porém os nomes de algumas propriedades e métodos são diferentes.

A primeira grande diferença que conseguimos notar é que não existe a propriedade “ScriptErrorsSuppressed“! Infelizmente a Microsoft não disponibiliza uma maneira de desabilitarmos as mensagens de script no WebBrowser do WPF. Para conseguirmos desabilitar essas mensagens, temos que recorrer a alternativas sinistras, conforme demonstrado nesta thread do StackOverflow. Uma outra alternativa seria utilizarmos um WindowsFormsHost com um controle WebBrowser do Windows Forms dentro dele.

Outra diferença é que as propriedades “Width” e “Height” do controle WebBrowser retornarão a altura e comprimento desejados, e não os valores reais. Os valores reais ficam armazenados nas propriedades “ActualWidth” e “ActualHeight“. Porém, os valores para essas propriedades só serão calculados quando os controles já tiverem sido desenhados. Isso quer dizer que nós não podemos colocar o código de carregamento do WebBrowser no construtor da janela, mas sim, teremos que utilizar o evento Load da janela.

Por fim, para carregarmos um HTML no controle WebBrowser do WPF, nós chamamos o método “NavigateToString” passando o código HTML desejado.

Para demonstrar tudo isso, vamos criar um novo projeto do tipo “WPF Application” e vamos ajustar o XAML da janela dessa forma:

<Window x:Class="VimeoEYoutube.WPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:VimeoEYoutube.WPF"
        mc:Ignorable="d"
        Title="MainWindow" Height="600" Width="800" Loaded="Window_Loaded">
    <Grid>
        <WebBrowser x:Name="WebBrowser1" Navigated="WebBrowser1_Navigated"/>
    </Grid>
</Window>

Em seguida, vamos para o code-behind, onde adicionaremos o seguinte código:

        // C#
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            var cabecalhoHtml = "<html><head><title></title></head><body>{0}</body></html>";
            var codigoEmbed = @"<iframe src=""https://player.vimeo.com/video/182970337\"" width=""{0}"" height=""{1}"" frameborder=""0"" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>";
            codigoEmbed = string.Format(codigoEmbed, WebBrowser1.ActualWidth - 50, WebBrowser1.ActualHeight - 50);
            WebBrowser1.NavigateToString(string.Format(cabecalhoHtml, codigoEmbed));
        }

        private void WebBrowser1_Navigated(object sender, NavigationEventArgs e)
        {
            SetSilent(WebBrowser1, true);
        }

        public static void SetSilent(WebBrowser browser, bool silent)
        {
            if (browser == null)
                throw new ArgumentNullException("browser");

            // get an IWebBrowser2 from the document
            IOleServiceProvider sp = browser.Document as IOleServiceProvider;
            if (sp != null)
            {
                Guid IID_IWebBrowserApp = new Guid("0002DF05-0000-0000-C000-000000000046");
                Guid IID_IWebBrowser2 = new Guid("D30C1661-CDAF-11d0-8A3E-00C04FC9E26E");

                object webBrowser;
                sp.QueryService(ref IID_IWebBrowserApp, ref IID_IWebBrowser2, out webBrowser);
                if (webBrowser != null)
                {
                    webBrowser.GetType().InvokeMember("Silent", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.PutDispProperty, null, webBrowser, new object[] { silent });
                }
            }
        }


        [System.Runtime.InteropServices.ComImport, System.Runtime.InteropServices.Guid("6D5140C1-7436-11CE-8034-00AA006009FA"), System.Runtime.InteropServices.InterfaceType(System.Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown)]
        private interface IOleServiceProvider
        {
            [System.Runtime.InteropServices.PreserveSig]
            int QueryService([System.Runtime.InteropServices.In] ref Guid guidService, [System.Runtime.InteropServices.In] ref Guid riid, [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.IDispatch)] out object ppvObject);
        }
    ' VB.NET
    Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs)
        Dim CabecalhoHtml = "<html><head><title></title></head><body>{0}</body></html>"
        Dim CodigoEmbed = "<iframe src=""https://player.vimeo.com/video/182970337\"" width=""{0}"" height=""{1}"" frameborder=""0"" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>"
        'Dim codigoEmbed = "<iframe width=""{0}"" height=""{1}"" src=""https://www.youtube.com/embed/WwC-WOqUaIk"" frameborder=""0"" allowfullscreen></iframe>"
        CodigoEmbed = String.Format(CodigoEmbed, WebBrowser1.ActualWidth - 50, WebBrowser1.ActualHeight - 50)
        'WebBrowser1.ScriptErrorsSuppressed = true;
        WebBrowser1.NavigateToString(String.Format(CabecalhoHtml, CodigoEmbed))
    End Sub

    Private Sub WebBrowser1_Navigated(sender As Object, e As NavigationEventArgs)
        SetSilent(WebBrowser1, True)
    End Sub

    Public Shared Sub SetSilent(Browser As WebBrowser, Silent As Boolean)
        If Browser Is Nothing Then
            Throw New ArgumentNullException("Browser")
        End If

        ' get an IWebBrowser2 from the document
        Dim sp As IOleServiceProvider = TryCast(browser.Document, IOleServiceProvider)
        If sp IsNot Nothing Then
            Dim IID_IWebBrowserApp As New Guid("0002DF05-0000-0000-C000-000000000046")
            Dim IID_IWebBrowser2 As New Guid("D30C1661-CDAF-11d0-8A3E-00C04FC9E26E")

            Dim WebBrowser As Object
            sp.QueryService(IID_IWebBrowserApp, IID_IWebBrowser2, WebBrowser)
            If WebBrowser IsNot Nothing Then
                WebBrowser.GetType().InvokeMember("Silent", System.Reflection.BindingFlags.Instance Or System.Reflection.BindingFlags.Public Or System.Reflection.BindingFlags.PutDispProperty, Nothing, WebBrowser, New Object() {Silent})
            End If
        End If
    End Sub


    <System.Runtime.InteropServices.ComImport, System.Runtime.InteropServices.Guid("6D5140C1-7436-11CE-8034-00AA006009FA"), System.Runtime.InteropServices.InterfaceType(System.Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown)> _
    Private Interface IOleServiceProvider
        <System.Runtime.InteropServices.PreserveSig> _
        Function QueryService(<System.Runtime.InteropServices.In> ByRef guidService As Guid, <System.Runtime.InteropServices.In> ByRef riid As Guid, <System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.IDispatch)> ByRef ppvObject As Object) As Integer
    End Interface

Perceba que a ideia do código é exatamente a mesma do que fizemos no Windows Forms. As diferenças estão somente nos detalhes.

Execute a aplicação e veja o resultado:

Para reproduzir um vídeo do Youtube, basta substituir o código de embed apontando para o vídeo desejado (exatamente como fizemos no Windows Forms). Aproveito também para deixar um link para este projeto no CodeProject, no qual o autor implementou um player do Youtube para o WPF (utilizando o controle WebBrowser por trás dos panos, como fizemos neste artigo).

Atenção! Este código não funciona mais para o Youtube!!

Provavelmente devido a mudanças recentes no código de embed do Youtube (estou adicionando essa seção no artigo em outubro de 2017), esse código não está mais funcionando para carregar vídeos dessa plataforma. Os vídeos do Vimeo funcionam corretamente, mas do Youtube você só receberá uma tela preta ao invés do vídeo. Isso ocorre por incompatibilidades do controle WebBrowser no Windows Forms / WPF (que é muito limitado e usa uma engine antiga do IE por trás dos panos). E aí, como sair dessa?

Eu consigo visualizar duas opções:

Utilize um componente COM Flash como apresentado pelo Márcio Fessini no canal dele
Utilize o componente Chromium ao invés do WebBrowser

O Chromium é uma biblioteca que provê a engine do Chrome para utilização em projetos .NET. Com ele você pode seguir o mesmo esquema para carregar o código embed do Youtube através do método “LoadHtml“:

        public Form1()
        {
            InitializeComponent();

            CefSharp.CefSettings s = new CefSharp.CefSettings();
            CefSharp.Cef.Initialize(s);

            var cabecalhoHtml = "<html><head><title></title></head><body>{0}</body></html>";
            var codigoEmbed = @"<iframe width=""{0}"" height=""{1}"" src=""https://www.youtube.com/embed/WwC-WOqUaIk"" frameborder=""0"" allowfullscreen></iframe>";
            codigoEmbed = string.Format(codigoEmbed, webBrowser1.Width - 50, webBrowser1.Height - 50);

            webBrowser1.LoadHtml(string.Format(cabecalhoHtml, codigoEmbed));
        }

Baixe o projeto de exemplo

Para baixar o projeto de exemplo desse artigo, assine a minha newsletter. Ao fazer isso, além de ter acesso ao projeto, você receberá um e-mail toda semana onde eu falo sobre o artigo publicado e ficará sabendo também em primeira mão sobre o artigo da próxima semana, além de receber dicas “bônus” que eu só compartilho por e-mail. Inscreva-se utilizando o formulário no final do artigo.

Concluindo

Reproduzir vídeos do Vimeo ou Youtube nas nossas aplicações Windows Forms ou WPF não é uma tarefa muito difícil. Apesar de não termos controles específicos que implementem essa funcionalidade, graças aos códigos de embed, nós conseguimos facilmente utilizar um controle WebBrowser para reproduzirmos qualquer vídeo que quisermos.

No artigo de hoje você aprendeu a exibir vídeos dessas duas plataformas tanto no Windows Forms quanto no WPF. Você viu também como desabilitar a mensagem de erro de script disparada ao carregarmos um vídeo do Vimeo no controle WebBrowser. Por fim, você aprendeu a ajustar automaticamente o código de embed para que o player ocupe o espaço todo do WebBrowser.

E aí, será que essa funcionalidade não pode ser útil no seu aplicativo? Imagine que você tenha gravado e publicado no Youtube um tutorial mostrando o funcionamento da sua aplicação. Que tal incorporar esse vídeo na janela de ajuda do seu aplicativo? Uma boa ideia, não é mesmo? Me avisa nos comentários se você gostou desse artigo.

Até a próxima!

André Lima

Newsletter do André Lima

* indicates required



Powered by MailChimp

8 thoughts on “Exibindo vídeos do Vimeo e Youtube no Windows Forms e WPF

  • Daniel Lion disse:

    Excelente artigo, me ajudou bastante. Hoje meus clientes acessam tutoriais em vídeo, diretamente da aplicação.

    Valeu André, abraços.

  • Marcio Maciel disse:

    no WPF recomendo usar o CefSharp (Chrome). Além de evitar os erros de JS e etc do IE do WebBrowser, não precisa apelar para a Interop e ainda tem uma engine mais atual.

    • andrealveslima disse:

      Fala Marcio, muito obrigado pela dica! Não conhecia o CefSharp, mas pareceu ser bastante interessante.. Vou colocar aqui na minha lista para dar uma investigada..

      Abraço!
      André Lima

  • José disse:

    Boa tarde, gostaria de saber se é possivel rodar videos do openload ou ok.ru com vb.net, tentei de todas maneiras e não obtive resultado, aguardo resposta, obrigad

  • Celio Morikoshi disse:

    André! Mais uma vez estou recorrendo aos seus tutoriais, sei que deve ser algum erro bobo, mas quando clico no botão para abrir o form com o vídeo aparece uma tela preta, alguém já perguntou sobre este erro?

    • andrealveslima disse:

      Olá Celio!

      Realmente fui testar o mesmo projeto que eu compartilhei aqui (e que estava funcionando perfeitamente em janeiro desse ano), só que ele não está mais funcioando corretamente.. Ele realmente está exibindo uma janela preta ao invés do vídeo.. Acredito que isso deva ter ocorrido por mudanças no jeito que o Youtube faz embed de vídeos (eles mudaram recentemente algumas coisas)..

      Nesse caso, eu vejo duas alternativas:

      Utilizar um componente COM Flash como apresentado pelo Márcio Fessini no canal dele
      Utilizar o componente Chromium ao invés do WebBrowser

      Eu adicionei uma seção aqui no artigo onde eu mostro rapidamente como ficou o código utilizando a biblioteca Chromium.. Com ela o vídeo do Youtube é carregado normalmente.. Dá uma olhada ali em cima na última seção do artigo..

      Abraço!
      André Lima

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *