feature image

2026年9月17日 | ブログ記事

pure-Go で FFmpeg の subset を実装したい!

この記事は 夏のブログリレー 32日目の記事です。


FFmpeg の提供する機能全体からなる集合を とします。
より、 を実装することで、題意を満たすことができました。

いかがでしたか?


こんばんは、25B のみどりむしと申します。

情報工学系の 200 番台には「プログラミング創造演習」という講義があり、パソカタをするだけことで単位が貰えます (しかも結構いい点数が来たり来なかったりします)。なんとも夢のような話です。

そこで私は「pure-Go によるマルチメディアトランスコーディングのためのオープンソース FFmpeg 代替アーキテクチャの開発」テーマで開発に取り組むことにしました。

実際にはこんな大層なものが 2 四半期で終わるわけがないので、音声コーデックの、そしてそのさらに一部に限って実装することにしていました (FFmpeg 代替とか言ってますがタイトルでカッコつけただけです。)。

動機

私は traP で traQ というチャットツールを開発しているのですが (紛らわしいですね)、その中で .m4a の波形のプレビューをしたいという要望がありました (波形画像を生成するために Linear PCM に変換する必要があるため,現在は .wav.mp3 のみ対応しています)。

しかし、Go にはそこそこ動きそうな .m4a のデコーダライブラリがなさそうだったため、FFmpeg を導入することも考えられたのですが、せっかくサーバーが pure-Go なのにもったいないといったような議論があり一時保留となりました。

それを機に pure-Go で音声コーデックを実装することに関して興味を持ったという流れになります (先にオチを話すと、.m4a に記録できるコーデックのうち ACC の仕様書が学生には高額すぎたため、結局 .m4a は実装してません。)。

また、個人的に Go はあまり好きではなかったのですが、そういえば大してなにも作っていないのに毛嫌いするのもよくないかと思い、もう少し真面目に Go を触ってみることにしました (結果的には今は「普通」くらいに思っています。Python よりちょっと好きくらい)。

作ったもの

どーん

GitHub - godexture/workspace
Contribute to godexture/workspace development by creating an account on GitHub.

最初はポリレポにしようと思って一丁前に Organization まで作ったのですが、複数リポジトリの同期リリースが面倒すぎてやめました (ちょっと時期尚早だったね。)。

AI 君と特大リファクタリングを行っている最中に飽きて放り投げたので結構コードがひどいことになっていますが、た、多分動くと思います...... (やる気が戻ってきたらまたメンテナンスします。)

創造演習当時のバージョンを

go install github.com/godexture/godec@latest

でインストールもできます (リリースをサボっているので今の master とは若干サブコマンドとかが違います)。

あとは

godec convert in.mp3 out.wav
godec play out.wav

