javacv实现音频文件转码g711a

        最近在做华为摄像头相关的项目,里边需要实现语音广播和语音对讲,涉及到音频数据编码成g711a格式发送.参考了网上不少文章,最终通过javacv 调用ffmgeg实现转码.

先附上命令行转码的方式:

# 转换wav文件为G711A
ffmpeg -i "input.wav" -bitexact -c:a pcm_alaw output.wav

# 转换wav文件为G711U
ffmpeg -i "input.wav" -bitexact -c:a pcm_mulaw output.wav

        通过java方式实现如下:

1 maven依赖

  <!-- 媒体只用到以下两个,javacv、ffmpeg -->
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacv</artifactId>
            <version>1.5.6</version>
        </dependency>

        <!-- ffmpeg全平台引入 -->
        <!--        <dependency>-->
        <!--            <groupId>org.bytedeco</groupId>-->
        <!--            <artifactId>ffmpeg-platform</artifactId>-->
        <!--            <version>4.4-1.5.6</version>-->
        <!--        </dependency>-->
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>ffmpeg</artifactId>
            <version>4.4-1.5.6</version>
            <classifier>windows-x86_64</classifier>
        </dependency>
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>ffmpeg</artifactId>
            <version>4.4-1.5.6</version>
            <classifier>linux-x86_64</classifier>
        </dependency>

2 转换工具类

package com.hisql.iot.javacv.util;

import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.*;
import org.bytedeco.javacv.FrameRecorder.Exception;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;

/**
 * 音频参数转换(包含采样率、编码,位数,通道数)
 *
 * @author fmi110
 */
public class AudioConvertUtil {
    private static Logger log = LoggerFactory.getLogger(AudioConvertUtil.class);

    /**
     * 转换音频数据为g711a格式
     *
     * @param inputFile
     * @return
     */
    public static byte[] convert2G711a(byte[] inputFile) {
        return convert(inputFile, avcodec.AV_CODEC_ID_PCM_ALAW, 8000, 64000, 1);
    }

    /**
     * 通用音频格式参数转换
     *
     * @param inputFile    -导入音频文件
     * @param audioCodec   -音频编码
     * @param sampleRate   -音频采样率
     * @param audioBitrate -音频比特率
     */
    public static byte[] convert(byte[] inputFile, int audioCodec, int sampleRate, int audioBitrate,
                                 int audioChannels) {
        Frame audioSamples = null;
        // 音频录制(输出地址,音频通道)
        FFmpegFrameRecorder  recorder    = null;
        ByteArrayInputStream inputStream = new ByteArrayInputStream(inputFile);
        //抓取器
        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputStream);

        // 开启抓取器
        if (!start(grabber)) {
            return null;
        }
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        recorder = new FFmpegFrameRecorder(outStream, audioChannels);
        recorder.setAudioOption("crf", "0");
        recorder.setAudioCodec(audioCodec);
        recorder.setAudioBitrate(audioBitrate);
        recorder.setAudioChannels(audioChannels);
        recorder.setSampleRate(sampleRate);
        recorder.setAudioQuality(0);
        recorder.setAudioOption("aq", "10");
        recorder.setFormat("wav"); // 不指定格式无法写入内存,会报错


