CEF 自定义用户协议(scheme)实现以二进制流的方式显示图片、视频、音频

转载:https://www.cnblogs.com/sinceret/p/10417941.html

转载:https://stackoverflow.com/questions/48811756/registering-custom-backend-scheme-is-not-working-in-cef

转载:https://www.twblogs.net/a/5c308e03bd9eee35b3a4d59a/zh-cn

转载:http://www.voidcn.com/article/p-ffanxazs-bpp.html

转载:https://magpcss.org/ceforum/viewtopic.php?f=6&t=13266

转载:https://github.com/gabyx/ExecutionGraph/tree/3ff8b340d3ae1c87976104f0bbbda4c048e7eb2b(Github上Demo)

转载:https://blog.csdn.net/ming19951224/article/details/81807159(解决思路参考)

转载:https://blog.csdn.net/cdx1170776994/article/details/76571535

转载:https://blog.csdn.net/zhangpeng_linux/article/details/85858814

转载:https://www.cnblogs.com/himax/p/how_to_intercept_response_in_cef_using_csharp.html

在谷歌浏览器中点击设置,地址栏里出现的不是普通网址,而是chrome://settings/,这个地址就是谷歌浏览器的自定义scheme,cef也提供了自定义协议手段。

scheme就是一种协议,比如http://helloworld.com中的http就是scheme,不过它是内置的。client://helloworld.com中的client就是一个自定义scheme。

当javascript通过XMLHttpRequest请求地址client://helloworld.com时,我们c++中实现的处理器,就会收到这个请求。

XMLHttpRequest可以通过post方法将二进制数据如arraybuffer发送到browser进程。
1.当javascript需要传递大量二进制数据给browser进程的c++代码时,可以使用POST方法,
2.当javascript需要从browser进程的c++代码拿到大量二进制数据时,可以使用GET方法。

1.CEF注册custom scheme 来接受http请求

 在cef中我们可以通过以下接口来注册scheme

bool CefRegisterSchemeHandlerFactory(
    const CefString& scheme_name,
    const CefString& domain_name,
    CefRefPtr<CefSchemeHandlerFactory> factory);

注册一个自定义http scheme

CefRegisterSchemeHandlerFactory("http", "test", new MySchemeHandlerFactory());

这个scheme限定了,scheme为"http",domain为"test",只有当请求为"http://test/"开头时,才会执行自定义c++代码。

处理器工厂为MySchemeHandlerFactory,是我们自己实现的处理请求的c++代码。

继承一个工厂类MySchemeHandlerFactory : public CefSchemeHandlerFactory 

需要包含#include "include/cef_scheme.h"

 .h文件

#ifndef _MYSCHEMEHANDLERFACTORY_H_
#define _MYSCHEMEHANDLERFACTORY_H_
#include "include\cef_scheme.h"


class MySchemeHandlerFactory : public CefSchemeHandlerFactory
{
public:
    virtual CefRefPtr<CefResourceHandler> Create(CefRefPtr<CefBrowser> browser,
        CefRefPtr<CefFrame> frame,
        const CefString& scheme_name,
        CefRefPtr<CefRequest> request)
        OVERRIDE;// Return a new resource handler instance to handle the request.
        
    
private:
    IMPLEMENT_REFCOUNTING(MySchemeHandlerFactory);
};



#endif //_MYSCHEMEHANDLERFACTORY_H_

.cpp文件

#include "MySchemeHandlerFactory.h"
#include "MyResourceHandler.h"
#include "include/cef_parser.h"
#include "include/wrapper/cef_helpers.h"
#include "include/wrapper/cef_stream_resource_handler.h"
#include <shlwapi.h> 
#pragma comment(lib, "shlwapi.lib")

