【问题标题】:Need to apply seeking in ogg playing using Java需要在使用Java的ogg播放中申请搜索
【发布时间】:2025-11-23 10:05:02
【问题描述】:

我一直在为一个需要实现 mp3 和 ogg 播放器(包括搜索)的多平台桌面应用程序工作,现在我的 mp3 部分还可以,但是在 ogg 播放中搜索不起作用......

我正在使用 javazoom.jlgui 的BasicPlayer,下面是我的搜索功能

/**
 * Skip bytes in the File inputstream. It will skip N frames matching to
 * bytes, so it will never skip given bytes length exactly.
 *
 * @param bytes
 * @return value>0 for File and value=0 for URL and InputStream
 * @throws BasicPlayerException
 * @throws IOException
 */
protected long skipBytes(long bytes) throws BasicPlayerException, NullPointerException, IOException {

    long totalSkipped = 0;

    if (m_dataSource instanceof File) {
        log.info("Bytes to skip : " + bytes);
        int previousStatus = m_status;
        m_status = SEEKING;
        long skipped = 0;

        synchronized (m_audioInputStream) {
            notifyEvent(BasicPlayerEvent.SEEKING, getEncodedStreamPosition(), -1, null);
            initAudioInputStream();

            if (m_audioInputStream != null) {
                // Loop until bytes are really skipped.
                while (totalSkipped < (bytes - SKIP_INACCURACY_SIZE)) {
                    skipped = m_audioInputStream.skip(bytes - totalSkipped);
                    if (skipped == 0) {
                        break;
                    }

                    totalSkipped = totalSkipped + skipped;
                    log.info("Skipped : " + totalSkipped + "/" + bytes);

                    if (totalSkipped == -1) {
                        throw new BasicPlayerException(BasicPlayerException.SKIPNOTSUPPORTED);
                    }
                }
            }
        }

        notifyEvent(BasicPlayerEvent.SEEKED, getEncodedStreamPosition(), -1, null);
        m_status = OPENED;

        if (previousStatus == PLAYING) {
            startPlayback();
        } else if (previousStatus == PAUSED) {
            startPlayback();
            pausePlayback();
        }
    }

    return totalSkipped;
}

有没有办法添加另一个seek函数来实现seek for ogg?提前谢谢...

不太了解它的工作原理,但它适用于 mp3,包括搜索, 音频播放、暂停、停止 在 ogg 播放中,暂停、停止都可以,但是寻找是问题,当寻找的音频播放从头开始时。

我没有更改代码的任何部分 BasicPlayer Api 的来源是 http://www.javazoom.net/jlgui/sources/basicplayer3.0.zip

当我仔细检查细节时,使用此代码实现的jlgui3.0播放器也没有实现寻求Ogg播放,他们已经提到了。所以当前代码需要添加一个单独的查找函数来播放 Ogg 并使用它而不是当前的seek(),只要播放的音频是 Ogg...

我不知道该怎么做,请帮助我提供良好的参考来源和实现相同的简单方法...

【问题讨论】:

  • “在 ogg 游戏中寻找不起作用” 它在做什么?还是不做?还有else if (previousStatus == PAUSED) { startPlayback(); pausePlayback(); }? (我可能不知道你的程序是如何工作的,但start -> 立即pause 似乎很可疑。)
  • @Radiodef:问题已编辑...
  • 我不认为这将是一个简单、直接的任务来实现搜索。 OGG 格式很不一样,对搜索的底层支持似乎不正确。
  • OGG.. 最好先尝试将整个音轨解码为 PCM,然后再播放/搜索。所有音频解码器都必须先从压缩格式转换为 PCM,然后才能听到它,所以为什么不在发送到扬声器之前先寻找 PCM?无论如何,对于 OGG 搜索,您必须遍历文件的字节以找到 OGG 页面的开头(x4F\x67\x67\x53),然后向前移动 6 个字节,从第 7 个字节到第 14 个字节读取 Granule Pos(8 个字节)。现在复杂的是:什么是音频编解码器? Flac、Opus、Vorbis? GranulePos 可能意味着到目前为止解码了多少 PCM 样本(样本 = 时间)
  • 是的,它是可能的,但对于大尺寸来说并不理想(30mb 将使用大约 318mb 的内存?)。一些应用程序改为写入硬盘驱动器临时文件。但我听到了您的担忧,并会尽快提供解决方案。我不使用Java,所以正确地建议这个是一个问题。你能处理字节吗?意思是从位置查找和读取?你也可以写值到一些新的字节数组吗?这是因为在某些系统中,寻找意味着从寻找的位置中提取剩余的字节部分并提供给 OGG 解码器。每次搜索都成为原始文件字节的新“抓取”

标签: java ogg seek multiplatform audio-player


【解决方案1】:

我认为这个库可能不足以满足您的需求。查看jlGui的源代码,(粘贴在下面)仅.mp3文件和.wav文件支持搜索。

此外,它背后的逻辑有些幼稚,因为它只向前跳了固定数量的字节。对于 PCM 格式的 .wav 文件,跳过的字节数将始终与跳过的时间量成正比,但对于可变比特率 .mp3 文件,跳过的时间量将随着文件中不同点的瞬时比特率而变化. Ogg Vorbis 是一种支持多路复用的容器格式,这使得查找比仅仅在文件中跳转和重新同步解码器更加复杂。

作为替代方案,我建议使用 JavaSound 或 JavaFX API,它们都可以播放音频文件并查找您提供的时间,而不是字节偏移量。

来自 jlGui:

protected void processSeek(double rate)
{
    try
    {
        if ((audioInfo != null) && (audioInfo.containsKey("audio.type")))
        {
            String type = (String) audioInfo.get("audio.type");
            // Seek support for MP3.
            if ((type.equalsIgnoreCase("mp3")) && (audioInfo.containsKey("audio.length.bytes")))
            {
                long skipBytes = (long) Math.round(((Integer) audioInfo.get("audio.length.bytes")).intValue() * rate);
                log.debug("Seek value (MP3) : " + skipBytes);
                theSoundPlayer.seek(skipBytes);
            }
            // Seek support for WAV.
            else if ((type.equalsIgnoreCase("wave")) && (audioInfo.containsKey("audio.length.bytes")))
            {
                long skipBytes = (long) Math.round(((Integer) audioInfo.get("audio.length.bytes")).intValue() * rate);
                log.debug("Seek value (WAVE) : " + skipBytes);
                theSoundPlayer.seek(skipBytes);
            }
            else posValueJump = false;
        }
        else posValueJump = false;
    }
    catch (BasicPlayerException ioe)
    {
        log.error("Cannot skip", ioe);
        posValueJump = false;
    }
}

【讨论】: