1
1
mirror of https://github.com/wader/fq.git synced 2024-10-04 23:48:00 +03:00

mp3: Error if > 5 unique header configs

Hopefully make it less likely to missprobe
This commit is contained in:
Mattias Wadman 2021-11-19 11:55:45 +01:00
parent 44251ca8bd
commit 527f917698
3 changed files with 54 additions and 6 deletions

View File

@ -165,3 +165,12 @@ type MPEGASCOut struct {
type AACFrameIn struct { type AACFrameIn struct {
ObjectType int ObjectType int
} }
type MP3FrameOut struct {
MPEGVersion int
ProtectionAbsent bool
BitRate int
SampleRate int
ChannelsIndex int
ChannelModeIndex int
}

View File

@ -1,9 +1,10 @@
package mp3 package mp3
// TODO: vbri // TODO: vbri
// TODO: mime audio/mpeg
import ( import (
"fmt"
"github.com/wader/fq/format" "github.com/wader/fq/format"
"github.com/wader/fq/format/registry" "github.com/wader/fq/format/registry"
"github.com/wader/fq/pkg/decode" "github.com/wader/fq/pkg/decode"
@ -33,6 +34,17 @@ func init() {
} }
func mp3Decode(d *decode.D, in interface{}) interface{} { func mp3Decode(d *decode.D, in interface{}) interface{} {
// things in a mp3 stream usually have few unique combinations of.
// does not include bitrate on purpose
type headerConfig struct {
MPEGVersion int
ProtectionAbsent bool
SampleRate int
ChannelsIndex int
ChannelModeIndex int
}
uniqueHeaderConfigs := map[headerConfig]struct{}{}
// there are mp3s files in the wild with multiple headers, two id3v2 tags etc // there are mp3s files in the wild with multiple headers, two id3v2 tags etc
d.FieldArray("headers", func(d *decode.D) { d.FieldArray("headers", func(d *decode.D) {
for d.NotEnd() { for d.NotEnd() {
@ -59,16 +71,33 @@ func mp3Decode(d *decode.D, in interface{}) interface{} {
d.SeekRel(syncLen) d.SeekRel(syncLen)
} }
if dv, _, _ := d.FieldTryFormat("frame", mp3Frame, nil); dv == nil { dv, v, _ := d.FieldTryFormat("frame", mp3Frame, nil)
if dv == nil {
decodeFailures++ decodeFailures++
d.SeekRel(8) d.SeekRel(8)
continue continue
} }
mfo, ok := v.(format.MP3FrameOut)
if !ok {
panic(fmt.Sprintf("expected MP3FrameOut got %#+v", v))
}
uniqueHeaderConfigs[headerConfig{
MPEGVersion: mfo.MPEGVersion,
ProtectionAbsent: mfo.ProtectionAbsent,
SampleRate: mfo.SampleRate,
ChannelsIndex: mfo.ChannelsIndex,
ChannelModeIndex: mfo.ChannelModeIndex,
}] = struct{}{}
lastValidEnd = d.Pos() lastValidEnd = d.Pos()
validFrames++ validFrames++
if len(uniqueHeaderConfigs) > 5 {
d.Errorf("too many unique header configurations")
}
} }
}) })
// TODO: better validate
if validFrames == 0 || (validFrames < 2 && decodeFailures > 0) { if validFrames == 0 || (validFrames < 2 && decodeFailures > 0) {
d.Errorf("no frames found") d.Errorf("no frames found")
} }

View File

@ -147,8 +147,11 @@ func frameDecode(d *decode.D, in interface{}) interface{} {
var crcBytes int64 var crcBytes int64
var mpegVersionNr uint64 var mpegVersionNr uint64
var mpegLayerNr uint64 var mpegLayerNr uint64
var protectionAbsent bool
var bitRate uint64 var bitRate uint64
var sampleRate uint64 var sampleRate uint64
var channelsIndex uint64
var channelModeIndex uint64
var mainDataEnd uint64 var mainDataEnd uint64
var crcValue *decode.Value var crcValue *decode.Value
@ -239,14 +242,14 @@ func frameDecode(d *decode.D, in interface{}) interface{} {
1: "Padded", 1: "Padded",
}), d.Bin) }), d.Bin)
d.FieldU1("private") d.FieldU1("private")
channelsIndex := d.FieldU2("channels", d.MapUToStrSym(decode.UToStr{ channelsIndex = d.FieldU2("channels", d.MapUToStrSym(decode.UToStr{
0b00: "Stereo", 0b00: "Stereo",
0b01: "Joint stereo", 0b01: "Joint stereo",
0b10: "Dual", 0b10: "Dual",
0b11: "Mono", 0b11: "Mono",
}), d.Bin) }), d.Bin)
isStereo = channelsIndex != 0b11 isStereo = channelsIndex != 0b11
d.FieldU2("channel_mode", d.MapUToStrSym(decode.UToStr{ channelModeIndex = d.FieldU2("channel_mode", d.MapUToStrSym(decode.UToStr{
0b00: "None", 0b00: "None",
0b01: "Intensity stereo", 0b01: "Intensity stereo",
0b10: "MS stereo", 0b10: "MS stereo",
@ -393,5 +396,12 @@ func frameDecode(d *decode.D, in interface{}) interface{} {
} }
d.FieldValueRaw("crc_calculated", crcHash.Sum(nil), d.RawHex) d.FieldValueRaw("crc_calculated", crcHash.Sum(nil), d.RawHex)
return nil return format.MP3FrameOut{
MPEGVersion: int(mpegVersionNr),
ProtectionAbsent: protectionAbsent,
BitRate: int(bitRate),
SampleRate: int(sampleRate),
ChannelsIndex: int(channelModeIndex),
ChannelModeIndex: int(channelModeIndex),
}
} }