用< 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,使得在一个单页面中实现 ...
随机推荐
- python笔记-标准库unittest
unittest核心工作原理 unittest中最核心的四个概念是:test case, test suite, test runner, test fixture. 一个TestCase的实例就是一 ...
- openssl1.0在mac下的编译安装(踩坑精华)
之前做了一次brew版本升级,然后用pip3安装的一个python命令就无法执行了(涉及到openssl库),执行就会报一个错误. ImportError: dlopen(/usr/local/Cel ...
- K - Queries for Number of Palindromes(区间dp+容斥)
You've got a string s = s1s2... s|s| of length |s|, consisting of lowercase English letters. There a ...
- 【问题】Java和Scala混合编译下无法正常使用lombok的问题
工作中有java和scala和混合编译的工程,最近遇到一个问题,就是工程中有依赖java bean的scala文件,编译过程中发现编译器无法找到Java bean 中 lombok生成的getter, ...
- DVWA_sql injection(low)
这里主要记录下做题时的思路以及步骤,不查看源码也不对源码进行分析.(我这个dvwa是一个在线靶场,所以我也不确定是否与本地靶场有些许出入) 1.Low 将难度调为Low级别后,来到如下界面 首先输入一 ...
- 汽车芯片如何高效符合ISO 26262功能安全标准
汽车芯片和集成电路(IC)是高级驾驶员辅助系统(advanced driver assistance systems-ADAS)和联网自动驾驶汽车(connected autonomous veh ...
- [Python]在当前目录下创建三个目录
import os os.mkdir("2018-03-16-b018") os.mkdir("2019-03-16-b019") os.mkdir(" ...
- upstream--负载
语法格式: upstream 负载名 { [ip_hash;] server ip:port [weight=数字] [down]; server ip:port [weight=数字]; } ...
- [LeetCode]1071. 字符串的最大公因子(gcd)
题目 对于字符串 S 和 T,只有在 S = T + ... + T(T 与自身连接 1 次或多次)时,我们才认定 "T 能除尽 S". 返回最长字符串 X,要求满足 X 能除尽 ...
- Hadoop入门学习整理(三)
1.Hive 的安装 下载tar包,并且要注意和Hadoop版本兼容. 下载 -----> 传输 -------> 解压 即可. 然后配置环境变量和相关配置信息. 参考: ...