XiNGRZ

XiNGRZ 查看完整档案

广州编辑  |  填写毕业院校aja  |  CTO 编辑 xingrz.me 编辑
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 该用户太懒什么也没留下

个人动态

XiNGRZ 关注了用户 · 2019-12-26

iFLYOS @iflytek_iflyos

「蓝小飞」——前往未来世界

关注 4

XiNGRZ 关注了标签 · 2019-12-26

iflyos

iFLYOS 是科大讯飞提供的一款智能物联网操作系统,它聚合了讯飞语音唤醒、声纹识别、语义理解、语音合成等各项强大技术能力,旨在实现人机交互无障碍,使人与机器之间可以通过自然的语音交互方式,进行持续,双向,自然地沟通。

关注 1

XiNGRZ 评论了文章 · 2018-08-29

使用 WebSockets 进行 HTML5 视频直播

这篇文章是2014年发的,已经过时了!不要再评论了!

最近在做的一个小项目需要用到相关技术,找到这篇文章貌似不错,于是就翻译转载上来了。
Recently I'm interesting in these technologies and I'm working on a project related to it. I've found this useful article so I translated and posted it here.

原文地址 / Original post:
HTML5 Live Video Streaming via WebSockets - PhobosLab

笔者之前做一个实时监控应用的时候,曾搜索过一些将 iPhone 的摄像头拍摄的画面实时传输到浏览器的方案,一个都没有。

就 HTML5 来说,视频(实时)直播是一个很悲催的活,HTML5 视频目前还没有一个正式的流式传输支持,Safari 支持很蹩脚的 HTTP Live Streaming 并且也即将有 Media Source Extension 规范和 MPEG-DASH。但所有这些方案都是将视频分成小片,由浏览器单独下载,因此会产生最小五秒钟的延迟。

下面是一个完全不同的方案,可以支持所有现代浏览器:Firefox、Chrome、Safari、Mobile Safari、Android 版 Chrome 甚至是 IE10。

原文的这个位置提供了一个_伪_直播例子。

这套方案向后兼容,没有用到什么新奇技术,目前暂时不支持音频。但它出乎意料地好用。

来自摄像头的视频被 ffmpeg 编码,然后通过 HTTP 传递给一个 Node.js 写的小脚本;脚本会将这条 MPEG 视频流通过 WebSockets 分发给所有链接的浏览器;浏览器使用 JavaScript 解码 MPEG 视频流并将解码后的画面渲染到 Canvas 元素上。

你甚至可以用树莓派来传输视频。可能会有点慢,但是笔者测试过以 30fps 的帧率实时编码 320x240 视频不成问题。对笔者来说这是最好的树莓派视频方案。

下面是构建步骤。首先你需要取得最新版本的 ffmpeg,最新的安装包可以从 deb-multimedia 获得。如果你使用 Linux,你的摄像头应该在位于 /dev/video0/dev/video1;在 OS X 或 Windows 上你可以用 VLC

确保用来分发视频流的服务器安装了 Node.js。下载 phoboslab/jsmpeg 项目的 stream-server.js 脚本。安装 WebSocket 包 ws 并启动服务器:

npm install ws
node stream-server.js 你的密码

这里的密码是用来确保不会有好奇宝宝来劫持你的视频流用的。如果服务器运行正常,你应该会看到这样的输出:

Listening for MPEG Stream on http://127.0.0.1:8082/<secret>/<width>/<height>
Awaiting WebSocket connections on ws://127.0.0.1:8084/

服务器启动后,你就可以启动 ffmpeg 并将它指向到正在运行的这个域名和端口了:

ffmpeg -s 640x480 -f video4linux2 -i /dev/video0 -f mpeg1video -b 800k -r 30 http://example.com:8082/你的密码/640/480/

这条命令会开始从摄像头捕捉 640x480 的视频,并编码成 30fps 码率 800kbps 的 MPEG 视频。编码后的视频会通过 HTTP 被发送到所指定的服务器和端口。确保密码正确,URL 中的长和宽也需要正确指定,否则服务器无法正确判断当前的分辨率。

