ffmpeg - 使用 xuggler 转码音频

标签 ffmpeg xuggle xuggler

我正在尝试转换带有标题的音频文件

Opening audio decoder: [pcm] Uncompressed PCM audio decoder
AUDIO: 44100 Hz, 2 ch, s16le, 1411.2 kbit/100.00% (ratio: 176400->176400)
Selected audio codec: [pcm] afm: pcm (Uncompressed PCM)

我想将此文件转码为 mp3 格式。我有以下代码片段,但效果不佳。我用 XUGGLER code snippet for transcoding audio and video 写的.

音频解码器是

    audioDecoder = IStreamCoder.make(IStreamCoder.Direction.DECODING, ICodec.findDecodingCodec(ICodec.ID.CODEC_ID_PCM_S16LE));
    audioDecoder.setSampleRate(44100);
    audioDecoder.setBitRate(176400);
    audioDecoder.setChannels(2);
    audioDecoder.setTimeBase(IRational.make(1,1000));
    if (audioDecoder.open(IMetaData.make(), IMetaData.make()) < 0)
        return false;
    return true; 

音频编码器是

    outContainer = IContainer.make();
    outContainerFormat = IContainerFormat.make();
    outContainerFormat.setOutputFormat("mp3", urlOut, null);
    int retVal = outContainer.open(urlOut, IContainer.Type.WRITE, outContainerFormat);
    if (retVal < 0) {
        System.out.println("Could not open output container");
        return false;
    }
    outAudioCoder = IStreamCoder.make(IStreamCoder.Direction.ENCODING, ICodec.findEncodingCodec(ICodec.ID.CODEC_ID_MP3));
    outAudioStream = outContainer.addNewStream(outAudioCoder);
    outAudioCoder.setSampleRate(new Integer(44100));
    outAudioCoder.setChannels(2);
    retVal = outAudioCoder.open(IMetaData.make(), IMetaData.make());
    if (retVal < 0) {
        System.out.println("Could not open audio coder");
        return false;
    }
    retVal = outContainer.writeHeader();
    if (retVal < 0) {
        System.out.println("Could not write output FLV header: ");
        return false;
    }
    return true;

这是编码方法,我发送 32 字节的数据包进行转码

public void encode(byte[] audioFrame){
    //duration of 1 video frame
    long lastVideoPts = 0;

    IPacket packet_out = IPacket.make();
    int lastPos = 0;
    int lastPos_out = 0;

    IAudioSamples audioSamples = IAudioSamples.make(48000, audioDecoder.getChannels());
    IAudioSamples audioSamples_resampled = IAudioSamples.make(48000, audioDecoder.getChannels());

    //we always have 32 bytes/sample
    int pos = 0;
    int audioFrameLength = audioFrame.length;
    int audioFrameCnt = 1;
    iBuffer = IBuffer.make(null, audioFrame, 0, audioFrameLength);
    IPacket packet = IPacket.make(iBuffer);
    //packet.setKeyPacket(true);
    packet.setTimeBase(IRational.make(1,1000));
    packet.setDuration(20);
    packet.setDts(audioFrameCnt*20);
    packet.setPts(audioFrameCnt*20);
    packet.setStreamIndex(1);
    packet.setPosition(lastPos);
    lastPos+=audioFrameLength;
    int pksz = packet.getSize();
    packet.setComplete(true, pksz);
    /*
    * A packet can actually contain multiple samples
    */
    int offset = 0;
    int retVal;
    while(offset < packet.getSize())
    {
        int bytesDecoded = audioDecoder.decodeAudio(audioSamples, packet, offset);
        if (bytesDecoded < 0)
            throw new RuntimeException("got error decoding audio ");
        offset += bytesDecoded;
        if (audioSamples.isComplete())
        {
            int samplesConsumed = 0;
            while (samplesConsumed < audioSamples.getNumSamples()) {
                retVal = outAudioCoder.encodeAudio(packet_out, audioSamples, samplesConsumed);
                if (retVal <= 0)
                    throw new RuntimeException("Could not encode audio");
                samplesConsumed += retVal;
                if (packet_out.isComplete()) {
                    packet_out.setPosition(lastPos_out);
                    packet_out.setStreamIndex(1);
                    lastPos_out+=packet_out.getSize();
                    retVal = outContainer.writePacket(packet_out);
                    if(retVal < 0){
                        throw new RuntimeException("Could not write data packet");
                    }
                }
            }
        }

    }

}

