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:
parent
44251ca8bd
commit
527f917698
@ -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
|
||||||
|
}
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
|
@ -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),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user