用< 100行代码向EPUB或Web服务器添加视频回放
介绍 在我 在关于CodeProject的前一篇文章中,我展示了一个简单的EPUB查看器 Android。从那时起,我收到了获取EPUB查看器的请求 显示嵌入在EPUB中的MPEG-4视频,这是EPUB 3.0的一个特性 规范。本文描述了如何使用一些 的局限性。 这篇文章将涵盖: 获得WebView的问题 控件显示视频。构建一个基本的Web服务器 在EPUB主持。 Android的问题/限制 MediaPlayer和如何检查MPEG-4视频的兼容性。 因为这是我前一篇文章的延续,所以我假设你已经读过了。 在WebView中显示视频 从EPUB 3规范,视频内容可以包括在 通过HTML 5视频生成文档。标签。正如EPUB viewer I 提供使用Android的WebView控件来显示内容,它 应该“只是工作了”。不幸的是,它没有。 EPUB查看器有两个问题。首先, WebView没有被配置为显示视频。第二,WebView 不调用WebViewClient.shouldInterceptRequest()来获取视频 内容。 为视频配置WebView很容易(至少对 Android 4.1.2)。给WebView一个WebChromeClient 将PluginState设置为ON_DEMAND。这就需要增加 两行到EpubWebView构造函数 隐藏,复制Code
- public EpubWebView(Context context, AttributeSet attrs) {
- super(context, attrs);
- mGestureDetector = new GestureDetector(context, mGestureListener);
- WebSettings settings = getSettings();
- settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
- // these two lines enable Video
- settings.setPluginState(WebSettings.PluginState.ON_DEMAND);
- setWebChromeClient(new WebChromeClient());
- setWebViewClient(mWebViewClient = createWebViewClient());
- }
我认为shouldInterceptRequest()没有被调用,因为视频回放不是由实际的WebView完成的。 相反,WebView将其委托给MediaPlayer,将视频内容的URI传递给MediaPlayer。 在旧的EPUB查看器中,我们将uri作为文件模式引用提供。所以MediaPlayer在尝试 读取文件,但失败。因为文件不存在“磁盘上”。 不调用shouldInterceptRequest()可以通过让EPUB查看器运行web服务器并更改提供给WebView的uri来引用web服务器来解决。因此,媒体播放器向EPUB viwer发出HTTP请求以获取视频内容。 修改后的代码给出HTTP uri: 隐藏,复制Code
- public static Uri resourceName2Url(String resourceName) {
- return new Uri.Builder().scheme("http")
- .encodedAuthority("localhost:" + Globals.WEB_SERVER_PORT)
- .appendEncodedPath(Uri.encode(resourceName, "/"))
- .build();
- }
惟一需要做的更改是使用“http”方案并添加一个本地主机权威机构,该机构使用服务器监听的端口。 一个基本的Web服务器 网络服务器必须完成以下工作: 侦听传入的请求。解析请求以确定所请求的文件。返回请求的文件。 监听网络请求可以使用java.net.ServerSocket来完成。 这 甲骨文教程 详细描述如何使用ServerSocket。剥离错误处理的代码看起来像这样: 隐藏,收缩,复制Code
- public class ServerSocketThread extends Thread {
- private static final String THREAD_NAME = "ServerSocket";
- private WebServer mWebServer;
- private int mPort;
- public ServerSocketThread(WebServer webServer, int port){
- super(THREAD_NAME);
- mWebServer = webServer;
- mPort = port;
- }
- @Override
- public void run() {
- super.run();
- // create socket, giving it port to listen for requests on
- ServerSocket serverSocket = new ServerSocket(mPort);
- serverSocket.setReuseAddress(true);
- while(isRunning) {
- // wait until a client makes a request.
- // will return with a clientSocket that can be used
- // to communicate with the client
- Socket clientSocket = serverSocket.accept();
- // pass socket on to "something else" that will
- // use it to communicate with client
- mWebServer.processClientRequest(clientSocket);
- }
- }
- public synchronized void stopThread(){
- mIsRunning = false;
- mServerSocket.close();
- }
- }
需要注意的关键一点是accept()是一个阻塞函数。电话不回了 直到客户端连接。如果在应用程序的主线程上调用它,应用程序将暂停。为了避免这种情况,必须在自己的线程上创建ServerSocket。 要创建线程,请从java.lang派生一个类。线程并覆盖run()方法。 另一点需要注意的是,套接字不处理客户机的请求。请求 委托给“mWebServer”对象,该对象被提供给线程的构造函数。 “mWebServer”对象有三个职责: 解析客户端请求以确定客户端请求的操作。执行动作。向客户端返回操作的详细信息。 的org.apache.http.protocol.HttpService 类将处理大部分工作。Apache文档 因为这门课很长。但基本步骤是: 创建一个HttpService。因为为需要处理的HTTP头信息添加拦截器。注册处理程序以执行请求的操作。当接收来自客户机的请求时,使用客户机的套接字调用HttpService的handleRequest()。 一个骨架的网络服务器看起来是这样的: 隐藏,收缩,复制Code
- public class WebServer {
- private static final String MATCH_EVERYTING_PATTERN = "*";
- private BasicHttpContext mHttpContext = null;
- private HttpService mHttpService = null;
- /*
- * @handler that processes get requests
- */
- public WebServer(HttpRequestHandler handler){
- mHttpContext = new BasicHttpContext();
- // set up Interceptors.
- //... ResponseContent is required, or it doesn't work.
- //... Apache docs recommended the others be provided but
- //... they are not strictly needed in this case.
- BasicHttpProcessor httpproc = new BasicHttpProcessor();
- httpproc.addInterceptor(new ResponseContent());
- httpproc.addInterceptor(new ResponseConnControl());
- httpproc.addInterceptor(new ResponseDate());
- httpproc.addInterceptor(new ResponseServer());
- mHttpService = new HttpService(httpproc,
- new DefaultConnectionReuseStrategy(),
- new DefaultHttpResponseFactory());
- HttpRequestHandlerRegistry registry = new HttpRequestHandlerRegistry();
- registry.register(MATCH_EVERYTING_PATTERN, handler);
- mHttpService.setHandlerResolver(registry);
- }
- /*
- * Called when a client connects to server
- * @socket the client is using
- */
- public void processClientRequest(Socket socket) {
- try {
- DefaultHttpServerConnection serverConnection = new DefaultHttpServerConnection();
- serverConnection.bind(socket, new BasicHttpParams());
- mHttpService.handleRequest(serverConnection, mHttpContext);
- serverConnection.shutdown();
- } catch (IOException e) {
- e.printStackTrace();
- } catch (HttpException e) {
- e.printStackTrace();
- }
- }
- }
主要注意事项: , 我们只注册了一个处理程序,因为我们只做了一个操作:返回被请求的文件。我们在构造函数中传入这个处理程序。 处理程序需要返回与URI对应的“文件”。这听起来很像我们的书 类。实际上,我们通过添加一个函数将Book类转换为HttpRequestHandler: 隐藏,复制Code
- @Override
- public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException {
- String uriString = request.getRequestLine().getUri();
- String resourceName = url2ResourceName(Uri.parse(uriString));
- ZipEntry containerEntry = mZip.getEntry(resourceName);
- if (containerEntry != null) {
- InputStreamEntity entity = new InputStreamEntity(mZip.getInputStream(containerEntry), containerEntry.getSize());
- entity.setContentType(mManifestMediaTypes.get(resourceName));
- response.setEntity(entity);
- } else {
- response.setStatusLine(request.getProtocolVersion(), HttpStatus.SC_NOT_FOUND, "File Not Found");
- }
- }
在我们的主活动中,连接网络服务器并启动它运行: 隐藏,复制Code
- private void createWebServer() {
- WebServer server = new WebServer(getBook());
- mWebServerThread = new ServerSocketThread(server, Globals.WEB_SERVER_PORT);
- mWebServerThread.startThread();
- }
MPEG-4规范和Android媒体播放器 你可能会遇到的最后一个问题是Android的MediaPlayer不支持所有的MPEG4文件。 具体来说,android文档说 对于3GPP和MPEG-4容器,moov原子必须在任何mdat原子之前,但必须继承ftyp原子。 这意味着什么(粗略地简化了):MPEG-4由“原子”(在早期的规范中)或“盒子”组成 (当前规范)。moov原子是文件中所有其他原子的索引。特别是mdat原子 用来保存视频数据。mpeg - 4年代pec允许moov原子位于文件的开头或结尾。 然而,当moov原子位于HTTP流的末尾时,MediaPlayer就会出现问题,因为它只有在读取moov原子后才能播放任何内容。 AtomicParsley可用于检查MPEG-4文件,以查看原子是否为MediaPlayer的正确顺序。 如果moov原子位于文件的末尾,那么可以使用“qt-faststart”等工具将“moov”原子移动到MPEG-4的开始位置。 源代码 最新版本的源代码可以从GitHub下载。 运行提供的代码 源代码中包含一个简单的EPUB文件,其中包含一个嵌入的视频文件(workingvideos . EPUB)。我创建了这个文件 知识共享样本EPUB。 通过删除除了一个页面,所有图像音频和视频,然后添加一个视频文件 当EPUB查看器在Android 4.1.2版本的Android模拟器上运行时,可以显示视频。 EPUB查看器需要将此文件安装到SD卡上的一个名为“下载”的目录中。(在DDMS上,路径是“mnt/sdcard/Download”。) 当你的EPUB文件不能工作时该怎么做。 如果您的EPUB不能正常工作,需要我的帮助,请在给我的邮件中提供您遇到问题的EPUB文件的URL。 本文转载于:http://www.diyabc.com/frontweb/news30541.html
用< 100行代码向EPUB或Web服务器添加视频回放的更多相关文章
- 【转】100行代码实现最简单的基于FFMPEG+SDL的视频播放器
FFMPEG工程浩大,可以参考的书籍又不是很多,因此很多刚学习FFMPEG的人常常感觉到无从下手.我刚接触FFMPEG的时候也感觉不知从何学起. 因此我把自己做项目过程中实现的一个非常简单的视频播放器 ...
- 100行代码实现现代版Router
原文:http://www.html-js.com/article/JavaScript-version-100-lines-of-code-to-achieve-a-modern-version ...
- 用JavaCV改写“100行代码实现最简单的基于FFMPEG+SDL的视频播放器 ”
FFMPEG的文档少,JavaCV的文档就更少了.从网上找到这篇100行代码实现最简单的基于FFMPEG+SDL的视频播放器.地址是http://blog.csdn.net/leixiaohua102 ...
- 100行代码实现最简单的基于FFMPEG+SDL的视频播放器(SDL1.x)【转】
转自:http://blog.csdn.net/leixiaohua1020/article/details/8652605 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] ...
- 100行代码让您学会JavaScript原生的Proxy设计模式
面向对象设计里的设计模式之Proxy(代理)模式,相信很多朋友已经很熟悉了.比如我之前写过代理模式在Java中实现的两篇文章: Java代理设计模式(Proxy)的四种具体实现:静态代理和动态代理 J ...
- GuiLite 1.2 发布(希望通过这100+行代码来揭示:GuiLite的初始化,界面元素Layout,及消息映射的过程)
经过开发群的长期验证,我们发现:即使代码只有5千多行,也不意味着能够轻松弄懂代码意图.痛定思痛,我们发现:虽然每个函数都很简单(平均长度约为30行),可以逐个击破:但各个函数之间如何协作,却很难说明清 ...
- 【编程教室】PONG - 100行代码写一个弹球游戏
大家好,欢迎来到 Crossin的编程教室 ! 今天跟大家讲一讲:如何做游戏 游戏的主题是弹球游戏<PONG>,它是史上第一款街机游戏.因此选它作为我这个游戏开发系列的第一期主题. 游戏引 ...
- 100行代码实现HarmonyOS“画图”应用,eTS开发走起!
本期我们给大家带来的是"画图"应用开发者Rick的分享,希望能给你的HarmonyOS开发之旅带来启发~ 介绍 2021年的华为开发者大会(HDC2021)上,HarmonyOS ...
- 100 行代码实现的 JavaScript MVC 样式框架
介绍 使用过 JavaScript框架(如 AngularJS, Backbone 或者Ember)的人都很熟悉在UI(用户界面,前端)中mvc的工作机理.这些框架实现了MVC,使得在一个单页面中实现 ...
随机推荐
- PlayerPrefs
PlayerPrefs http://blog.csdn.net/u011416077/article/details/47334963
- unity2D物理引擎之-Rigidbody 2D
虽然Rigidbody 2D大致上可以看成是Rigidbody的2D化,大部分功能也是一致的,但是还是有一些细节问题. 一些事项: 1.任何添加到同一个 GameObject身上或者其子物体身上的 2 ...
- 1008 Elevator (20 分)(模拟)
The highest building in our city has only one elevator. A request list is made up with N positive nu ...
- 如何利用 docker 快速部署 Mysql 服务
docker 基础教程不再多说,这里只着重讲如何使用 docker 部署 mysql 服务 docker 拉取 访问 dockerhub,搜索关键词 mysql,我这里选择 mysql-server, ...
- Oracle Sqlplus 三项设置
显示sql执行时间:set timing on 显示sql execute plan:set autotrace trace exp 关闭 set autotrace off 设置行宽:set li ...
- 本地模拟 gitlab ci 的 demo 项目
构建好的镜像能跑起来, 项目地址: https://github.com/szliugx/gitlab-ci-local 为了不每次提交,本地可以做一些模拟 gitlab ci 的测试≍,主要实现方式 ...
- Vue的优缺点
使用vue.js做开发快两年了,对vue的优缺点有一点自己的见解,跟大神比不了,但是面试基本够用 vue在国内能被广泛使用的首要原因是它是基于mvvm框架做开发的,mvvm是前端开发中一种很有影响力的 ...
- Javaweb应用中配置错误跳转页面
关于在Javaweb应用中配置错误跳转页面 应用场景,比如服务器的出现404错误,我们想让它返回跳转到我们自定义的错误页面 解决方法: 主要在web.xml文件中进行配置,这里玩的错误页面都单独放在e ...
- Oracle sqlplus中退格键、DEL键、上下左右键无法使用乱码问题
功能描述:Oracle sqlplus中退格键.DEL键.上下左右键无法使用乱码 1.安装readline-8.0 ①下载readline-8.0.tar.gz文件,百度网盘下载路径: https:/ ...
- Linux实战(12):Centos装机常用脚本-进阶版
#!/bin/bash #shell菜单演示 function menu() { echo -e `date` cat <<EOF ---------------------------- ...