在树莓派上你可能需要将分辨率降至 320x240 来确保编码速度仍能维持 30fps。

要观看直播,需要从前文提到的 jsmpeg 项目中下载 stream-example.html 和 jsmpg.js 文件,更改 stream-example.html 中的 WebSocket URL 为你的服务器地址,并使用你喜欢的浏览器打开。

如果一切正常,你就能看到少于 100ms 延迟的流畅的摄像头画面。很好很强大对不?

更便捷的方案请围观原文的 Instant Webcam

只是备忘一下,近期会再发一篇博文来总结一下各个方案的实际使用效果。

重复一次原文地址 / Original post:
HTML5 Live Video Streaming via WebSockets - PhobosLab

查看原文

XiNGRZ 关注了标签 · 2014-09-16

docker

an open source project to pack, ship and run any application as a lightweight container ! By Lock !

关注 9292

XiNGRZ 关注了用户 · 2014-07-30

mj @mj

关注 6

XiNGRZ 评论了问题 · 2014-07-29

HTTP 上传返回 invalid put policy encoding 错误

XiNGRZ 提出了问题 · 2014-07-25

HTTP 上传返回 invalid put policy encoding 错误

总的来说

  1. 服务端使用七牛官方 Ruby SDK 生成的 uptoken
  2. Android 客户端使用 Retrofit 构建上传,失败:invalid put policy encoding
  3. 自己构建 Multipart 请求体,失败同上
  4. 已自己检查 upload token,以 : 为分割的第一段确为 Access Key 的 base64 编码;第三段确为 put policy 的 json 的 base64 编码(如果这个都能错就是你们 Ruby SDK 的问题)

生成 upload token

def upload_token
  put_policy = Qiniu::Auth::PutPolicy.new 'xxxxxx'
  put_policy.fsize_limit = "20971520"
  put_policy.mime_limit = "image/*;video/*"
  token = Qiniu::Auth.generate_uptoken(put_policy)
  render json: {token: token}, status: :created
end

使用 Retrofit 请求

@Multipart
@POST("/")
void upload(@Part("file") CountingTypedStream stream,
            @Part("token") TypedString token,
            Callback<UploadResult> callback);

产生的请求体如下(省略 file part。SF 你又擅自着色我的代码了!):

--667fdbb3-301f-4f25-ab8d-acc80ca14192
Content-Disposition: form-data; name="token"
Content-Type: text/plain; charset=UTF-8
Content-Length: 202
Content-Transfer-Encoding: binary
Y0这是我的AK无误t5:1o1Ic这里也没问题42UVEo=:eyJzY这一串也没问题KiJ9
--667fdbb3-301f-4f25-ab8d-acc80ca14192--

返回给我的东西(取自日志):

07-24 22:59:43.266 D/Retrofit﹕ <--- HTTP 401 http://upload.qiniu.com/ (13126ms)
07-24 22:59:43.266 D/Retrofit﹕ : HTTP/1.1 401 Unauthorized
07-24 22:59:43.266 D/Retrofit﹕ Access-Control-Allow-Headers: X-File-Name, X-File-Type, X-File-Size
07-24 22:59:43.266 D/Retrofit﹕ Access-Control-Allow-Methods: OPTIONS, HEAD, POST
07-24 22:59:43.266 D/Retrofit﹕ Access-Control-Allow-Origin: *
07-24 22:59:43.266 D/Retrofit﹕ Cache-Control: no-store, no-cache, must-revalidate
07-24 22:59:43.266 D/Retrofit﹕ Connection: close
07-24 22:59:43.266 D/Retrofit﹕ Content-Length: 39
07-24 22:59:43.266 D/Retrofit﹕ Content-Type: application/json
07-24 22:59:43.266 D/Retrofit﹕ Date: Thu, 24 Jul 2014 14:59:43 GMT
07-24 22:59:43.266 D/Retrofit﹕ Pragma: no-cache
07-24 22:59:43.266 D/Retrofit﹕ Server: nginx/1.4.4
07-24 22:59:43.266 D/Retrofit﹕ X-Android-Received-Millis: 1406213983252
07-24 22:59:43.266 D/Retrofit﹕ X-Android-Response-Source: NETWORK 401
07-24 22:59:43.266 D/Retrofit﹕ X-Android-Selected-Transport: http/1.1
07-24 22:59:43.266 D/Retrofit﹕ X-Android-Sent-Millis: 1406213970562
07-24 22:59:43.266 D/Retrofit﹕ X-Content-Type-Options: nosniff
07-24 22:59:43.266 D/Retrofit﹕ X-Log: UP:17/401
07-24 22:59:43.266 D/Retrofit﹕ X-Reqid: JUAAAFZBtNkq4IMT
07-24 22:59:43.266 D/Retrofit﹕ X-Via: 1.1 gzqxg204:1 (Cdn Cache Server V2.0)
07-24 22:59:43.274 D/Retrofit﹕ {"error":"invalid put policy encoding"}
07-24 22:59:43.274 D/Retrofit﹕ <--- END HTTP (39-byte body)

