Runner in the High

技術のことをかくこころみ

abema/go-mp4でASCの値を取得する

以下の記事ではASC(Audio Specific Config)をffprobeで取り出したが、これはmp4デマルチプレクサでも取り出すことができる。

izumisy.work

今回はabema/go-mp4を使ってやってみる。

mp4の仕様によればesdsというboxの中に入っているらしいので、それを取り出せばいい。

// esdsからASCの値を含むデスクリプタを取り出す
func getASCDescriptor(reader io.ReadSeeker) (*mp4.Descriptor, error) {
    var ascDescriptor *mp4.Descriptor

    if results, err := mp4.ExtractBoxWithPayload(reader, nil, mp4.BoxPath{
        mp4.BoxTypeMoov(),
        mp4.BoxTypeTrak(),
        mp4.BoxTypeMdia(),
        mp4.BoxTypeMinf(),
        mp4.BoxTypeStbl(),
        mp4.BoxTypeStsd(),
        mp4.BoxTypeMp4a(),
        mp4.BoxTypeEsds(),
    }); err != nil {
        return nil, err
    } else {
        esds := results[0].Payload.(*mp4.Esds)
        for _, descriptor := range esds.Descriptors {
            if descriptor.Tag == mp4.DecSpecificInfoTag {
                ascDescriptor = &descriptor
                break
            }
        }

        if ascDescriptor == nil {
            return nil, errors.New("no descriptor found")
        }
    }

    return ascDescriptor, nil
}

単なるm4aファイルに対して動かして確認してみた限り esds.Descriptors には4つ程度のデスクリプタが含まれていた。その中で mp4.DecSepcificInfoTag という値に該当するやつがASCを持っているっぽい。なのでそれを探してやればいい。

あとはこんな感じでgo-fdkaacの初期化のときのパラメタとして使える。

descriptor, err := getASCDescriptor(m4aFile)
if err != nil {
    panic(err)
} else if len(descriptor.Data) == 0 {
    panic(errors.New("no ASC available"))
}

decoder := fdkaac.NewAacDecoder()
if err := decoder.InitRaw([]byte{
    descriptor.Data[0],
    descriptor.Data[1],
}); err != nil {
    panic(err)
}