在我开源的APP 弹弹play 概念版 中实现了局域网视频播放的功能,所以将相关功能抽离出来写了个Demo,并写了这篇介绍相关内容的文章。

Demo地址:https://github.com/xyoye/SmbPlayHelper

一、简述

  1. 需要实现局域网内视频播放,首要条件是能从局域网文件中拿到InputStream(A),这里局域网内文件浏览的库推荐使用jcifs-ngsmbj,介绍中Demo使用的是jcifs-ng。

  2. 由于普通播放器一般不能直接设置InputStream(A)作为播放源,但是播放器大都是能播放http链接的视频,所以转换一下思路,通过创建本地服务端接收播放器的http请求,将InputStream(A)内数据写回播放器,以此实现播放。

二、功能实现

一、创建ServerSocket

  1. 获取本地可用的网络接口从中拿到IP。

    获取本地网络接口

  2. 设置端口,创建ServerSocket。

    创建ServerSocket

  3. 所以在接收到请求后,会得到一个Socket,在新线程中处理该Sockt。

    接收请求

二、处理Socket

  1. 通过从Socket中拿到InputStream(B),将其转换为BufferedInputStream。

  2. 从BufferedInputStream中读出请求头信息,主要是读取其中的Range信息,Range的作用是在创建返回体Resonpse时确定返回数据具体的位置。(一般只需要处理”n-“、”-n”、”n-m”这三种格式就可以了)

三、返回Response

  1. 拿到Range后需要做相关检验,比如range范围是否超出文件等。

  2. 返回Response响应头
    响应头构建

  3. 将局域网文件的InputStream(A)调整至range开始的位置,再从InputStream按块读取数据,将数据通过Socket的OutputStream写回播放器。

     OutputStream outputStream = httpSocket.getOutputStream();
     //响应头
     outputStream.write(response.getResponseHeader().getBytes());
     //必须返回!!!
     outputStream.write("\r\n".getBytes());
     ...
     InputStream inputStream = response.getContentInputStream();
     //跳转至contentOffset
     inputStream.skip(contentOffset);
     ...
     //读数据
     int readLen = inputStream.read(readBuffer, 0, (int) readSize);
     while (readLen > 0 && readTotalSize < contentLength) {
         //写回数据
         outputStream.write(readBuffer, 0, readLen);
         outputStream.flush();
         ...
     }
     outputStream.flush();