王骏的博客 http://blog.okbase.net/JO2000 chrome浏览器html5播放rtsp视频实现视频直播 http://blog.okbase.net/JO2000/archive/56692.html JO2000 2018/7/21 20:57:01 海康、大华等摄像机都支持rtsp视频,但chrome无法直接播放rtsp视频,需要转码为rtmp视频流。

 

1) 单一视频
可以使用vlc软件进行串流,实现转码。


html5页面的代码如下:
<video autoplay width="640" height="480" controls="controls">
<source src="http://127.0.0.1:8080/test" type="video/mp4">
</video>

 

海康新款相机rtsp格式如下:
rtsp://admin:12345@NVR或摄像机IP地址:554/Streaming/Channels/101?transportmode=unicast
老款摄像机格式是不同的,需要注意。

 

对于多路视频,因vlc无法同时处理多路视频输入输出,只能采用其它方案。

 

2)开源方案

常见的流媒体解决方案有:

流媒体解决方案 Live555(C++)
流媒体平台框架 EasyDarwin(C++)
实时流媒体播放服务器程序DarwinStreamingSrvr(C++)
流媒体实时传输开发包 jrtplib
多媒体处理工具 ffmpeg
多媒体编码工具包Libav
Flash流媒体服务器 Red5(Java)
流媒体服务器 Open Streaming Server (Java)
FMS流媒体服务器(Adobe,收费的)
Wowza流媒体服务器(Java)
开源流媒体平台FreeCast(Java)

 

采用:Nginx-rtmp流媒体服务器+使用ffmpeg推流来搭建直播平台是比较常见的一种形式。

 

3) 商业解决方案
例如easynvr,网址是http://www.easynvr.com/
价格有点贵 10路视频授权,需要2500元,但无疑是一种迅速搭建平台的途径。

 

]]>
记一次PHP站点迁移后页面及图片显示异常的问题处理 http://blog.okbase.net/JO2000/archive/56661.html JO2000 2018/5/26 22:16:32 一、站点从A服务器迁移到B服务器,页面无法打开。

分析代码发现,输出是经过gzip压缩的,而B站点并没有启用gzip。启用后恢复正常。启用步骤如下:

 

1) 打开php.ini配置文件,找到zlib.output_compression = Off,将

zlib.output_compression = Off
;zlib.output_compression_level = -1
修改成,其中zlib.output_compression_level = 6 中的数字6是压缩比例

zlib.output_compression = On
zlib.output_compression_level = 6

 

2) 打开apache 配置文件httpd.conf,配置装载deflate_module,找到

#LoadModule deflate_module modules/mod_deflate.so
把前面的注释“#”号去掉


二、imagepng或imagejpeg浏览器无显示问题
A服务器的验证码图片显示正常,迁移后无法显示。
分析从B服务器返回的图片数据,发现文件头多了些数据,怀疑是输出缓冲的问题。
在图片输出前添加ob_end_clean();恢复正常。

为什么同样的代码在A服务器没有问题呢?因为A服务器的php.ini中output_buffering = Off,默认关闭了缓存。
而B服务器output_buffering = 4096,缓冲是打开的。

]]>
JSON开源库Jackson介绍及下载 http://blog.okbase.net/JO2000/archive/56660.html JO2000 2018/5/24 12:02:11 本文根据:https://javaarm.com/faces/display.xhtml?tid=3828 改写
 

Jackson fasterxml和codehaus的区别:


他们是Jackson的两大分支、也是两个版本的不同包名。Jackson从2.0开始改用新的包名fasterxml;1.x版本的包名是codehaus。除了包名不同,他们的Maven artifact id也不同。1.x版本现在只提供bug-fix,而2.x版本还在不断开发和发布中。如果是新项目,建议直接用2x,即fasterxml jackson。

P.S.
Jackson可以轻松的将Java对象转换成json对象和xml文档,同样也可以将json、xml转换成Java对象。

三个主要的模块:
jackson-core:核心包
jackson-annotations:注解包
jackson-databind:数据绑定包
jackson-databind需要引用另外两个包,所以如果项目中需要jackson-databind,则只需要加入它的dependency就行了,其他两个会自动引入:
<dependency>
<groupId>com.fasterxml.jackson.
core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.5.3</version>
</dependency>

 

概述

Jackson是一个用于将JSON格式数据 和 Java Bean进行映射的第三方软件库。

