当前位置: 首页 > 面试题库 >

MP3:一种以毫秒为单位获取给定字节位置的方法?

微生雨泽
2023-03-14
问题内容

我创建了一个Servlet,它从客户端请求的任何给定字节位置开始返回流(来自MP3文件)。这样,客户端可以在任何给定的字节位置立即开始播放,而无需进行任何本地搜索。

现在,我有一个滑块,可以直观地看到进度。我正在使用当前字节位置来更新滑块。但是,我也想以秒为单位显示当前位置。

这要求服务器可以将以字节为单位的当前位置“转换”为以毫秒为单位的位置。然后,服务器可以只提供以毫秒为单位的流开始位置作为响应头。

有人对如何计算以字节为单位的当前位置有经验吗?

更新

从注释中可以明显看出,没有精确的方法可以将字节转换为毫秒,反之亦然,而无需将MP3文件解码到一定程度(以毫秒或字节为单位),然后确定已读取的字节数或毫秒为单位演奏过的
但是,考虑到一台服务器(例如100个用户将同时请求文件)的服务器,这种方法显然效果不佳。然后,服务器将必须解码MP3文件直到请求的位置,然后从该点返回流。我选择了以性能来交换精度,并采取了一种方法,该方法可以为我提供大概的位置,并且对播放器来说已经足够了,其目的只是播放音轨(而不将音频与其他信号源同步到毫秒)。

我所做的是,播放器(在客户端)现在仅关心毫秒(MS)。也就是说,进度条的当前值和最大值以MS为单位,而不是字节数(如其最初那样)。为了从任何给定位置开始播放,客户端请求服务器(servlet)提供从MS中任何给定位置开始的音频流。servlet使用JAudioTagger获取有关文件的详细信息,然后对MS位置对应的字节位置进行近似计算。我已经对其进行了测试,它可以与CBR(恒定比特率)文件一起很好地工作。该方法不适用于VBR(可变比特率)文件,因为帧大小可能会有所不同。请注意,这只是一个播放器,用于播放音乐文件。并非旨在将音频与其他媒体同步到MS。

更新(2012年7月3日)

servlet已经使用下面的代码运行了一段时间,并且一切运行良好。已经播放了成千上万的MP3,并且从ms到字节的近似值效果很好。

更新(2017年1月3日)

该servlet仍以完全相同的代码运行,并且成千上万的MP3播放良好。在制作期间,没有人抱怨播放和定时

/**
 * Returns the approximate byte position for any given position in
 * milliseconds.
 *
 * http://www.java2s.com/Open-Source/Android/Mp3/needletagger/org/jaudiotagger/audio/mp3/MP3AudioHeader.java.htm
 * http://www.autohotkey.com/forum/topic29420.html
 *
 * @param   file the <code>File</code> for which the byte position for the
 *          provided position in milliseconds is to be returned.
 * @param   ms a <code>long</code> being the position in milliseconds for
 *          which the corresponding byte position is to be returned.
 * @return  a <code>long</code> being the byte position, or <b>-1</b> if the
 *          position in bytes could not be obtained.
 */
public static long getApproximateBytePositionForMilliseconds(File file, long ms) {

    long bytePosition = -1;

    try {

        AudioFile audioFile = AudioFileIO.read(file);
        AudioHeader audioHeader = audioFile.getAudioHeader();

        if (audioHeader instanceof MP3AudioHeader) {
            MP3AudioHeader mp3AudioHeader = (MP3AudioHeader) audioHeader;
            long audioStartByte = mp3AudioHeader.getMp3StartByte();
            long audioSize = file.length() - audioStartByte;
            long frameCount = mp3AudioHeader.getNumberOfFrames();
            long frameSize = audioSize / frameCount;

            double frameDurationInMs = (mp3AudioHeader.getPreciseTrackLength() / (double) frameCount) * 1000;
            double framesForMs = ms / frameDurationInMs;
            long bytePositionForMs = (long) (audioStartByte + (framesForMs * frameSize));
            bytePosition = bytePositionForMs;
        }

        return bytePosition;

    } catch (Exception e) {
        return bytePosition;
    }

}

问题答案:

它不是那样工作的。即使您的MP3文件是恒定比特率编码的,哪个字节位置编码流中的哪一秒也是可变的。(当然,VBR编码使得很多
比CBR变量,但都是一样的。)可靠地获取这些信息的唯一方法是实际数据流解码,最高到这一点,你可能不希望做。这就是为什么当您跳来跳去时,甚至XMMS之类的专业播放器也无法可靠地更新滑块的原因。



 类似资料:
  • 问题内容: 有什么办法可以使时间戳记中的毫秒数变为或(或出于好奇而使毫秒数)? 是否有这样的事情: 或者,唯一的选择是使用从? 问题答案: 在MySQL中 以秒 为单位获取Unix时间戳: 详细信息:http : //dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_unix- timestamp 未经测试的

  • 问题内容: Linux中是否有shell命令来获取时间(以毫秒为单位)? 问题答案: 返回秒数+当前纳秒。 因此,这就是您所需要的。 例: 返回自纪元以来的秒数(如果有用)。

  • Linux中是否有shell命令来获取以毫秒为单位的时间?

  • 问题内容: 我正在尝试在Java字节变量中设置位。它确实提供了类似的适当方法。有人知道我该怎么实现吗? 我可以逐位遍历给定的字节: 但是我不能将此位置设置为1或0,可以吗? 问题答案: 使用按位 OR ()和 AND ()运算符。要设置一点,即将其转到: 取消设置或将其转到: 有关示例,请参见高级Java /按位运算符。

  • 问题内容: 我有一个来自sqllite数据库的格式化日期,要在图形视图中使用它,我需要将其格式化为长整数。 格式为: 2012-07-11 10:55:21 如何将其转换为毫秒? 问题答案: 您可以使用以下代码将字符串转换为Date对象: 然后使用内置方法将其转换为毫秒

  • 问题内容: 我通过传递ipAddress来对方法进行调用,它会返回ipAddress的位置,例如国家/地区,城市等。因此,我试图查看每个调用花费的时间。因此,我在调用方法之前设置了start_time,在调用之后设置了end_time。 所以有时候我得到的差为0 。并且resp包含有效的响应。 因此,这意味着有时需要0毫秒才能恢复响应。任何建议将不胜感激。 问题答案: 试试这个