java ffmpeg压缩视频报错踩坑整理+解决措施:

作者:丘杨(如需转载请注明出处)

背景:

为加快网页加载速度,压缩相关视频文件。其中发现在进行视频压缩的时候会报ws.schild.jave.EncoderException: Exit code of ffmpeg encoding run is 1错误,本文章旨在记录踩坑历史。

原代码:

参考文章:视频压缩(记录)_videoattributes-CSDN博客

本代码基于参考文章的基础上,将入参改为inputstream,出参改为byte以适配minio上传、下载文件的需求。

maven:

        <dependency>
            <groupId>ws.schild</groupId>
            <artifactId>jave-core</artifactId>
            <version>3.0.0</version>
        </dependency>
        <!-- 在windows上开发 开发机可实现压缩效果 window64位 -->
        <dependency>
            <groupId>ws.schild</groupId>
            <artifactId>jave-nativebin-win64</artifactId>
            <version>3.0.0</version>
        </dependency>
        <!-- 在linux上部署 linux服务器需要这个才能生效 linux64位 -->
        <dependency>
            <groupId>ws.schild</groupId>
            <artifactId>jave-nativebin-linux64</artifactId>
            <version>3.0.0</version>
        </dependency>

原代码:

    /**
     * 传视频File对象(这是一个具体的文件),返回压缩后File对象信息
     *
     * @param inputStream
     */
    public byte[] compressionVideo(InputStream inputStream, String suffix) throws EncoderException, IOException {
        if (inputStream == null) {
            return null;
        }
        File source = null;
        File target = null;
        try {
            source = File.createTempFile("source", suffix);
            target = File.createTempFile("target", suffix);
            OutputStream outputStream = new FileOutputStream(source);
            byte[] buffer = new byte[1024];
            int length;
            while ((length = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, length);
            }
            inputStream.close();
            outputStream.close();

            MultimediaObject object = new MultimediaObject(source);
            AudioInfo audioInfo = object.getInfo().getAudio();
            // 根据视频大小来判断是否需要进行压缩,
            int maxSize = 5;
            double mb = Math.ceil(source.length() / 1048576);
            int second = (int) object.getInfo().getDuration() / 1000;
            BigDecimal bd = new BigDecimal(String.format("%.4f", mb / second));
            System.out.println("开始压缩视频了--> 视频每秒平均 " + bd + " MB ");
            long time = System.currentTimeMillis();
            //TODO 视频属性设置
            int maxBitRate = 128000;
            int maxSamplingRate = 44100;
            int bitRate = 800000;
            int maxFrameRate = 20;
            int maxWidth = 1280;

            AudioAttributes audio = new AudioAttributes();
            // 设置通用编码格式10                   audio.setCodec("aac");
            // 设置最大值:比特率越高,清晰度/音质越好
            // 设置音频比特率,单位:b (比特率越高,清晰度/音质越好,当然文件也就越大 128000 = 182kb)
            if (audioInfo.getBitRate() > maxBitRate) {
                audio.setBitRate(maxBitRate);
            }
            // 设置重新编码的音频流中使用的声道数(1 =单声道,2 = 双声道(立体声))。如果未设置任何声道值,则编码器将选择默认值 0。
            audio.setChannels(audioInfo.getChannels());
            // 采样率越高声音的还原度越好,文件越大
            // 设置音频采样率,单位:赫兹 hz
            // 设置编码时候的音量值,未设置为0,如果256,则音量值不会改变
            // audio.setVolume(256);
            if (audioInfo.getSamplingRate() > maxSamplingRate) {
                audio.setSamplingRate(maxSamplingRate);
            }


            //TODO 视频编码属性配置
            ws.schild.jave.info.VideoInfo videoInfo = object.getInfo().getVideo();
            VideoAttributes video = new VideoAttributes();
//            video.setCodec("h264");
            //设置音频比特率,单位:b (比特率越高,清晰度/音质越好,当然文件也就越大 800000 = 800kb)
            if (videoInfo.getBitRate() > bitRate) {
                video.setBitRate(bitRate);
            }

            // 视频帧率:15 f / s  帧率越低,效果越差
            // 设置视频帧率(帧率越低,视频会出现断层,越高让人感觉越连续),视频帧率(Frame rate)是用于测量显示帧数的量度。所谓的测量单位为每秒显示帧数(Frames per Second,简:FPS)或“赫兹”(Hz)。
            if (videoInfo.getFrameRate() > maxFrameRate) {
                video.setFrameRate(maxFrameRate);
            }

            // 限制视频宽高
            int width = videoInfo.getSize().getWidth();
            int height = videoInfo.getSize().getHeight();
            if (width > maxWidth) {
                float rat = (float) width / maxWidth;
                video.setSize(new VideoSize(maxWidth, (int) (height / rat)));
            }

            EncodingAttributes attr = new EncodingAttributes();
//                attr.setFormat("mp4");
            attr.setAudioAttributes(audio);
            attr.setVideoAttributes(video);

            // 速度最快的压缩方式, 压缩速度 从快到慢: ultrafast, superfast, veryfast, faster, fast, medium,  slow, slower, veryslow and placebo.
//                attr.setPreset(PresetUtil.VERYFAST);
//                attr.setCrf(27);
//                // 设置线程数
//                attr.setEncodingThreads(Runtime.getRuntime().availableProcessors()/2);

            Encoder encoder = new Encoder();
            encoder.encode(new MultimediaObject(source), target, attr);
            System.out.println("压缩总耗时:" + (System.currentTimeMillis() - time) / 1000);
            return fileToBytes(target);
        } catch (
                Exception e) {
            e.printStackTrace();
            throw e;
        } finally {
            assert source != null;
            source.delete();
            assert target != null;
            target.delete();
        }

    }

    public static byte[] fileToBytes(File file) {
        FileInputStream fis = null;
        byte[] bytes = null;

        try {
            fis = new FileInputStream(file);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int bytesRead;

            while ((bytesRead = fis.read(buffer)) != -1) {
                bos.write(buffer, 0, bytesRead);
            }

            bytes = bos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }

        return bytes;
    }