        // 开启录制器
        if (!start(recorder)) {
            return null;
        }
        try {
            // 抓取音频
            while ((audioSamples = grabber.grab()) != null) {
                recorder.setTimestamp(grabber.getTimestamp());
                recorder.record(audioSamples);
            }
            log.info("转换音频成功");
        } catch (Exception | org.bytedeco.javacv.FrameGrabber.Exception e) {
            log.error("[{}]转换音频失败:{}", inputFile, e.getMessage());
            return null;
        } finally {
            stop(grabber);
            stop(recorder);
        }
        return outStream.toByteArray();
    }

    /**
     * 通用音频格式参数转换
     *
     * @param inputFile    -导入音频文件
     * @param outputFile   -导出音频文件
     * @param audioCodec   -音频编码
     * @param sampleRate   -音频采样率
     * @param audioBitrate -音频比特率
     */
    public static boolean convert(String inputFile, String outputFile, int audioCodec, int sampleRate, int audioBitrate,
                                  int audioChannels) {
        Frame audioSamples = null;
        // 音频录制(输出地址,音频通道)
        FFmpegFrameRecorder recorder = null;
        //抓取器
        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputFile);

        // 开启抓取器
        if (!start(grabber)) {
            return false;
        }

        recorder = new FFmpegFrameRecorder(outputFile, audioChannels);
        recorder.setAudioOption("crf", "0");
        recorder.setAudioCodec(audioCodec);
        recorder.setAudioBitrate(audioBitrate);
        recorder.setAudioChannels(audioChannels);
        recorder.setSampleRate(sampleRate);
        recorder.setAudioQuality(0);
        recorder.setAudioOption("aq", "10");


        // 开启录制器
        if (!start(recorder)) {
            return false;
        }
        try {
            // 抓取音频
            while ((audioSamples = grabber.grab()) != null) {
                recorder.setTimestamp(grabber.getTimestamp());
                recorder.record(audioSamples);
            }
            log.info("转换音频成功:\r\n\tinput:{}\r\n\toutput:{}", inputFile, outputFile);
        } catch (Exception | org.bytedeco.javacv.FrameGrabber.Exception e) {
            log.error("[{}]转换音频失败:{}", inputFile, e.getMessage());
            return false;
        } finally {
            stop(grabber);
            stop(recorder);
        }
        return true;
    }

    public static boolean start(FrameGrabber grabber) {
        try {
            grabber.start();
            return true;
        } catch (org.bytedeco.javacv.FrameGrabber.Exception e2) {
            try {
                log.error("首次打开抓取器失败,准备重启抓取器...");
                grabber.restart();
                return true;
            } catch (org.bytedeco.javacv.FrameGrabber.Exception e) {
                try {
                    log.error("重启抓取器失败,正在关闭抓取器...");
                    grabber.stop();
                } catch (org.bytedeco.javacv.FrameGrabber.Exception e1) {
                    log.error("停止抓取器失败!");
                }
            }

        }
        return false;
    }

    public static boolean start(FrameRecorder recorder) {
        try {
            recorder.start();
            return true;
        } catch (Exception e2) {
            try {
                log.error("首次打开录制器失败!准备重启录制器...");
                recorder.stop();
                recorder.start();
                return true;
            } catch (Exception e) {
                try {
                    log.error("重启录制器失败!正在停止录制器...");
                    recorder.stop();
                } catch (Exception e1) {
                    log.error("关闭录制器失败!");
                }
            }
        }
        return false;
    }

    public static boolean stop(FrameGrabber grabber) {
        try {
            grabber.flush();
            grabber.stop();
            return true;
        } catch (org.bytedeco.javacv.FrameGrabber.Exception e) {
            return false;
        } finally {
            try {
                grabber.stop();
            } catch (org.bytedeco.javacv.FrameGrabber.Exception e) {
                log.error("关闭抓取器失败");
            }
        }
    }

    public static boolean stop(FrameRecorder recorder) {
        try {
            recorder.stop();
            recorder.release();
            return true;
        } catch (Exception e) {
            return false;
        } finally {
            try {
                recorder.stop();
            } catch (Exception e) {

            }
        }
    }

    public static void main(String[] args) throws IOException {
        //convert("d:\\audio.wav","d:\\audio.mp3", avcodec.AV_CODEC_ID_MP3,8000,16,1); // 转成map3
        //convert("d:\\audio.wav", "d:\\audio_g711a.wav", avcodec.AV_CODEC_ID_PCM_ALAW, 8000, 8, 1); // 转成g711a a-law 编码的文件
        FileInputStream inputStream = new FileInputStream("D:\\rec-13500ms-16kbps-48000hz.wav");
        byte[]          bytes       = new byte[inputStream.available()];
        inputStream.read(bytes);
        byte[] g711aData = convert(bytes, avcodec.AV_CODEC_ID_PCM_ALAW, 8000, 64000, 1);
        new FileOutputStream("d:\\g711a.wav").write(g711aData);
    }
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要使用 javacv 将视频分离为音频和视频,可以使用 FFmpegFrameGrabber 类来读取视频文件,然后使用 FFmpegFrameRecorder 类将音频和视频分别输出为单独的文件。 下面是一个简单的代码示例: ```java import org.bytedeco.javacv.*; public class VideoSplitter { public static void main(String[] args) throws Exception { FFmpegFrameGrabber grabber = new FFmpegFrameGrabber("input.mp4"); grabber.start(); FFmpegFrameRecorder audioRecorder = new FFmpegFrameRecorder("output_audio.mp3", grabber.getAudioChannels()); audioRecorder.setAudioCodec(avcodec.AV_CODEC_ID_MP3); audioRecorder.start(); FFmpegFrameRecorder videoRecorder = new FFmpegFrameRecorder("output_video.mp4", grabber.getImageWidth(), grabber.getImageHeight()); videoRecorder.setVideoCodec(avcodec.AV_CODEC_ID_MPEG4); videoRecorder.start(); Frame frame; while ((frame = grabber.grab()) != null) { if (frame.samples != null) { audioRecorder.record(frame); } else { videoRecorder.record(frame); } } grabber.stop(); audioRecorder.stop(); videoRecorder.stop(); } } ``` 在上面的示例中,我们首先创建了一个 FFmpegFrameGrabber 对象来读取视频文件。然后,我们创建了两个 FFmpegFrameRecorder 对象,一个用于输出音频文件,一个用于输出视频文件。我们使用 setAudioCodec() 和 setVideoCodec() 方法来设置音频和视频编解码器。最后,我们循环读取视频文件中的每一帧,根据帧的类型将其写入对应的输出文件中。最后,我们停止读取器和记录器以完成分离操作。 需要注意的是,由于 javacv 依赖于 FFmpeg 库,因此需要正确配置 FFmpeg 的路径才能正常使用。具体配置方法可以参考 javacv 的文档。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值