ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

javaCV开发详解之补充篇:根据视频时间戳同步播放图像画面以及视频倍速播放实现

2021-04-19 21:55:42  阅读:294  来源: 互联网

标签:视频 画面 grabber 详解 javaCV 倍速 播放


javaCV系列文章:

javacv开发详解之1:调用本机摄像头视频

javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG、javaCV-openCV)

javaCV开发详解之3:收流器实现,录制流媒体服务器的rtsp/rtmp视频文件(基于javaCV-FFMPEG)

javaCV开发详解之4:转流器实现(也可作为本地收流器、推流器,新增添加图片及文字水印,视频图像帧保存),实现rtsp/rtmp/本地文件转发到rtmp流媒体服务器(基于javaCV-FFMPEG)

javaCV开发详解之5:录制音频(录制麦克风)到本地文件/流媒体服务器(基于javax.sound、javaCV-FFMPEG)

javaCV开发详解之6:本地音频(话筒设备)和视频(摄像头)抓取、混合并推送(录制)到服务器(本地)

javaCV开发详解之7:让音频转换更加简单,实现通用音频编码格式转换、重采样等音频参数的转换功能(以pcm16le编码的wav转mp3为例)

javaCV开发详解之8:转封装在rtsp转rtmp流中的应用(无须转码,更低的资源消耗,更好的性能,更低延迟)

javaCV开发详解之9:基于gdigrab的windows屏幕画面抓取/采集(基于javacv的屏幕截屏、录屏功能)

javaCV开发详解之10:基于dshow调用windows摄像头视频和音频,想要获取屏幕画面首选gdigrab

补充篇:

javaCV开发详解之补充篇:根据视频时间戳同步播放图像画面以及实现视频倍速播放

javaCV开发详解补充篇:基于avfoundation的苹果Mac和ios获取屏幕画面及录屏/截屏以及摄像头画面和音频采样获取实现

音视频编解码问题:javaCV如何快速进行音频预处理和解复用编解码(基于javaCV-FFMPEG)

音视频编解码问题:16/24/32位位音频byte[]转换为小端序short[],int[],以byte[]转short[]为例

实现给图片增加图片水印或者文字水印(也支持视频图像帧添加水印)

java原生实现屏幕设备遍历和屏幕采集(捕获)等功能

javacv文字识别系列:

javaCV文字识别之1:基于google的tesserac ocr识别图片中的文字,跨平台支持英文中文简体繁体等各种字符识别

javaCV文字识别之2:视频文字识别和视频提取字幕文字字符

javacpp-ffmpeg系列:

javacpp-FFmpeg系列之1:视频拉流解码成YUVJ420P,并保存为jpg图片

javacpp-FFmpeg系列之2:通用拉流解码器,支持视频拉流解码并转换为YUV、BGR24或RGB24等图像像素数据

javacpp-FFmpeg系列之3: 图像数据转换(BGR与BufferdImage互转,RGB与BufferdImage互转)

javacpp-FFmpeg系列补充:FFmpeg解决avformat_find_stream_info检索时间过长问题

javacpp-opencv系列:

一、javaCV图像处理之1:实时视频添加文字水印并截取视频图像保存成图片,实现文字水印的字体、位置、大小、粗度、翻转、平滑等操作

二、javaCV图像处理之2:实时视频添加图片水印,实现不同大小图片叠加,图像透明度控制

三、javacv图像处理3:使用opencv原生方法遍历摄像头设备及调用(方便多摄像头遍历及调用,相比javacv更快的摄像头读取速度和效率,方便读取后的图像处理)

四、javacv图像处理系列:国内车辆牌照检测识别系统(万份测试准确率99.7%以上)

一、前言

不管是推流还是拉流,还是摄像头抓取抑或是屏幕画面抓取都需要对视频画面进行预览播放,查看视频实际播放效果,之前我们都是根据帧率简单的通过Thread.sleep(1000/帧率);来以不太准确的时间来播放视频画面。

本章将通过实现一个简单的例子如何以视频时间戳的时间同步播放视频画面,以及实现倍速播放的目的。

 