CefRefPtr<CefResourceHandler> MySchemeHandlerFactory::Create(CefRefPtr<CefBrowser> browser, 
    CefRefPtr<CefFrame> frame, 
    const CefString& scheme_name, 
    CefRefPtr<CefRequest> request)
{
    CEF_REQUIRE_IO_THREAD();

    CefString url = request->GetURL();
    cef_uri_unescape_rule_t unescape_rule = UU_SPACES;//处理路径中有空格
    CefString& decoded_value = CefURIDecode(url, true, unescape_rule);

    CefURLParts urlParts;
    if (CefParseURL(url, urlParts))
    {
        std::wstring filePath = CefURIDecode(CefString(&urlParts.query),true,unescape_rule);//处理有中文路径
        CefRefPtr<CefStreamReader> fileStream = CefStreamReader::CreateForFile(CefString(filePath));

        if (fileStream != nullptr)
        {
            // "ext" 获取扩展名 例如:"txt"、"jpg"
            std::wstring ext;
            ext = PathFindExtension(filePath.c_str());
            ext =ext.substr(1, ext.length());
            CefString mimeType(CefGetMimeType(ext));
            //todo: Complete known mime times with web-font extensions
            if (mimeType.empty())
            {
                //mimeType = "font/" + fileExtension;
            }

            return CefRefPtr<CefStreamResourceHandler>(new CefStreamResourceHandler(mimeType, fileStream));//以二进制流的方式把文件返给js并显示到html标签中
        }
    }

    return new MyResourceHandler();
}

 

2.继承一个资源类class MyResourceHandler : public CefResourceHandler

ProcessRequest 处理请求,允许请求返回true;取消请求返回false。当需要返回的数据就绪后(自行请求网络或者文件就绪)或立即调用callback.Continue(),通知cef进入下一步:GetResponseHeaders。

GetResponseHeaders 设置响应头,在这里可以设置mime-type,响应长度,其它头等。不确定长度设置响应长度为-1。

ReadResponse 设置响应结果。可以设置响应具体内容,设置已读取长度。cef调用完上一步后会继续调用此方法。根据响应长度和数据就绪情况,调用此方法的次数和策略不同。

当响应长度为-1时,cef无法根据已读长度确定是否已读取完毕,必需根据返回值false来结束读取。

当响应长度大于0时,cef根据每次调用得到的已读长度,或返回值false来结束读取。

如果数据未就绪,可以设置读取长度为0 ,返回true,并在稍后调用callbak.Continue()通知cef调用此方法读取响应内容。

注意:

当响应长度为-1时,必需保证此方法至少执行两次,第一次返回true表示数据全部就绪,第二次返回false表示读取结束。

当响应长度大于0时,设置内容和已读长度,返回true。则此方法只执行一次。

若实际返回的响应内容,长度大于之前设置的响应总长度,则返回内容将被截取。

 

#ifndef _MYRESOURCEHANDLER_H_
#define _MYRESOURCEHANDLER_H_
#include <fstream>
#include <stdio.h>
#include "include\cef_resource_handler.h"

class MyResourceHandler : public CefResourceHandler
{
public:
    MyResourceHandler();

    virtual bool ProcessRequest(CefRefPtr<CefRequest> request,
        CefRefPtr<CefCallback> callback)OVERRIDE;

    virtual void GetResponseHeaders(CefRefPtr<CefResponse> response,
        int64& response_length,
        CefString& redirectUrl) OVERRIDE;

    virtual void Cancel() OVERRIDE{
        // Cancel the response...
    }

    virtual bool ReadResponse(void* data_out,
        int bytes_to_read,
        int& bytes_read,
        CefRefPtr<CefCallback> callback)
        OVERRIDE;

    virtual bool CanGetCookie(const CefCookie& cookie);
    

    virtual bool CanSetCookie(const CefCookie& cookie);
    
private:
    std::string data_;
    IMPLEMENT_REFCOUNTING(MyResourceHandler);
};
#endif//_MYRESOURCEHANDLER_H_

 

.cpp文件

#include "MyResourceHandler.h"

MyResourceHandler::MyResourceHandler()
{

}


bool MyResourceHandler::ProcessRequest(CefRefPtr<CefRequest> request,
    CefRefPtr<CefCallback> callback)
    {
    std::string url = request->GetURL();
    
    data_ = "hello cef";//返回到页面中的内容
    callback->Continue();//这个一定要有
    return true;//
}

void MyResourceHandler::GetResponseHeaders(CefRefPtr<CefResponse> response,
    int64& response_length,
    CefString& redirectUrl) {

    response->SetMimeType("text/plain");
    response->SetStatus(200);
    response_length = data_.length();
}


bool MyResourceHandler::ReadResponse(void* data_out,
    int bytes_to_read,
    int& bytes_read,
    CefRefPtr<CefCallback> callback)
    {
    int size = static_cast<int>(data_.length());
    memcpy(data_out, data_.c_str(), size);
    bytes_read = size;
    return true;
}

bool MyResourceHandler::CanGetCookie(const CefCookie& cookie)
{
    return false;
}