踩坑记录:

坑1:AudioInfo报空指针

修改compressionVideo方法:

加audioInfo的空指针判断:

        if (ObjectUtils.isNotEmpty(audioInfo)) {
            if (audioInfo.getBitRate() > maxBitRate) {
                audio.setBitRate(maxBitRate);
            }
            // 设置重新编码的音频流中使用的声道数(1 =单声道,2 = 双声道(立体声))。如果未设置任何声道值,则编码器将选择默认值 0。
            audio.setChannels(audioInfo.getChannels());
            // 采样率越高声音的还原度越好,文件越大
            // 设置音频采样率,单位:赫兹 hz
            // 设置编码时候的音量值,未设置为0,如果256,则音量值不会改变
            // audio.setVolume(256);
            if (audioInfo.getSamplingRate() > maxSamplingRate) {
                audio.setSamplingRate(maxSamplingRate);
            }
        }

坑2:多个视频文件报 ws.schild.jave.EncoderException: Exit code of ffmpeg encoding run is 1

压缩视频时发现经常报ws.schild.jave.EncoderException: Exit code of ffmpeg encoding run is 1问题,debug源码后发现有如下问题:

问题1:height不能整除2导致报错

解决后的代码:

// 限制视频宽高
            int width = videoInfo.getSize().getWidth();
            int height = videoInfo.getSize().getHeight();
            if (width > maxWidth) {
                float rat = (float) width / maxWidth;
                int newHeight = (int) (height / rat) % 2 == 1 ? (int) (height / rat) + 1 : (int) (height / rat);
                video.setSize(new VideoSize(maxWidth, newHeight));
            }
问题2:Specified sample rate 44100 is not supported 

bitrate不支持44100

在原代码里,代码的maxSamplelingRate设置为44100

暴力解决,直接删除下面代码

取了默认的96000bps,代码无报错

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
你可以通过以下步骤来实现Java与RTSP、FFmpeg、HTML和Nginx的结合来实现视频实时播放的监控系统: 1. 首先,你需要使用Java来创建一个监控系统的后端服务。你可以使用Java的网络编程库来监听RTSP流并将其解码。可以使用开源的库,例如JRTSP或者Xuggler来处理RTSP流,并将其转换为可供播放的视频流。 2. 接下来,你需要使用FFmpeg来处理视频流。FFmpeg是一个强大的多媒体处理工具,可以用于转码、解码、编码等操作。你可以使用FFmpeg来解码RTSP流,并将其转换为HTML5支持的视频格式,例如HLS(HTTP Live Streaming)或者MPEG-DASH(Dynamic Adaptive Streaming over HTTP)。 3. 在前端方面,你可以使用HTML和JavaScript来创建一个简单的视频播放器。你可以使用HTML5的<video>标签来嵌入视频,并使用JavaScript来控制视频的播放、暂停等操作。你可以使用一些开源的视频播放器库,例如video.js或者plyr来简化开发过程。 4. 最后,你可以使用Nginx作为反向代理服务器来提供视频流的分发和缓存功能。Nginx可以将视频流从后端服务器转发给前端浏览器,并且可以缓存视频文件以提高性能和可靠性。你可以配置Nginx来支持HLS或者MPEG-DASH协议,并且可以使用Nginx的HTTP模块来进行性能优化和安全加固。 综上所述,通过将Java、RTSP、FFmpeg、HTML和Nginx结合起来,你可以实现一个监控视频的实时播放系统。这个系统可以从RTSP流中提取视频数据,经过FFmpeg处理后,通过HTML和JavaScript在浏览器中进行播放,并且可以使用Nginx提供性能优化和缓存支持。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

樱曦何归

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值