二、实现功能

1、获取视频源信息

2、根据时间戳同步播放视频画面

3、倍速播放

 

三、实现原理

1、同步播放

记录每次显示前的时间(startViewTime)和显示结束的时间(endViewTime)。

视频当前帧画面的时间戳(nextTime)。

上一帧画面的时间戳(lastTime)。

理论来上来说两帧之间间隔是(nextTime-lastTime)。

但是显示图像也是需要耗时的,所以实际耗时应该是:(nextTime-lastTime -(endViewTime-startViewTime))。

也有可能会出现(nextTime-lastTime)>(endViewTime-startViewTime)的情况,这时候就不需要等待直接播放即可。

 

2、倍速播放(快进和慢放)

我们知道(nextTime-lastTime)表示两帧间隔,只要对该结果变量进行调整就可以实现倍速快进和慢放的效果。

 

四、代码实现

/**
     * 播放视频流
     * @another 做好自己!-- eguid原创,博客地址:blog.csdn.net/eguid_1或者eguid.blog.csdn.net
     * @param url            视频地址
     * @param videoPlaySpeed 播放速度
     */
    private static void playVideo(String url, double videoPlaySpeed) throws Exception, InterruptedException {

        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(url);
        grabber.setFormat("mp4");// 基于gdigrab的输入格式
        grabber.start();

        double frameRate = grabber.getVideoFrameRate();
        int bitRate = grabber.getVideoBitrate();
        int width = grabber.getImageWidth();
        int height = grabber.getImageHeight();
        long duraion = grabber.getLengthInTime();// 视频时长,也可以通过grabber.getFormatContext().duration();获取视频时长
        System.err.println(
                "视频信息:{宽度=" + width + ",高度=" + height + ",帧率:" + frameRate + ",比特率=" + bitRate + "视频时长:" + duraion);
        int videoStreamIndex = grabber.getVideoStream();
        CanvasFrame canvas = new CanvasFrame("屏幕预览", CanvasFrame.getDefaultGamma());// 新建一个窗口
        canvas.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        canvas.setAlwaysOnTop(true);
        Frame frame = null;

        long startRealTime;// 实际播放时间
        long startViewTime = 0;
        long consumTime = 0;
        // 抓取屏幕画面
        int i = 0;
        long lastTime = 0;
        for (startRealTime = System.nanoTime(); (frame = grabber.grabImage()) != null;) {
            // 显示画面
            if (frame.streamIndex == videoStreamIndex) {
                // 同步视频播放时间,为什么不能直接sleep(1000/帧率),因为显示图像也要耗时,而且每帧间隔不一定是(1000/帧率)每秒,所以需要定制
                if (lastTime > 0) {
                    long time = frame.timestamp - lastTime;
                    if (videoPlaySpeed > 0 && videoPlaySpeed != 1) {
                        time /= videoPlaySpeed;
                    }
                    consumTime = (System.nanoTime() - startViewTime) / 1000;
                    if (consumTime < time) {
                        long interval = (time - consumTime) / 1000;
                        int nano = (int) (time % (interval * 1000));
                        Thread.sleep(interval, nano);
                    }
                }
                startViewTime = System.nanoTime();
                canvas.showImage(frame);// 显示图像
                i++;
                lastTime = frame.timestamp;
            }
        }
        double inteval = (System.nanoTime() - startRealTime) / 1000000000.0;
        System.out.println("总耗时:" + inteval + "秒,总帧数:" + i + ",平均帧率:" + i / inteval);
        grabber.stop();
        canvas.dispose();
    }

 

public static void main(String[] args) throws Exception, UnsupportedEncodingException, InterruptedException {
        // 视频地址,播放速度(0-1之间表示慢放,1以上表示快放)
        playVideo("eguid.mp4", 3);//三倍快放

        //playVideo("eguid.mp4", 0.5);//2倍慢放
    }

标签:视频,画面,grabber,详解,javaCV,倍速,播放
来源: https://blog.51cto.com/u_6329998/2718413

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有