【问题标题】:Java AudioInputStream skip with negative number of bytes always returns 0带有负数字节的 Java AudioInputStream 跳过总是返回 0
【发布时间】:2025-12-03 23:35:01
【问题描述】:

我正在尝试使用AudioInputStream 跳过负数字节 skip(long bytes) 方法。

问题是试图(假设是少量字节......):

int skipped = audioInputStream.skip(-bytes);

总是返回 0 .... 我不知道该怎么办。


Here is the full code github 上的库。

我所做的是每次用户跳过音频时重新创建线路 当我当然可以做得更好时,这非常慢……只需向后或向前。现在它只支持转发...

/**                                                                                                                   
 * Skip bytes in the File input stream. It will skip N frames matching to bytes, so it will never skip given bytes len
 *                                                                                                                    
 * @param bytes                                                                                                       
 *            the bytes                                                                                               
 * @return value bigger than 0 for File and value = 0 for URL and InputStream                                         
 * @throws StreamPlayerException                                                                                      
 *             the stream player exception                                                                            
 */                                                                                                                   
public long seek(long bytes) throws StreamPlayerException {                                                           
    long totalSkipped = 0;                                                                                            

    //If it is File                                                                                                   
    if (dataSource instanceof File) {                                                                                 

        //Check if the requested bytes are more than totalBytes of Audio                                              
        long bytesLength = getTotalBytes();                                                                           
        System.out.println("Bytes: " + bytes + " BytesLength: " + bytesLength);                                       
        if ( ( bytesLength <= 0 ) || ( bytes >= bytesLength )) {                                                      
            generateEvent(Status.EOM, getEncodedStreamPosition(), null);                                              
            return totalSkipped;                                                                                      
        }                                                                                                             

        logger.info(() -> "Bytes to skip : " + bytes);                                                                
        Status previousStatus = status;                                                                               
        status = Status.SEEKING;                                                                                      

        try {                                                                                                         
            synchronized (audioLock) {                                                                                
                generateEvent(Status.SEEKING, AudioSystem.NOT_SPECIFIED, null);                                       
                initAudioInputStream();                                                                               
                if (audioInputStream != null) {                                                                       

                    long skipped;                                                                                     
                    // Loop until bytes are really skipped.                                                           
                    while (totalSkipped < ( bytes )) { //totalSkipped < (bytes-SKIP_INACCURACY_SIZE)))                
                        //System.out.println("Running");                                                              
                        skipped = audioInputStream.skip(bytes - totalSkipped);                                        
                        if (skipped == 0)                                                                             
                            break;                                                                                    
                        totalSkipped += skipped;                                                                      
                        logger.info("Skipped : " + totalSkipped + "/" + bytes);                                       
                        if (totalSkipped == -1)                                                                       
                            throw new StreamPlayerException(StreamPlayerException.PlayerException.SKIP_NOT_SUPPORTED);

                        logger.info("Skeeping:" + totalSkipped);                                                      
                    }                                                                                                 
                }                                                                                                     
            }                                                                                                         
            generateEvent(Status.SEEKED, getEncodedStreamPosition(), null);                                           
            status = Status.OPENED;                                                                                   
            if (previousStatus == Status.PLAYING)                                                                     
                play();                                                                                               
            else if (previousStatus == Status.PAUSED) {                                                               
                play();                                                                                               
                pause();                                                                                              
            }                                                                                                         

        } catch (IOException ex) {                                                                                    
            logger.log(Level.WARNING, ex.getMessage(), ex);                                                           
        }                                                                                                             
    }                                                                                                                 
    return totalSkipped;                                                                                              
}                                                                                                                     

这个问题的继续在这里...Java AudioInputStream how to support skip with negative number of bytes

【问题讨论】:

  • 不是关于这个问题,但我真的很想知道那些不赞成一个问题,却让它成为最爱的人!
  • @snr Me :) 因为我喜欢哈哈“Tell me and I forget, teach me and I may remember, involve me and I learn.”
  • 我从你那里得到了 NullPointerException :D
  • @snr “代码必须编译。输出必须是正确的。”如果你有这个问题的实现,你将永远受到祝福。
  • 更改问题可能会使已为原始问题提供的任何答案无效。你应该问一个关于如何获得你想要的行为的问题,并链接回这个问题作为参考。

标签: java audio skip audioinputstream


【解决方案1】:

AudioInputStream.skip 不支持否定参数。如果您阅读 InputStream.skip 的 Javadoc,它会说(强调我的):

跳过并丢弃此输入流中的 n 字节数据。由于各种原因,skip 方法最终可能会跳过一些较小的字节数,可能是0。这可能是由多种情况中的任何一种造成的;在跳过 n 个字节之前到达文件末尾只是一种可能性。返回实际跳过的字节数。 如果n 为负数,则InputStream 类的skip 方法始终返回0,并且不会跳过任何字节。子类可能会以不同的方式处理负值。

它确实提到子类可能会改变这种行为,但AudioInputStream 的文档没有给出任何迹象表明它会这样做。

类(AudioInputStream)javadoc:

音频输入流是具有指定音频格式和长度的输入流。长度以样本帧而不是字节表示。提供了几种方法用于从流中读取特定数量的字节,或未指定数量的字节。音频输入流跟踪读取的最后一个字节。您可以跳过任意数量的字节以到达稍后的位置进行读取。音频输入流可能支持标记。设置标记时,会记住当前位置,以便您稍后返回。

AudioSystem 类包括许多操作AudioInputStream 对象的方法。例如,这些方法让您:

  • 从外部音频文件、流或URL获取音频输入流
  • 从音频输入流写入外部文件
  • 将音频输入流转换为不同的音频格式

AudioInputStream.skipjavadoc:

跳过并丢弃此音频输入流中指定数量的字节。

此方法将始终跳过整数帧。如果n 未指定整数帧,则最多将跳过n - (n % frameSize) 字节。

另外,如果您查看AudioInputStream.skip 的实现,您会发现如果n&lt;= 0,第二个if 语句立即返回0

@Override
public long skip(long n) throws IOException {
    // make sure not to skip fractional frames
    final long reminder = n % frameSize;
    if (reminder != 0) {
        n -= reminder;
    }
    if (n <= 0) {
        return 0;
    }

    if (frameLength != AudioSystem.NOT_SPECIFIED) {
        // don't skip more than our set length in frames.
        if ((n / frameSize) > (frameLength - framePos)) {
            n = (frameLength - framePos) * frameSize;
        }
    }
    long remaining = n;
    while (remaining > 0) {
        // Some input streams like FileInputStream can return more bytes,
        // when EOF is reached.
        long ret = Math.min(stream.skip(remaining), remaining);
        if (ret == 0) {
            // EOF or not? we need to check.
            if (stream.read() == -1) {
                break;
            }
            ret = 1;
        } else if (ret < 0) {
            // the skip should not return negative value, but check it also
            break;
        }
        remaining -= ret;
    }
    final long temp =  n - remaining;

    // if no error, update our position.
    if (temp % frameSize != 0) {
        // Throw an IOException if we've skipped a fractional number of frames
        throw new IOException("Could not skip an integer number of frames.");
    }
    framePos += temp/frameSize;
    return temp;
}

Java 10 源代码。

【讨论】:

  • 感谢您的回答,我想创建一个实现或解决它。我需要用户在没有 5 秒延迟的情况下实现非常快速的搜索方法。我也考虑过使用Clip,但特别是用于 30 分钟大音频文件的 RAM 量简直太疯狂了。
最近更新 更多