自己手动拼接构建的请求体

--4da8f9b3-4e83-483b-b206-96faf1c4574d
Content-Disposition: form-data; name="token"

我是PutPolicy肯定没问题啦啦啦啦啦啦
--4da8f9b3-4e83-483b-b206-96faf1c4574d
Content-Disposition: form-data; name="file"; filename="stream_file"
Content-Type: application/octet-stream

文件内容
--4da8f9b3-4e83-483b-b206-96faf1c4574d--

完全按照 http://developer.qiniu.com/docs/v6/api/reference/up/upload.html 的格式构建,Header 不多不少。

关注 0 回答 0

XiNGRZ 发布了文章 · 2014-07-19

Retrofit 备忘

本来很抗拒 Retrofit 的,结果前几天在车上无聊想了一下,诶这玩意其实挺美的啊!

引入

在 21 世纪 10 年代还需要自己拷贝 jar 包的库都是耍流氓。—— 我说的

dependencies {
    compile 'com.squareup.retrofit:retrofit:1.6.1'
}

Gradle 是什么自己恶补去。

声明 API

我喜欢对照着 Resource 来声明 API。

public interface Greet {

    @FormUrlEncoded
    @POST("/greets")
    void create(@Field("message") String message, Callback<Void> callback);

}

构建类

public class YeahApi {

    private static final String ENDPOINT = "https://api.yeah.xingrz.us";

    // 让 Gson 自动将 API 中的下划线全小写式变量名转换成 Java 的小写开头驼峰式
    private static final Gson gson = new GsonBuilder()
            .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
            .create();

    private static final RestAdapter adapter = new RestAdapter.Builder()
            .setEndpoint(ENDPOINT)
            .setConverter(new GsonConverter(gson))
            .setRequestInterceptor(new RequestInterceptor() {
                @Override
                public void intercept(RequestFacade request) {
                    request.addHeader("User-Agent", "Yeah/" + BuildConfig.VERSION_NAME);
                    request.addHeader("Accept", "application/json");
                }
            })
            .build();

    private static final Greet GREET_API = adapter.create(Greet.class);

    public static Greet greet() {
        return GREET_API;
    }

}

请求

YeahApi.greet().create("Hello world!", new Callback<Void>() {
    @Override
    public void success(Void aVoid, Response response) {
        // ...
    }

    @Override
    public void failure(RetrofitError error) {
        // ...
    }
});
查看原文

赞 0 收藏 1 评论 0

XiNGRZ 评论了回答 · 2014-06-16

Android 第三方推送选择

XiNGRZ 评论了问题 · 2014-06-16

raspberry 安装opencv 始终装不上highgui模块

认证与成就

  • 获得 83 次点赞
  • 获得 12 枚徽章 获得 0 枚金徽章, 获得 3 枚银徽章, 获得 9 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

注册于 2013-10-22
个人主页被 1.1k 人浏览