javacv-ffmpeg播放视频里的音频

在javacv封装的ffmpeg包中,可以通过FFMpegFrameGrabber捕获image数据和sample数据,而且捕获的都是译码后的。下面通过一个Demo来实现如何处理sample数据。

(1) 首先实例化一个FFMpegFrameGrabber对象,然后调用grabSamples对象就可以得到一个包含音频数据的帧对象Frame,其Buffer[] samples域就是存放的就是解码后的音频数据。samples数组的长度是1或者2,这个取决于采样数据格式的类型。

(2) ffmpeg采样的数据类型在avutil.java文件中有描述,如下图所示,可以看到,采样数据的类型有无符号short,有符号short还有float,double,int等等,这些都可以对应于IntBuffer,FloatBuffer,DoubleBuffer,ShortBuffer。

javacv-ffmpeg播放视频里的音频_第1张图片

(3)接着介绍ffmpeg中planar和非planer的概念:

planar型:AV_SAMPLE_FMT中有加P后缀的比如FLTP,S16P等就是planar型,对于planar型的数据,返回的Frame中samples的长度为2,sample[0]就是存放立体声的第一个声道数据,sample[1]就是立体声的第二个声道数据。所以我们要将左右声道的数据合并成一个流后送入java的sourceDataLine中播放。

非planar型:没有加p后缀的类型,这类型返回的Frame中samples的长度为1,那么也就是左右声道的数据已经合并成一个流了,那么我们直接送入sourceDataLine播放即可。

​
​
import org.bytedeco.javacpp.avutil;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.FrameGrabber;

import javax.sound.sampled.*;
import javax.swing.*;

import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

/**
 * 播放视频里面的音频
 */
public class audioPlayback {
    private AudioFormat af = null;
    private SourceDataLine sourceDataLine;
    private DataLine.Info dataLineInfo;
    public audioPlayback(String musicPath) throws FrameGrabber.Exception {
        FFmpegFrameGrabber fg = new FFmpegFrameGrabber(musicPath);
        int sec = 60;
        Frame f;
        fg.start();
        //之前纯音频文件设置了时间戳有问题,视频没问题。
        //在JavaCV1.4.1修复了这个问题,因此可以调用
        fg.setTimestamp(sec*1000000);
        sampleFormat = fg.getSampleFormat();
        printMusicInfo(fg);
        initSourceDataLine(fg);
        while(true){
            f = fg.grabSamples();
            if(f == null){
                fg.stop();
                System.exit(0);
            }
            processAudio(f.samples);
        }
    }
    Buffer[] buf;
    FloatBuffer leftData,rightData;
    ShortBuffer ILData,IRData;
    ByteBuffer TLData,TRData;
    float vol = 1;//音量
    int sampleFormat;
    byte[] tl,tr;
    byte[] combine;
    private void processAudio(Buffer[] samples) {
        int k;
        buf = samples;
        switch(sampleFormat){
            case avutil.AV_SAMPLE_FMT_FLTP://平面型左右声道分开。
                leftData = (FloatBuffer)buf[0];
                TLData = floatToByteValue(leftData,vol);
                rightData = (FloatBuffer)buf[1];
                TRData = floatToByteValue(rightData,vol);
                tl = TLData.array();
                tr = TRData.array();
                combine = new byte[tl.length+tr.length];
                k = 0;
                for(int i=0;iv) f = v;
            if(f<-v) f = v;
            //默认转为大端序
            res.putShort(i*2,(short)f);//注意乘以2,因为一次写入两个字节。
        }
        return res;
    }
    private void printMusicInfo(FFmpegFrameGrabber fg) {
        //System.out.println("音频采样率"+fg.getSampleRate());
        //System.out.println("音频通道数"+fg.getAudioChannels());
    }

    public static void main(String[] args){
        /**
         * 测试成功。
         */
        //Stream #0:1: Audio: mp3 (U[0][0][0] / 0x0055), 44100 Hz, stereo, s16p, 96 kb/s
        //mp3,立体声,有short 16bit 平面型测试。
        String s1 = "C:\\Users\\Administrator\\Videos\\myVideo.avi";
        //Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 132 kb/s (default)
        //aac,立体声,float 平面型测试。
        String s2 = "C:\\Users\\Administrator\\Videos\\c.mp4";
        // Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 22050 Hz, 1 channels, s16, 352 kb/s
        //wav, 单通道,有符号short 16bot 非平面型测试
        String s3 = "C:\\Users\\Administrator\\Music\\滴答.wav";
        //Stream #0:0: Audio: flac, 44100 Hz, stereo, s16
        //flac, 双通道,有符号short 16bit 非平面型测试
        String s4 = "C:\\Users\\Administrator\\Music\\Sample Music\\陈小春 - 独家记忆.flac";
        // Stream #0:1: Audio: flac, 48000 Hz, stereo, s16 (default)
        //flac, 双通道,有符号short 16bit 非平面型测试。
        String s5 = "E:\\BaiduYunDownload\\t.mkv";
        //Stream #0:0: Audio: ac3, 44100 Hz, stereo, fltp, 320 kb/s
        //ac3 立体声,float 平面型测试
        String s7 = "D:\\FFOutput\\陈小春 - 独家记忆.ac3";
        //Stream #0:0: Audio: amr_nb (samr / 0x726D6173), 8000 Hz, mono, flt
        //amr,单声道,float 非平面型
        String s8 = "D:\\FFOutput\\陈小春 - 独家记忆.amr";
        //Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 311 kb/s (default)
        //m4a 立体声,float 平面型
        String s9 = "D:\\FFOutput\\陈小春 - 独家记忆.m4a";
        //Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 311 kb/s (default)
        //m4r 立体声,float 平面型
        String s10 = "D:\\FFOutput\\陈小春 - 独家记忆.m4r";
        //Stream #0:0: Audio: adpcm_yamaha, 8000 Hz, mono, s16, 32 kb/s
        //mmf 单声道,有符号short平面型
        String s11 = "D:\\FFOutput\\陈小春 - 独家记忆.mmf";
        //Stream #0:0: Audio: mp2, 44100 Hz, stereo, s16p, 320 kb/s
        //mp2 ,立体声,有符号short平面型
        String s12 = "D:\\FFOutput\\陈小春 - 独家记忆.mp2";
        //Stream #0:1: Audio: vorbis, 44100 Hz, stereo, fltp
        //ogg 立体声,float平面型
        String s13 = "D:\\FFOutput\\陈小春 - 独家记忆.ogg";
        //Stream #0:1: Audio: wmav2 (a[1][0][0] / 0x0161), 44100 Hz, 2 channels, fltp, 320 kb/s
        //wma,立体声,float平面型
        String s14 = "D:\\FFOutput\\陈小春 - 独家记忆.wma";
        //Stream #0:0: Audio: wavpack, 44100 Hz, stereo, s16p
        //wv,立体声,有符号short平面型
        String s15 = "D:\\FFOutput\\陈小春 - 独家记忆.wv";
        /**
         * 测试失败:ape。
         */
        //Stream #0:0: Audio: ape (APE  / 0x20455041), 44100 Hz, stereo, s16p
        //ape,双通道,有符号short 16bit 平面型。
        String s6 = "C:\\Users\\Administrator\\Music\\a.ape";
        try {
            new audioPlayback(s1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

​

​

参考链接:

关于音频采样格式和平面和非平面的概念见这篇文章:

【FFmpeg(2016)】SwrContext重采样结构体

 

你可能感兴趣的:(javaCV,ffmpeg)