官方地址:https://github.com/FasterXML/jackson

Jackson由多个子模块构成:
  • Streaming (docs) ("jackson-core") 定义底层的数据流API,包括JSON规范实现
  • Annotations (docs) ("jackson-annotations") 包含标准的Jackson注解
  • Databind (docs) ("jackson-databind") 基于streaming 包实现了数据绑定 (以及对象序列化功能) 支持;它依赖 streaming 和 annotations 包
对JAXB的支持:Jackson JAX-RS Providers

官方源码下载:
二进制下载
javaarm备份

Jackson用法

摘自: http://javaarm.com/faces/display.xhtml?tid=3696&page=1#post_45078
Jackson2框架。它有一个预先编写好的JAX-RS内容处理器(handler),可以自动地在Java beans和JSON之间进行转换。它也可以根据一个Java对象模型生成JSON schema文档。默认情况下,其工作原理是:它会探测你的Java类,查找各个属性,并将这些属性映射成JSON。比如,如果我们有如下的Java类:
public class Customer {
    private int id;
    private String firstName;
    private String lastName;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}
以及简单的数据:
{
    "id" : 42,
    "firstName" : "Bill",
    "lastName" : "Burke"
}
读取该数据从而创建一个Customer的操作就会很简单,如下:
ObjectMapper mapper = new ObjectMapper();
Customer cust = mapper.readValue(inputStream, Customer.class);
输出数据很简单,如下:
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(outputStream, customer);
Jackson框架的JAX-RS集成实际上为你执行了所有的工作,因此,你在你的JAX-RS类中需要做的就是:在编写你的JAX-RS方法时,将输入和输出格式指定为"application/json"。
]]>
Java读取相对路径下的文件 http://blog.okbase.net/JO2000/archive/56658.html JO2000 2018/5/23 22:24:17 例如,文件在 项目目录\src\config\jdbc-mysql.properties
生成后是位于 项目目录\build\classes\config\jdbc-mysql.properties

ClassLoader classLoader = getClass().getClassLoader();
String classespath = classLoader.getResource("/").getPath();
此时,classespath是classes的路径,读入文件代码如下:
FileInputStream fileInputStream = new FileInputStream(classespath + "/config/jdbc-mysql.properties");
properties.load(fileInputStream);

 

各种情形:
getResourceAsStream:
(1) 要加载的文件和.class文件在同一目录下,例如:com.x.y 下有类Test.class ,同时有资源文件config.properties
那么,应该有如下代码:
//前面没有“/”代表当前类的目录
InputStream is1 = Test.class.getResourceAsStream("config.properties");
System.out.println(is1);// 不为null

(2)在Test.class目录的子目录下,例如:com.x.y 下有类Test.class ,同时在 com.x.y.prop目录下有资源文件config.properties
那么,应该有如下代码:
//前面没有“/”代表当前类的目录
InputStream is2 = Test.class.getResourceAsStream("prop/config.properties");
System.out.println(is2);//不为null

(3)不在同目录下,也不在子目录下,例如:com.x.y 下有类Test.class ,同时在 com.m.n 目录下有资源文件config.properties
那么,应该有如下代码:
//前面有“/”,代表了工程的根目录
InputStream is3 = Test.class.getResourceAsStream("/com/m/n/config.properties");
System.out.println(is3);//不为null


ClassLoader.getSystemResourceAsStream :

和className.class.getResourceAsStream 的第三种取得的路径一样,但少了“/”
InputStream is4 = ClassLoader.getSystemResourceAsStream("properties/PayManagment_Config.properties");
System.out.println(is4);//不为null

]]>
ClassNotFoundException: com.mchange.v2.c3p0.ComboPooledDataSource http://blog.okbase.net/JO2000/archive/56657.html JO2000 2018/5/23 22:11:05 明明已经在Java Build Path中通过Add External JARs将c3p0中的3个jar加入,还是显示没有找到com.mchange.v2.c3p0.ComboPooledDataSource这个类。

 

解决:

在项目目录/web/WEB-INF/ 中新建lib目录, 将c3p0-0.9.5.2, c3p0-oracle-thin-extras-0.9.5.2, mchange-commons-java-0.2.11拷贝到lib目录下,如果用得到mysql,需要将mysql-connector-java-5.1.5-bin.jar也拷贝进来。然后在Java Build Path中将jar加入。

 

]]>
区块链智能合约解决方案 http://blog.okbase.net/JO2000/archive/56641.html JO2000 2018/5/13 20:58:24 一、区块链智能合约特性
1)去中心化,可信机制
2)强安全共识机制,无需三方介入
3)交易的公开透明、不可篡改
4)分布式,稳定、可靠、持续

 

二、智能合约能做什么?

1)数字身份
允许用户拥有和控制包含数据、信誉度和数字资产的数字身份

2)宠物游戏
通过区块链技术,实现电子宠物的养成、交易、繁殖与竞技等

3)竞猜游戏
通过区块链技术保障竞猜的规则不可篡改,保障游戏的公平性

4)信息安全
文件上链,信息保全,无法篡改,可信背书

5)资产数字化
将实体资产数字化,实现确权,保障数字资产有效流通

6)商品溯源
商品全生命周期上链,信息可追踪

7)积分联盟
使用区块链记录积分信息,让积分可以交换和交叉使用

8)加密资产游戏
加密名人、加密国家、加密地区、加密星球、加密品牌

9)供应链金融
供应链信息流与资金流的生命周期管理,提高业务效率,降低业务风险

10)财政数据
财政组织可以利用智能合约进行准确、透明的财务数据记录

11)合同存证
通过智能合约,保障电子合同的不可篡改与有效性

12)调研投票
通过区块链技术,可以保障调研和投票信息的真实性与保密性

13)资产拍卖
保障拍卖信息的私密性与不可篡改

14)金融借贷
有效保障金融借贷信息的不可抵赖性

15)股权合约
将项目信息、股权信息登记到区块链中,所有者通过各自的私钥控制数字股权

]]>
ThinkPHP调用display输出模板的代码分析 http://blog.okbase.net/JO2000/archive/56630.html JO2000 2018/4/30 20:46:59 display函数位于Library/Think/View.class.php

public function display($templateFile='',$charset='',$contentType='',$content='',$prefix='',$cacheControl='') {
G('viewStartTime');
// 视图开始标签
Hook::listen('view_begin',$templateFile);
// 解析并获取模板内容
$content = $this->fetch($templateFile,$content,$prefix);
// 输出模板内容
$this->render($content,$charset,$contentType,$cacheControl);
// 视图结束标签
Hook::listen('view_end');
}

关键的代码是$content = $this->fetch($templateFile,$content,$prefix);

/**
* 解析和获取模板内容 用于输出
* @access public
* @param string $templateFile 模板文件名
* @param string $content 模板输出内容
* @param string $prefix 模板缓存前缀
* @return string
*/
public function fetch($templateFile='',$content='',$prefix='') {
if(empty($content)) {
$templateFile = $this->parseTemplate($templateFile);
// 模板文件不存在直接返回
if(!is_file($templateFile)) E(L('_TEMPLATE_NOT_EXIST_').':'.$templateFile);
}else{
defined('THEME_PATH') or define('THEME_PATH', $this->getThemePath());
}
// 页面缓存
ob_start();
ob_implicit_flush(0);
if('php' == strtolower(C('TMPL_ENGINE_TYPE'))) { // 使用PHP原生模板
$_content = $content;
// 模板阵列变量分解成为独立变量
extract($this->tVar, EXTR_OVERWRITE);
// 直接载入PHP模板
empty($_content)?include $templateFile:eval('?>'.$_content);
}else{
// 视图解析标签
$params = array('var'=>$this->tVar,'file'=>$templateFile,'content'=>$content,'prefix'=>$prefix);
Hook::listen('view_parse',$params);
}
// 获取并清空缓存
$content = ob_get_clean();
// 内容过滤标签
Hook::listen('view_filter',$content);
// 输出模板文件
return $content;
}


// 关键在这里
Hook::listen('view_parse',$params);
...
// 然后在 ThinkPHP\Mode\common.php: 从tags配置可知此处挂载的行为.
'view_parse' => array(
'Behavior\ParseTemplateBehavior', // 模板解析 支持PHP、内置模板引擎和第三方模板引擎
),
....
 在 \ThinkPHP\Library\Behavior\ParseTemplateBehavior.class.php 可以找到run方法

 

public function run(&$_data){
$engine = strtolower(C('TMPL_ENGINE_TYPE'));
$_content = empty($_data['content'])?$_data['file']:$_data['content'];
$_data['prefix'] = !empty($_data['prefix'])?$_data['prefix']:C('TMPL_CACHE_PREFIX');
if('think'==$engine){ // 采用Think模板引擎
if((!empty($_data['content']) && $this->checkContentCache($_data['content'],$_data['prefix']))
|| $this->checkCache($_data['file'],$_data['prefix'])) { // 缓存有效
//载入模版缓存文件
Storage::load(C('CACHE_PATH').$_data['prefix'].md5($_content).C('TMPL_CACHFILE_SUFFIX'),$_data['var']);
}else{
$tpl = Think::instance('Think\\Template');
// 编译并加载模板文件
$tpl->fetch($_content,$_data['var'],$_data['prefix']);
}
}else{
// 调用第三方模板引擎解析和输出
if(strpos($engine,'\\')){
$class = $engine;
}else{
$class = 'Think\\Template\\Driver\\'.ucwords($engine);
}
if(class_exists($class)) {
$tpl = new $class;
$tpl->fetch($_content,$_data['var']);
}else { // 类没有定义
E(L('_NOT_SUPPORT_').': ' . $class);
}
}
}

关键在这里,tpl = Think::instance('Think\\Template'); 实例化Library/Think/Template.class.php,该类是ThinkPHP内置模板引擎类,
然后调用fetch编译并加载模板文件
$tpl->fetch($_content,$_data['var'],$_data['prefix']);


最后fetch函数里调用compiler函数进行模板编译。

]]>
PHP数组常用操作备忘 http://blog.okbase.net/JO2000/archive/56608.html JO2000 2018/4/1 10:20:32 添加元素
1)方式1
$arr = array();
$arr[] = 1;
$arr[] = 2;

 

2)方式2
array_push($arr,1,2,3);

 

3)在头部添加
array_unshift($arr, 'joe', 'hank');

 

4)任意位置插入
$arr = array('A', 'B', 'C');
$arr2 = 'abc';
$t = array_splice($arr, 1, 0, $arr2);


array_splice方法,参数一是被操作的数组,参数二是操作元素的索引值,参数三是长度,参数四是要替换成的元素。该方法的效果是删除$arr中以1为起始位置,长度0的连贯的元素,然后用$arr2补上。假如长度为0,那么效果就相当于在指定索引值处插入指定元素了。

 

删除元素
$array = array(0 => "a", 1 => "b", 2 => "c");
array_splice($array, 1, 1); //删除了b

 

 

数组遍历
用foreach(速度最快):
$urls= array('aaa','bbb','ccc','ddd');
foreach ($urls as $url){
echo "This Site url is $url! <br />";
}

 

用for:
for ($i= 0;$i< count($urls); $i++){
$str= $urls[$i];
echo "This Site url is $str.<br />";
}

 

]]>
curl_exec返回false故障一例 http://blog.okbase.net/JO2000/archive/56603.html JO2000 2018/3/27 19:11:56 故障现象:

curl请求http正常,请求https返回false

var_dump(curl_errno($ch)

显示 string(28) "TCP connection reset by peer"

 

加上
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
也没有效果。

 

解决:

指定SSL版本
curl_setopt($ch, CURLOPT_SSLVERSION, 6);

 

 

SSL版本对应的值如下:

CURL_SSLVERSION_DEFAULT (0)
CURL_SSLVERSION_TLSv1 (1)
CURL_SSLVERSION_SSLv2 (2)
CURL_SSLVERSION_SSLv3 (3)
CURL_SSLVERSION_TLSv1_0 (4)
CURL_SSLVERSION_TLSv1_1 (5)
CURL_SSLVERSION_TLSv1_2 (6)

 

]]>
RequestCoreException: cURL resource: Resource id #51; cURL error: SSL certificate problem: unable to get local issuer certificat http://blog.okbase.net/JO2000/archive/56580.html JO2000 2018/3/8 8:15:03 在调试阿里云OSS客户端应用的时候出现错误:

RequestCoreException: cURL resource: Resource id #51; cURL error: SSL certificate problem: unable to get local issuer certificate

 

解决方法:

证书下载地址:
http://curl.haxx.se/ca/cacert.pem

放到服务器,例如:d:/php/php5.5

 

在php.ini添加:
curl.cainfo = "d:/php/php5.5/cacert.pem"

]]>