我得到了一个输出文件,但它没有被播放。我对音频编码和采样的经验很少。提前致谢。

最佳答案

我终于能够将 pcm 流实时转码为 mp3 流。

代码中存在几个问题:

  • 我试图仅对一件事进行转码,即音频,并且代码片段对音频和视频进行转码,因此设置流索引时出现问题。

    packet_out.setStreamIndex(1); packet_out.setStreamIndex(0)

  • 第二件事是计算 ffmpeg guid

    channel * bits * sampling rate = bit rate
    

    这件事我最后算错了。

  • 音频样本中的样本数量取决于您的采样率。我的代码中这是错误的。

注意:这是一个相当旧的代码

 byte[] data = new byte[418];

public void encode(byte[] audioFrame) {
    IPacket packet_out = IPacket.make();
    int lastPos_out = 0;


    IAudioSamples audioSamples = IAudioSamples.make(11025, audioDecoder.getChannels());
    //IAudioSamples audioSamples_resampled = IAudioSamples.make(48000, audioDecoder.getChannels());

    //we always have 32 bytes/sample
    int pos = 0;
    int audioFrameLength = audioFrame.length;
    int audioFrameCnt = 1;
    iBuffer = IBuffer.make(null, audioFrame, 0, audioFrameLength);
    IPacket packet = IPacket.make(iBuffer);
    //packet.setKeyPacket(true);
    packet.setTimeBase(IRational.make(1, 1000));
    packet.setStreamIndex(0);
    int pksz = packet.getSize();
    packet.setComplete(true, pksz);
   /*
    * A packet can actually contain multiple samples
    */
    int offset = 0;
    int retVal;
    while (offset < packet.getSize()) {
        int bytesDecoded = audioDecoder.decodeAudio(audioSamples, packet, offset);
        if (bytesDecoded < 0)
            throw new RuntimeException("got error decoding audio ");
        offset += bytesDecoded;
        if (audioSamples.isComplete()) {
            /*audioResampler.resample(audioSamples_resampled, audioSamples, audioSamples.getNumSamples());
            audioSamples_resampled.setPts(Global.NO_PTS);*/
            int samplesConsumed = 0;
            while (samplesConsumed < audioSamples.getNumSamples()) {
                retVal = outAudioCoder.encodeAudio(packet_out, audioSamples, samplesConsumed);
                if (retVal <= 0)
                    throw new RuntimeException("Could not encode audio");
                samplesConsumed += retVal;
                if (packet_out.isComplete()) {
                    packet_out.setPosition(lastPos_out);
                    packet_out.setStreamIndex(0);
                    lastPos_out += packet_out.getSize();
                    System.out.println("size" + packet_out.getSize());
                    packet_out.getByteBuffer().get(data,0,packet_out.getSize());
                    try {
                        fo.write(data);
                    } catch (IOException e) {
                        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                    }
                    packet_out.reset();
                    //retVal = outContainer.writePacket(packet_out);
                    if (retVal < 0) {
                        throw new RuntimeException("Could not write data packet");
                    }
                }
            }
        }
    }
}

关于ffmpeg - 使用 xuggler 转码音频,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13916123/

相关文章:

FFMPEG - 视频中带有 Splash 图像的绿色转换

java - openIMAJ 缺少类或错误的库

Java - Xuggle 在 Windows 7 64 位上崩溃

java - 单独线程中的屏幕捕获导致 Java 应用程序缓慢/无响应

javascript - 如何使用 nodejs 和 ffmpeg 生成视频预览缩略图?

ffmpeg - 使用 ffmpeg : playback issue in older quicktime (7. 6.6 从 PNG 创建 MOV

java/xuggle - 将图像数组编码到电影中

java - xuggler 输入输出流处理程序 SIGSEGV

java - Xuggler - 从 RTMP 流获取快照

ffmpeg - 如何在使用 ffmpeg 计算 vmaf 分数时同步帧