とかできます (再生には https://github.com/ebitengine/oto を使ってます。God Library.)。

楽しくなって  delay とか reverb とか resample とか FFT convolver とかいろんなフィルタつくりました。

godec play out.flac --filter trim --filter fade:fade-in=10s 

とか

godec convert \
	in.wav out.wav \
	--filter "split=mixer[in=1,out=2]" \
	--filter reverb \
	--filter delay \
	--filter "join=mixer[in=2,out=1]" \
	--wire "split.in0=@in" \
	--wire "reverb.in=split.out0" \
	--wire "delay.in=split.out1" \
	--wire "join.in0=reverb.out" \
	--wire "join.in1=delay.out" \
	--wire "@out.in=join.out0"

とかできます。たのしい!

Go の API もあります。Go としてどうなのかはわかりません。

例によって今の master では動きません (:person_facepalming:)

package main

import (
	"context"
	"fmt"
	"os"
	"runtime"
	"runtime/debug"
	"runtime/pprof"

	"github.com/godexture/filter-audio"
	"github.com/godexture/sdk/dsp"
	"github.com/godexture/sdk/profiling"
	"github.com/godexture/sdk/timer"

	godec "github.com/godexture/core"
	"github.com/godexture/core/domain/media"
	"github.com/godexture/core/routing"

	flacFormat "github.com/godexture/format-flac"

	_ "github.com/godexture/codec-flac"
	_ "github.com/godexture/codec-mp3"
	_ "github.com/godexture/codec-pcm"
	_ "github.com/godexture/format-flac"
	_ "github.com/godexture/format-mp3"
	_ "github.com/godexture/format-wav"
)

const targetCodec = media.CodecFLAC

func main() {
	inputPath := os.Args[1]
	outputPath := os.Args[2]

	inputFile, err := os.Open(inputPath)
	if err != nil {
		fmt.Printf("Failed to open input: %v\n", err)
		return
	}
	defer inputFile.Close()

	outputFile, err := os.Create(outputPath)
	if err != nil {
		fmt.Printf("Failed to create output: %v\n", err)
		return
	}
	defer outputFile.Close()

	negotiator := godec.NewNegotiator()

	spec := routing.ConversionSpec{
		Input:       inputFile,
		Output:      outputFile,
		TargetCodec: targetCodec,
		Filters: []routing.FilterSpec{
			{
				Config: filter.MustNewResampleConfig(
					filter.WithSampleRate(48000),
				),
			},
		},
		MuxConfig: flacFormat.MustNewMuxerConfig(),
	}

	geometry, err := negotiator.NegotiateConversion(context.Background(), spec)
	if err != nil {
		fmt.Printf("Failed to negotiate conversion: %v\n", err)
		return
	}

	builder := godec.NewBuilder()
	conversion, err := builder.Build(geometry)
	if err != nil {
		fmt.Printf("Failed to build pipeline: %v\n", err)
		return
	}
	defer conversion.Close()

	if err := conversion.Run(context.Background()); err != nil {
		fmt.Printf("Pipeline execution failed: %v\n", err)
		return
	}
}

実は SIMD を有効にすると一部 SIMD で動きます。それなりにパフォーマンスチューニングを頑張りました。

あとは調子に乗って Web で動くエディタも作りました (半分くらい Claude と Codex が)。
いろいろできて結構楽しいです。 

Godexture
(ないと思うけど) 負荷が増えてきたら止めます

Go なので WASM で動かすこともできます。遅いけど。

サポート

Formats (Demultiplexing / Multiplexing)

Metadata (Unmarshalling / Marshalling)

Codecs (Decoding / Encoding):

Filters (Processing):

感想

Go ちょっと楽しいかもって思いました。
でもバイナリ操作したりするなら流石に Rust とか C++ のほうがいいね。

GC 便利だけどやっぱりパフォーマンスチューニングとかしようとすると結局 GC のお気持ちを考えてご機嫌取りしないといけないのがつらいです、私は GC 無い方が好きかな、嘘です、参照カウントくらいは欲しいかも。

でも Go にもゼロアロケーションを謳ってるライブラリとかあるらしくてすごい。正気?

あと仕様書が有料ってちょっと嫌な気持になりますね。いやしょうがないけど、こっちも学生なので許してほしい。というか工業大学って名前なら ISO/IEC とか JIS の規格書くらい全部タダで読めてほしくないですか? あ今は工業大学じゃないんでしたねそういえば。(ISO/IEC 14882:2024 の寄贈待ってます♡)

学生に使ってほしい人は無料で仕様書を公開するといいと思います (?)

FLAC とかすべてが無料で読めてとても楽しかったです。
皆様もよき FFmpeg ライフを。

あと創造演習はいいですよ、ぜひ履修してください。

二時間前くらいに書き始めてなんとか間に合いました。
殴り書きですみません。

明日のブログリレーの投稿者は 25/jk と @ramdos です、お楽しみに。

uni_kakurenbo icon
この記事を書いた人
uni_kakurenbo

Web と C++

この記事をシェア

このエントリーをはてなブックマークに追加
共有

関連する記事

2025年9月15日
traPでの一年半を振り返る〜全班所属の体験記(?)〜
gurukun41 icon gurukun41
2024年9月17日
1か月でゲームを作った #BlueLINE
Komichi icon Komichi
2025年9月18日
泥タブに夢と希望を見出した男の物語 【Lenovo Yoga Tab Plus】
mutv625 icon mutv625
2024年8月21日
【最新版 / 入門】JUCEを使ってVSTプラグインを作ろう!!!!【WebView UI】
kashiwade icon kashiwade
2021年8月12日
CPCTFを支えたWebshell
mazrean icon mazrean
2021年5月19日
CPCTF2021を実現させたスコアサーバー
xxpoxx icon xxpoxx
記事一覧 タグ一覧 Google アナリティクスについて 特定商取引法に基づく表記