You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解析WMA(ASF)格式音乐文件时长以用于初代Xbox音轨描述文件生成

提问:跨平台无依赖获取WMA音频时长方案

我正在开发一款适配初代Xbox音乐菜单的文件生成工具,该工具仅读取WMA格式的音乐文件,基于这些歌曲生成音轨描述文件ST.DB以及对应的文件系统。

目前我需要在ST.DB的对应字段中存储每首歌曲的时长,因此想要编写一个小型工具专门解析WMA文件的音乐时长。我在网上查找了WMA格式的相关说明和文档,目前能找到的方案大多需要调用Windows SDK,对我的需求来说太过冗余,且我的工具需要支持跨平台,无法使用Windows SDK相关接口。

我也尝试过使用ffmpeg/ffprobe实现该需求,但存在两处缺陷:一是二者的输出需要额外二次解析,不够便捷;二是我不希望工具依赖外部程序。

恳请各位提供相关的WMA格式文档或者示例代码,非常感谢!


回答

WMA格式核心逻辑说明

WMA属于ASF容器格式的子类,音频时长不需要解码音频流,仅需读取文件头部的固定字段即可获取,完全不需要依赖系统SDK或者外部程序。

ASF文件头部以固定GUID开头,遍历头部块找到File Properties Object块后,读取其中的Play Duration字段即可,该字段为64位整数,单位是100纳秒,除以10^7即可得到秒级时长,精度完全满足初代Xbox ST.DB的存储要求。

无依赖示例代码(C语言,全平台可用)

#include <stdio.h>
#include <stdint.h>
#include <string.h>

// File Properties Object 固定GUID,小端存储
static const uint8_t wma_fp_guid[16] = {0xA1, 0xDC, 0xAB, 0x8C, 0x47, 0xA9, 0xCF, 0x11, 0x8E, 0xE4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65};

double get_wma_duration(const char* file_path) {
    FILE* fp = fopen(file_path, "rb");
    if (!fp) return -1.0;

    uint8_t guid_buf[16];
    uint64_t obj_size;
    uint64_t header_remain;

    // 跳过ASF头部对象的固定GUID段
    if (fread(guid_buf, 1, 16, fp) != 16) goto err;
    // 读取头部总大小
    if (fread(&obj_size, 8, 1, fp) != 1) goto err;
    // 跳过头部对象的计数和保留字段
    if (fseek(fp, 5, SEEK_CUR) != 0) goto err;

    header_remain = obj_size - 29; // 已读取16+8+5=29字节

    while (header_remain > 24) { // 每个对象至少有16字节GUID + 8字节大小共24字节
        if (fread(guid_buf, 1, 16, fp) != 16) goto err;
        if (fread(&obj_size, 8, 1, fp) != 1) goto err;
        header_remain -= 24;

        if (memcmp(guid_buf, wma_fp_guid, 16) == 0) {
            uint64_t play_duration;
            // 跳过File ID(16字节) + File Size(8字节)
            if (fseek(fp, 24, SEEK_CUR) != 0) goto err;
            if (fread(&play_duration, 8, 1, fp) != 1) goto err;
            fclose(fp);
            // 100纳秒转换为秒
            return (double)play_duration / 10000000.0;
        }

        // 跳转到下一个对象
        if (obj_size < 24 || header_remain < obj_size -24) goto err;
        if (fseek(fp, obj_size -24, SEEK_CUR) != 0) goto err;
        header_remain -= (obj_size -24);
    }

err:
    fclose(fp);
    return -1.0;
}

你可以直接把这段代码嵌入到你的工具中,仅需读取文件头部几十到几百字节即可拿到时长,不需要解析整个文件,也没有任何第三方依赖。

使用注意点

  • 所有ASF结构的数值均为小端存储,x86、ARM等主流架构都是小端,可直接使用;如果需要适配大端架构,自行添加字节序转换逻辑即可
  • 函数解析失败返回-1.0,你可以根据需要添加对应的错误处理逻辑
  • 你可以根据ST.DB的字段要求,把返回的秒级时长转换为毫秒、帧或者Xbox要求的任意单位存储

内容的提问来源于stack exchange,提问作者Aureal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 02:24:03