bool MyResourceHandler::CanSetCookie(const CefCookie& cookie)
{
    return false;
}

 

3.在初始化cef那几行代码后面增加一句

CefRegisterSchemeHandlerFactory("http", "test", new MySchemeHandlerFactory());

 

CefSettings cSettings;
    const char* loc = "zh-CN";

    cSettings.no_sandbox = true;
    cSettings.multi_threaded_message_loop = true;
    //cSettings.single_process = false;
    cSettings.log_severity = LOGSEVERITY_DISABLE;//设置日志级别,解决安装启动佰卓数安后桌面出现一个debug.log文件(调试阶段可以去掉)
    CefString(&cSettings.locale).FromASCII(loc);
    cef_string_from_ascii(loc, strlen(loc), &cSettings.locale);

    // Execute the secondary process, if any.
    CefInitialize(main_args, cSettings, spApp.get(), sandbox_info);
    /***************************************结束初始化cef*******************************************/
    //自定义scheme    
    CefRegisterSchemeHandlerFactory("http", "test", new MySchemeHandlerFactory());

 

4.CEF浏览器加载的静态html

<html>
<script>
function do_post()
{
   //alert('posting');
   var xhr  = new XMLHttpRequest();
   var zurl = "http://test?C:\\Users\\Administrator\\Desktop\\梅西.jpg";
   xhr.open("GET", zurl, true);
   xhr.responseType = 'blob';
   xhr.onload = function()
   {
    //console.log(this);
    if (this.status == 200) 
    {
        var blob = this.response;
        var img = document.createElement("img");
        img.onload = function(e) {
            window.URL.revokeObjectURL(img.src); 
        };
        //alert(blob);
        img.src = window.URL.createObjectURL(blob);
        document.body.appendChild(img); 
    }
   }
   xhr.send();
   //alert('posted');
}

function do_video()
{
   //alert('posting');
   var xhr  = new XMLHttpRequest();
   var zurl = "http://test?C:\\Users\\Administrator\\Desktop\\稻香.mp4";
   xhr.open("GET", zurl, true);
   xhr.responseType = 'blob';
   xhr.onload = function()
   {
    //console.log(this);
    if (this.status == 200) 
    {
        var blob = this.response;
        var video = document.querySelector("video");
        //alert(window.URL.createObjectURL(blob));
        video.src = window.URL.createObjectURL(blob);
  
    }
   }
   xhr.send();
   //alert('posted');
}

function do_audio()
{
   //alert('posting');
   var xhr  = new XMLHttpRequest();
   var zurl = "http://test?C:\\Users\\Administrator\\Desktop\\千年等一回.mp3";
   xhr.open("GET", zurl, true);
   xhr.responseType = 'blob';
   xhr.onload = function()
   {
    //console.log(this);
    if (this.status == 200) 
    {
        var blob = this.response;
        var audio = document.querySelector("audio");
        //alert(window.URL.createObjectURL(blob));
        audio.src = window.URL.createObjectURL(blob);
  
    }
   }
   xhr.send();
   //alert('posted');
}

