fq 解码 AVI:样本索引优先级、流信息提取与解码加速实战指南
2026/9/24 16:38:13 网站建设 项目流程

fq 解码 AVI:样本索引优先级、流信息提取与解码加速实战指南

【免费下载链接】fqfq - jq for binary formats. Tool, language and decoders for working with binary formats.项目地址: https://gitcode.com/gh_mirrors/fq/fq

fq 是面向二进制格式的 jq 工具,内置了对 AVI(Audio Video Interleaved,微软音视频交错容器)的完整解码支持。本篇指南以 format/riff/avi.md 为骨架,结合 format/riff/avi.go 源码与其 测试数据,系统讲解 fq 如何处理 AVI 中冗余的样本索引机制、如何提取指定流的样本数据、如何快速查看流摘要,以及如何通过关闭样本与扩展块解码来大幅加速解码。读完本文,你将能够用 fq 独立完成 AVI 文件的样本抽取、流级元数据分析和性能调优。

fq 中的 AVI 解码器概览

AVI 解码器位于format/riff包内,与 WAV(wav.go)、AIFF(aiff.go)、WebP(webp.go)等格式共享 RIFF 容器基础实现(format/riff/common.go 中的riffDecode负责递归解析 RIFF chunk 结构并处理 16 位字对齐)。

解码器在 format/riff/avi.go 中注册,核心信息如下:

  • 格式标识:format.AVI,描述为 "Audio Video Interleaved";
  • 解码入口:aviDecode,采用小端字节序(d.Endian = decode.LittleEndian);
  • 默认输入参数(定义于 format/format.go):
    • decode_samples=true:是否解码样本(samples);
    • decode_extended_chunks=true:是否解码扩展块(extended chunks,即 OpenDML AVIX 后续 RIFF 块);
  • 依赖格式组(用于样本深层解码):
    • format.AVC_AU(H.264 访问单元,对应视频流);
    • format.HEVC_AU(H.265 访问单元);
    • format.MP3_Frame(MP3 音频帧);
    • format.FLAC_Frame(FLAC 音频帧)。

通过fq -h avi可以随时查看解码器的帮助信息,与仓库中的 format/riff/testdata/help_avi.fqtest 输出一致:

avi: Audio Video Interleaved decoder Options ======= decode_extended_chunks=true Decode extended chunks decode_samples=true Decode samples

理解 AVI 的样本索引机制:为何存在多种索引

AVI 格式发展历史较长,历史上出现过多种记录媒体样本(音频帧、视频帧)位置的方式,因此一个 AVI 文件可能同时携带多套索引。fq 文档明确说明:

AVI has many redundant ways to index samples so currently.streams[].sampleswill only include samples using the most "modern" method found in the file. That is in order of stream super index, movi ix index then idx1 index.

