Java下视频弹幕的获取和解析

原文地址

原文链接

前言

这里以bilibili的弹幕文件为例,弹幕文件一般为两种,ass文件和xml文件,前者对于普通用户更友好,后者对于程序员更友好。如果经常下载视频资源的小伙伴应该知道,ass文件常常作为外挂字幕文件使用,同文件下一般视频播放器会自动加载同名ass文件,可以通过这个直接实现弹幕播放,但是这个web端是不行,现在web播放器默认只支持webvtt文件作为字幕资源。扯远了,我们这里以B站弹幕 + DPlayer弹幕源引擎的背景简单说下,如何在自己个人网站实现弹幕播放效果

实现

弹幕获取

获取弹幕源的方式有很多,这个最简单的还是使用浏览器插件,这个比较简单就不多说了

弹幕上传

本文使用的是xml解析的方式,如果小伙伴觉得ass文件解析更简单那么使用它也是不错的方法。由于我们的多媒体服务是反应式的,这里我们的示例代码都是反应式的,大家需要稍作调整

    @PostMapping(value = "/your_path", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public Mono<Void> subBarInsert(@RequestPart("file") FilePart file,
                                   @PathVariable String videoId) {
        return barrageService.insertSubBarrageList(file, videoId);
    }
    @Override
    public Mono<Void> insertSubBarrageList(FilePart file, String videoId) {
        @SuppressWarnings("deprecation")
        Mono<byte[]> fileDataByte = DataBufferUtils.join(file.content())
                .map(dataBuffer -> dataBuffer.asByteBuffer().array());
        //save
        return fileDataByte.map(BarrageParseUtils::genBarrageList)
                .map(barrageDtosList -> {
                    VideoBarrageRef ref = new VideoBarrageRef();
                    //set data ...
                    return ref;
                })
                .flatMap(entity -> videoBarrageRefMapper.save(entity))
                .then();
    }

这里只是简单示例,缺少很多稳定性代码,大家自行根据需求添加

下方为弹幕的实际解析,xml文件的解析参考本站Java解析Xml文件转为数据对象,这里就不重复了。该工具类还进行了弹幕压缩,不需要的小伙伴也可以去掉,本来应该在输出时随机压缩弹幕的,但是考虑到性能问题改在弹幕上传时候压缩。一般比较火的视频几万条弹幕是很正常的,所以如果在输出时候进行随机压缩,小服务器是没办法很快响应的

public class BarrageParseUtils {

    public static final double MAX_BARRAGE_SIZE = 3000.0;

    public static final int ZIP_OFFSET = 10;

    public static final List<Integer> ZIP_INDEX = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);

    public static List<BarrageDto> genBarrageList(byte[] file) {
        List<BarrageDto> barrageDtoList = new ArrayList<>();
        try {
            //convert to obj
            XmlMapper xmlMapper = new XmlMapper();
            SubBarrageCollection poppy = xmlMapper.readValue(file, SubBarrageCollection.class);
            List<SubBarrage> subBarrageList = poppy.getSubBarrageList();
            //zip ratio
            double zipRatio = MAX_BARRAGE_SIZE / subBarrageList.size();
            zipRatio = zipRatio > 1 ? 1 : zipRatio;
            List<Integer> dynamicZipRate = ZIP_INDEX.subList(0, (int) (zipRatio * ZIP_OFFSET) + 1);
            //convert to entity
            for (SubBarrage subBarrage : subBarrageList) {
                try {
                    BarrageDto barrageDto = new BarrageDto();
                    barrageDto.setText(subBarrage.getContent());
                    String[] barrageDetail = subBarrage.getProperty().split(",");
                    barrageDto.setTime(Double.valueOf(barrageDetail[0]));
                    if (!dynamicZipRate.contains((int) (barrageDto.getTime() * ZIP_OFFSET) % ZIP_OFFSET)) {
                        continue;
                    }
                    barrageDto.setColor(Integer.valueOf(barrageDetail[3]));
                    //todo https://github.com/DIYgod/DPlayer/blob/master/src/js/danmaku.js 
                    barrageDto.setType(0);
                    barrageDto.setAuthor("");
                    barrageDtoList.add(barrageDto);
                } catch (Exception ignored) {
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return barrageDtoList;
    }
}

DPlayer的弹幕结构在本站的Vue3下构建带有弹幕功能的Web播放器有介绍,同样不再赘述,这里简单给下后端实体类

public class BarrageDto {

    /**
     * video barrage time 5.312
     */
    private Double time;

    /**
     * 233333
     */
    private String text;

    /**
     * #fff
     */
    private Integer color;

    /**
     * barrage site
     */
    private Integer type;

    /**
     * author
     */
    private String author;
}

弹幕发放

这里没啥,就按照前端数据结果直接取出来即可,这个给个简易示例

    @Override
    public Flux<BarrageDto> getBarrageList(String videoId) {
        return videoBarrageRefMapper.getByVideoId(videoId)
                .map(data -> JSON.parseArray(data.getBarrageTextSub(), BarrageDto.class))
                .flatMapMany(Flux::fromIterable);
    }

原文地址

原文链接

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值