</script>
<body onLoad="">
<div>
<!-- <img src="图片路径、地址" alt="" /> -->
<input type="button" value="加载图片" onclick="do_post()">
<input type="button" value="加载视频" onclick="do_video();">
<input type="button" value="加载音频" onclick="do_audio();">
</div>
<video controls="true" ></video> 
<audio controls="true" ></audio>
<p>Hello everyone!
</p>
</body>
</html>

 

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: WinForms CefSharp 113.1.40 是一个基于Chromium的.NET框架,用于嵌入一个自定义浏览器控件到Windows应用程序中。如果你想要支持视频播放功能,你需要进行一些额外的工作。 首先,你需要添加一个名为libcef.dll的动态链接库文件,该文件是CefSharp的核心组件之一,它提供了与Chromium进行交互的功能。你可以通过从CefSharp中文官方GitHub仓库中下载合适版本的CefSharp包来获取该文件。 一旦你有了libcef.dll文件,你需要将它复制到你的项目的输出目录中,或将其放置在你的应用程序的可执行文件所在的同一目录下。这是为了确保系统能够找到这个文件。 接下来,你需要在你的WinForms项目中引用CefSharp类库。你可以通过使用NuGet包管理器来添加CefSharp.WinForms和CefSharp.Common的引用。 一旦你完成了引用,你需要在你的WinForms的代码中创建一个CefSharp控件,并在需要显示浏览器的地方将其添加到你的窗体中。你可以使用类似下面的代码来完成: ``` using CefSharp; using CefSharp.WinForms; public class MyBrowserForm : Form { private ChromiumWebBrowser browser; public MyBrowserForm() { browser = new ChromiumWebBrowser("https://www.example.com"); Controls.Add(browser); } } ``` 以上代码将创建一个带有浏览器控件的窗体,并显示指定的URL。 至此,你已经成功创建了一个基本的自定义浏览器控件,通过CefSharp可以在你的WinForms应用程序中显示网页。如果你要支持视频播放功能,你可以在页面中嵌入HTML5的video标签或使用Flash等其他技术来实现。然后,CefSharp将能够解析并呈现这些视频。 综上所述,通过使用WinForms CefSharp 113.1.40,你可以创建一个自定义浏览器控件,并支持视频播放。为此,你需要添加libcef.dll文件到你的项目中,引用CefSharp类库,并在你的代码中创建和配置浏览器控件。希望这些信息对你有帮助。 ### 回答2: WinForm-CefSharp是一种用于嵌入Chromium浏览器的库,而CEFSharp 113.1.40是其特定版本。若想实现视频播放功能,可能需要自定义浏览器以支持视频播放DLL。 首先,需要添加CEFSharp.Wpf和其他相关库的引用来创建WinForm-CefSharp应用程序。然后,我们可以添加一个自定义的ChromiumWebBrowser控件到窗体,并将其设置为允许媒体播放。 CEFSharp支持通过CefSettings配置浏览器的各种选项。我们可以通过设置CefSettings的Plugins属性来允许浏览器加载插件。此属性可接受一个插件文件夹的路径作为参数,即希望支持的DLL文件所在的目录。 在加载CEFSharp之前,我们需要确保要加载的DLL文件已经添加到项目中,并设置其属性为始终复制。这样,在运行应用程序时,相关的DLL文件将被复制到输出目录。 接下来,我们需要处理CefSharp控件的LoadingStateChanged事件,并在事件处理程序中判断当前加载的URL类型。当加载的URL为媒体文件(例如视频)时,我们可以执行一些自定义操作,例如显示播放器控件、设置播放器的源文件等。 最后,我们可以使用CefSharp控件的ExecuteScriptAsync方法调用JavaScript代码来控制视频播放。通过执行一些相关的JavaScript函数,我们可以实现自定义视频控制功能,如播放、暂停、跳转等。 总之,要实现WinForm-CefSharp应用程序的自定义浏览器支持视频播放DLL,我们需要添加CEFSharp和其他相关库的引用,设置浏览器的配置选项以支持插件加载,确保相关的DLL文件已添加到项目中并设置为始终复制,处理LoadingStateChanged事件来判断并控制加载的URL类型,以及通过执行JavaScript代码来实现自定义视频播放功能。 ### 回答3: Winform-CefSharp是一个用于在Winform应用程序中嵌入Chromium浏览器的开源库。要实现自定义浏览器支持视频播放DLL,可以按照以下步骤操作。 首先,确保已经将CefSharp集成到你的Winform应用程序中。你需要在项目中引用CefSharp的相关dll文件,以及解决依赖关系。 接下来,创建一个自定义CefSharp浏览器控件,您可以继承CefSharp.WinForms.ChromiumWebBrowser类并重写一些必要的方法。例如,你可以重写OnBeforeResourceLoad方法来拦截特定视频资源的加载请求。 在你的自定义控件中实现视频播放的逻辑。你可以通过调用CEF浏览器引擎 提供的相关方法来实现视频播放的支持。例如,你可以使用CefBrowserHost.GetFrame函数获取浏览器的当前帧,然后通过调用LoadUrl方法加载视频链接。 另外,你还需要添加将视频URL传递给CefSharp浏览器控件的方法。你可以在自定义的控件中添加一个方法,用于接收调用者传递的视频URL,并将其传递给CefSharp浏览器控件。 最后,在你的Winform应用程序中使用自定义CefSharp浏览器控件。将该控件添加到你的界面中,并在需要的时候调用相关方法来加载和播放视频。 总结来说,要实现自定义浏览器支持视频播放DLL,你需要集成CefSharp到你的Winform应用程序中,创建自定义CefSharp浏览器控件,并在其中实现视频播放的逻辑。然后,在你的应用程序中使用该自定义控件来加载和播放视频。这样就可以实现自定义浏览器支持视频播放DLL的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值