即:AVI 拥有许多冗余的样本索引方式,因此当前实现中.streams[].samples只会使用文件中找到的最"现代"的索引方法,优先级从高到低为:

  1. Stream super index(流超索引 /indx:即 OpenDMLindx块,位于strl流列表内,属于"现代"索引,支持 64 位偏移与多级子索引;
  2. movi ix index(ix##块):位于movi数据区内的流索引块,chunk id 形如ix00ix01,与具体流编号绑定;
  3. idx1 index(idx1块):传统 AVI 索引,位于文件末尾,采用 32 位偏移的旧式索引。

源码中对应优先级选择的逻辑在 format/riff/avi.go:解码完streams数组后,按顺序尝试三套候选区间——streamIndexSampleRanges(来自indx超索引解析出的子索引)、stream.ixSamples(来自ix块)、idx1Samples(来自idx1),只取第一套非空的作为samples输出,避免同一份样本被重复列出。

这三种索引在解码过程中被分别收集:

  • indxstrl列表内被解析(format/riff/avi.go),解析出的区间暂存于stream.indexes,随后在输出streams时通过aviDecodeChunkIndex逐级展开为子索引区间;
  • ix块在movi区遇到形如ixNN的 chunk id 时解析(format/riff/avi.go),区间累积到对应流(streams[index])的ixSamples
  • idx1块在 RIFF 顶层解析(format/riff/avi.go),每条记录包含id(如00wb)、flags(含key_framelist位)、offsetlength,全部收集到idx1Samples

值得一提的是,idx1offset是相对movi数据区开始位置的偏移,因此使用idx1计算样本绝对位置时,源码会额外加上moviListPos并跳过 32 位的 chunk size 字段(+32,见 format/riff/avi.go)。

提取指定流的样本:.streams[N].samples[] | tobytes

原文档提供了提取流样本的标准命令。例如提取 1 号流(下标从 0 开始)的全部样本,并将每个样本的原始字节拼接后重定向输出:

$ fq '.streams[1].samples[] | tobytes' file.avi > stream01.mp3

命令拆解:

  • .streams[1]:取第二个流的流对象(streams数组按strl声明顺序排列);
  • .samples[]:按上文所述优先级挑选的样本数组展开,每个元素是一个已被深层解码的样本(如mp3_frame);
  • | tobytes:将解码后的样本还原为原始字节串;
  • > stream01.mp3:重定向保存,得到可直接播放的裸 MP3 流。

若文件是双流 AVI(如视频流 + 音频流),把下标换成对应流的序号即可。从仓库测试 format/riff/testdata/mp3.avi.fqtest 可以看到实际效果:该文件只有一个音频流,其streams[0]下的samples[0:3]被逐一解码为(mp3_frame),每个样本内部展开了完整的 MP3 帧结构(header{}side_info{}audio_datacrc_calculated),证明tobytes提取的是帧边界精确的原始数据。

注意:只有strf声明了 fq 支持的编解码格式(见下文"支持的流格式"一节)时,样本才会被深层解码;否则样本会以FieldRawLen原始位形式呈现。

查看流摘要:grep_by 组合查询

当只需要了解每个流"是什么"而不想看全部细节时,原文档提供了流摘要命令:

$ fq -o decode_samples=false '[.chunks[0] | grep_by(.id=="LIST" and .type=="strl") | grep_by(.id=="strh") as {$type} | grep_by(.id=="strf") as {$format_tag, $compression} | {$type,$format_tag,$compression}]' *.avi

这条命令同时适用于多个文件(*.avi),输出每个 AVI 内所有流的(type, format_tag, compression)三元组。逐步解释:

  • -o decode_samples=false:关闭样本解码,只解析容器与流头,速度更快;
  • .chunks[0]:进入最外层 RIFF(AVI)的 chunk 数组;
  • grep_by(.id=="LIST" and .type=="strl"):筛选出LIST类型的流列表块。grep_by是 fq 提供的按条件查找的便捷函数;
  • grep_by(.id=="strh") as {$type}:在strl内找到流头strh块,解构出type字段(如auds/vids)。strh的解析见 format/riff/avi.go,其中type会映射为友好描述:auds(Audio stream)、mids(MIDI stream)、txts(Text stream)、vids(Video stream),映射表见 format/riff/avi.go;
  • grep_by(.id=="strf") as {$format_tag, $compression}:在strl内找到流格式strf块,解构出音频流的format_tag(WAV 格式标签,如mp3、FLAC)或视频流的compression(BITMAPINFOHEADER 中的四字符压缩标识,如 H.264 相关标识)。strf的解析见 format/riff/avi.go;
  • 最终{$type,$format_tag,$compression}组装为摘要对象,其中不存在的字段在输出中为null,可以直观区分音频流(有format_tag)与视频流(有compression)。

以仓库测试中的 format/riff/testdata/mp3.avi.fqtest 为参照,strf解码结果中format_tag: "mp3" (85)会被映射为符号名mp3;视频流则会显示compression字段。对avc.avi(format/riff/testdata/avc.avi)执行此命令,可以确认其视频流compression为 H.264 相关标识。

解码选项详解:样本与扩展块的开关

-o decode_samples=false:关闭样本深层解码

fq 在解析到movi内的媒体 chunk(如00wb00dc00db)时,若decode_samples=true且该流声明了受支持的格式,会调用对应格式组(MP3_FrameFLAC_FrameAVC_AUHEVC_AU)做逐样本解码(见 format/riff/avi.go 与decodeSample函数 format/riff/avi.go)。样本解码计算量较大,关闭后movi数据块以data: raw bits形式呈现,仅保留容器层级结构。

-o decode_extended_chunks=false:关闭扩展块解码

OpenDML 允许 AVI 超过 1 GB,通过额外的RIFFAVIX)块扩展数据。解码器在 format/riff/avi.go 中循环TryPeekBytes(4)检测是否还有RIFF块,并将其解析为extended_chunks数组。关闭该选项可跳过这些扩展块。

组合使用以加速解码

原文档给出的加速命令:

$ fq -o decode_samples=false -o decode_extended_chunks=false d file.avi

若你只关心容器结构、索引或流头信息,而不需要样本细节和扩展块,这条命令会显著加快解码速度并减少输出体积。同理,帮助信息中也给出了等价的对象写法avi({decode_extended_chunks:false,decode_samples:false}),适用于管道场景:

$ fq -d avi -o decode_extended_chunks=true -o decode_samples=true . file

样本解码的底层细节:如何划分帧边界

decodeSample(format/riff/avi.go)体现了 fq 对 AVI 样本边界的处理策略:

  • 若索引区间长度为 0,直接输出剩余位作为单个sample
  • 子样本大小subSampleSize = stream.sampleSize * 8(来自strhsample_size字段)。若sample_size为 0,或流没有受支持格式且子样本大小不超过 64 位(8*8的启发式规则,避免把 PCM 拆成过小的块),则退化为整个区间作为一个样本;
  • 随后用FramedFn(subSampleSize, ...)按固定帧大小逐帧解码;若decode_samples=true且流有受支持格式,每帧用FieldFormat交给对应格式组(MP3/FLAC/H.264/HEVC)深解,否则按原始位输出。

这套逻辑使得固定帧大小(如strh.sample_size非零)的流可以被精确分帧,而变长帧(如 MP3)则交由 MP3 帧解码器自行同步帧边界。仓库中 format/riff/testdata/mp3.avi.fqtest、format/riff/testdata/flac.avi.fqtest、format/riff/testdata/avc.avi.fqtest、format/riff/testdata/pcm.avi.fqtest 分别覆盖了 MP3、FLAC、H.264 与 PCM 样本的解码验证。

支持的流格式与格式标签

strf解析逻辑(format/riff/avi.go)可以看出当前支持的映射:

流类型判定字段受支持取值深层解码格式
音频(audsformat_tagmp3(WAVTagMP3)MP3_Frame
音频(audsformat_tagFLAC(WAVTagFLAC)FLAC_Frame
视频(vidscompressionH.264 一族标识(H264h264X264x264avc1DAVCSMV2VSSHQ264V264GAVCUMSVtshdINMCAVC_AU
视频(vidscompressionHEVCH265HEVC_AU

音频流的format_tag通过format.WAVTagNames映射为符号名(如 85 →mp3);视频流的compression以四字符码形式展示。这些格式标签常量定义在format包中,例如format.WAVTagMP3format.BMPTagH264等。未在列表内的编解码(如 MPEG-4 Part 2、DV 等,源码中TODO也标注了 DV handler、palette change 等未实现项)会以原始位输出。

容器与流的完整字段速览

了解解码输出的字段有助于编写更精确的查询:

  • RIFF 层id("RIFF")、sizetype("AVI ",通过StrAssert校验,错误时报wrong or no AVI riff type found,见 format/riff/avi.go);
  • avih主头micro_sec_per_framemax_bytes_per_secpadding_granularityflags(含must_use_indexhas_indextrust_ck_typeis_interleavedcopyrightedwas_capture_file等位字段)、total_framesinitial_framesstreamssuggested_buffer_sizewidthheightreserved,见 format/riff/avi.go;
  • dmlh扩展头total_frames(64 位宽),见 format/riff/avi.go;
  • strh流头typehandlerflagsdisabledpal_changes)、prioritylanguageinitial_framesscaleratestartlengthsuggested_buffer_sizequalitysample_sizeframe(left/top/right/bottom),见 format/riff/avi.go;
  • strf流格式:视频为 BITMAPINFOHEADER(bi_sizewidthheightplanesbit_countcompressionsize_imagex/y_pels_per_meterclr_usedclr_important),音频为 WAVEFORMATEX(format_tagchannelssamples_per_secavg_bytes_per_secblock_alignbits_per_sample、可选cb_sizeextra);
  • vprp视频属性strn/INFO 元数据字符串块ISFT等,见 format/riff/common.go 的 chunk 描述表);
  • streams[]汇总:每个流输出typehandlerformat_tagcompression,以及按优先级选出的indexes/samples
  • extended_chunks[]:OpenDML AVIX 扩展块数组。

测试与验证

仓库通过 fqtest 机制对 AVI 解码器做了回归验证,相关测试文件位于 format/riff/testdata/:

  • mp3.avi.fqtest:MP3 音频流 AVI,验证容器头解析、movi00wb块、idx1索引解析,以及streams[0].samples的逐帧 MP3 深解;
  • avc.avi.fqtest:H.264 视频流 AVI,验证strfcompression识别与AVC_AU样本解码;
  • flac.avi.fqtest、pcm.avi.fqtest:分别覆盖 FLAC 与 PCM 音频样本;
  • help_avi.fqtest:fq -h avi帮助输出,与本文介绍的命令一致。

这些测试同时也展示了d file.avi(十六进制 + 解码树视图)与dv file.avi的实际输出格式,可作为排查解码问题的参照。

参考资料

原文档末尾附有 AVI 格式的两份权威背景资料:微软官方 AVI RIFF 文件参考(AVI RIFF File Reference)以及 OpenDML AVI 文件格式扩展规范(OpenDML AVI File Format Extensions),它们是理解indx/ix/idx1三类索引与AVIX扩展块设计初衷的基础读物。结合本文介绍的 fq 命令与 format/riff/avi.go 源码,即可完整掌握用 fq 分析、提取与调优 AVI 文件的实用技能。

【免费下载链接】fqfq - jq for binary formats. Tool, language and decoders for working with binary formats.项目地址: https://gitcode.com/gh_mirrors/fq/fq

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询