0

高水平:

我以两种不同的方式使用相同的编码器。

方法#1:录制原始音频并保存到整个文件,然后在全部完成后压缩文件。结果完美的音频

方式#2:记录原始音频,逐帧编码。结果有声跳音

为什么方式#2会导致跳过?

低级

方式#1的代码(写入FileOutputStream fos,并在所有写入完成后压缩)

public void writeSample(short[] buf) throws IOException {
            byte[] byteArray = Util.toByteArray(buf,false);
            bytesWritten += byteArray.length;
            fos.write(byteArray);
        }

方式#2的代码

public void writeSample(short[] buf) throws IOException {
            byte[] byteArray = Util.toByteArray(buf,false);
            bytesWritten += byteArray.length;
            encoder.encode(byteArray);
        }

几乎完美:方法#2 中短缓冲区的长度为 15360。由于这是一个奇数大小,我采用了这种技术:但仍然有轻微的可听跳过:

      ByteArrayInputStream bais = new ByteArrayInputStream(byteArray);
      byte[] readme = new byte[4096];
      int count = bais.read(readme);
      while ( count != -1 ) {
        System.out.println("READING :"+count+ " bytes");
        if(bais.available() < 4096) {
          System.out.println ("LESS THAN 4096 available: "+bais.available());
          byte[] remain = new byte[bais.available()];
          bais.read(remain);
          aacEncoder.encode(remain);
          break;
        }
        aacEncoder.encode(readme);
        count = bais.read(readme);
      }
4

1 回答 1

0

这是交易:当编码器编码时,它并不总是花费相同的时间。有时它只是将一些数据藏起来以备后用,有时它实际上会进行大量的数字运算。它必须等待足够的音频来编码整个 MP3“帧”,否则它只会存储数据。

每次调用需要数字运算的新数据时,如果它需要的时间比音频所代表的时间长,那么就有可能发生丢失的风险。

解决方案是让您的记录线程填充缓冲区并让第二个线程完成所有可能减慢速度或花费不可预测的时间的工作。这包括编码和写入文件。

对于您的缓冲区,如果您的目标是 android 2.3 或更高版本,则可以使用管道I / O。从技术上讲,这不是环形缓冲区,因为它会阻塞,但根据我的经验,它运行得很好。(这个 api 在早期版本的 android 中可用,但你不能设置缓冲区大小。Grrr!)

您可能会发现此链接有助于理解音频 IO 在概念上的实际工作原理:http ://blog.bjornroche.com/2011/11/slides-from-fundamentals-of-audio.html

于 2012-11-20T20:48:33.563 回答