Skip to content

Commit

Permalink
ffmpeg: Add a metadata option to each output (#421)
Browse files Browse the repository at this point in the history
This will allow us to identify the software version and
who transcoded a given segment.
  • Loading branch information
j0sh authored Sep 9, 2024
1 parent f873529 commit fe5aff1
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 2 deletions.
4 changes: 4 additions & 0 deletions ffmpeg/encoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,8 @@ int open_output(struct output_ctx *octx, struct input_ctx *ictx)
if (ret < 0) LPMS_ERR(open_output_err, "Error opening output file");
}

if (octx->metadata) av_dict_copy(&oc->metadata, octx->metadata, 0);

ret = avformat_write_header(oc, &octx->muxer->opts);
if (ret < 0) LPMS_ERR(open_output_err, "Error writing header");

Expand Down Expand Up @@ -324,6 +326,8 @@ int reopen_output(struct output_ctx *octx, struct input_ctx *ictx)
ret = avio_open(&octx->oc->pb, octx->fname, AVIO_FLAG_WRITE);
if (ret < 0) LPMS_ERR(reopen_out_err, "Error re-opening output file");
}

if (octx->metadata) av_dict_copy(&octx->oc->metadata, octx->metadata, 0);
ret = avformat_write_header(octx->oc, &octx->muxer->opts);
if (ret < 0) LPMS_ERR(reopen_out_err, "Error re-writing header");

Expand Down
7 changes: 6 additions & 1 deletion ffmpeg/ffmpeg.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ type TranscodeOptions struct {
Muxer ComponentOptions
VideoEncoder ComponentOptions
AudioEncoder ComponentOptions
Metadata map[string]string
}

type MediaInfo struct {
Expand Down Expand Up @@ -778,6 +779,7 @@ func createCOutputParams(input *TranscodeOptionsIn, ps []TranscodeOptions) ([]C.
name: C.CString(audioEncoder),
opts: newAVOpts(p.AudioEncoder.Opts),
}
metadata := newAVOpts(p.Metadata)
fromMs := int(p.From.Milliseconds())
toMs := int(p.To.Milliseconds())
vfilt := C.CString(filters)
Expand All @@ -786,7 +788,7 @@ func createCOutputParams(input *TranscodeOptionsIn, ps []TranscodeOptions) ([]C.
params[i] = C.output_params{fname: oname, fps: fps,
w: C.int(w), h: C.int(h), bitrate: C.int(bitrate),
gop_time: C.int(gopMs), from: C.int(fromMs), to: C.int(toMs),
muxer: muxOpts, audio: audioOpts, video: vidOpts,
muxer: muxOpts, audio: audioOpts, video: vidOpts, metadata: metadata,
vfilters: vfilt, sfilters: nil, xcoderParams: xcoderOutParams}
if p.CalcSign {
//signfilter string
Expand Down Expand Up @@ -841,6 +843,9 @@ func destroyCOutputParams(params []C.output_params) {
if p.video.opts != nil {
C.av_dict_free(&p.video.opts)
}
if p.metadata != nil {
C.av_dict_free(&p.metadata)
}
}
}

Expand Down
53 changes: 52 additions & 1 deletion ffmpeg/ffmpeg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1628,6 +1628,9 @@ func TestTranscoder_FormatOptions(t *testing.T) {
Oname: dir + "/test.flv",
VideoEncoder: ComponentOptions{Name: "copy"},
AudioEncoder: ComponentOptions{Name: "copy"},
Metadata: map[string]string{
"encoded_by": "Livepeer Media Server",
},
}}
if out[0].Profile.Format != FormatNone {
t.Error("Expected empty profile for output option")
Expand All @@ -1637,7 +1640,7 @@ func TestTranscoder_FormatOptions(t *testing.T) {
t.Error(err)
}
cmd = `
ffprobe -loglevel warning -show_format test.flv | grep format_name=flv
ffprobe -loglevel warning -show_format test.flv | grep 'format_name=flv\|encoded_by=Livepeer Media Server'
`
run(cmd)

Expand All @@ -1646,6 +1649,9 @@ func TestTranscoder_FormatOptions(t *testing.T) {
out[0].Muxer = ComponentOptions{Name: "hls", Opts: map[string]string{
"hls_segment_filename": dir + "/test_segment_%d.ts",
}}
out[0].Metadata = map[string]string{
"service_provider": "Livepeer Media Server",
}
_, err = Transcode3(in, out)
if err != nil {
t.Error(err)
Expand All @@ -1660,6 +1666,7 @@ func TestTranscoder_FormatOptions(t *testing.T) {
ffprobe -loglevel warning -show_entries format=format_name,duration test.ts > test.out
diff -u segment.out test.out
wc -l test.out | grep 4 # sanity check output file length
ffprobe segment.ts 2>&1 | grep 'service_provider: Livepeer Media Server'
`
run(cmd)

Expand Down Expand Up @@ -1752,6 +1759,50 @@ func TestTranscoder_FormatOptions(t *testing.T) {
}
}

func TestTranscoder_Metadata(t *testing.T) {
runTestTranscoder_Metadata(t, Software)
}

func runTestTranscoder_Metadata(t *testing.T, accel Acceleration) {
// check that metadata is there in all segments
run, dir := setupTest(t)
defer os.RemoveAll(dir)

err := RTMPToHLS("../transcoder/test.ts", dir+"/in.m3u8", dir+"/in_%d.ts", "2", 0)
if err != nil {
t.Error(err)
}
tc := NewTranscoder()
defer tc.StopTranscoder()
for i := 0; i < 4; i++ {
in := &TranscodeOptionsIn{
Fname: fmt.Sprintf("%s/in_%d.ts", dir, i),
Accel: accel,
}
out := []TranscodeOptions{{
Accel: accel,
Oname: fmt.Sprintf("%s/out_%d.ts", dir, i),
Profile: P144p30fps16x9,
Metadata: map[string]string{
"service_name": fmt.Sprintf("lpms-test-%d", i),
},
}}
_, err := tc.Transcode(in, out)
if err != nil {
t.Error(err)
}
}

cmd := `
ffprobe -hide_banner -i out_1.ts
ffprobe -i out_0.ts 2>&1 | grep 'service_name : lpms-test-0'
ffprobe -i out_1.ts 2>&1 | grep 'service_name : lpms-test-1'
ffprobe -i out_2.ts 2>&1 | grep 'service_name : lpms-test-2'
ffprobe -i out_3.ts 2>&1 | grep 'service_name : lpms-test-3'
`
run(cmd)
}

func TestTranscoder_IgnoreUnknown(t *testing.T) {
run, dir := setupTest(t)
defer os.RemoveAll(dir)
Expand Down
1 change: 1 addition & 0 deletions ffmpeg/filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ struct output_ctx {
component_opts *muxer;
component_opts *video;
component_opts *audio;
AVDictionary *metadata;

int64_t drop_ts; // preroll audio ts to drop

Expand Down
5 changes: 5 additions & 0 deletions ffmpeg/nvidia_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -801,3 +801,8 @@ func TestNvidia_DiscontinuityAudioSegment(t *testing.T) {
func TestNvidia_Rotation(t *testing.T) {
runRotationTests(t, Nvidia)
}

func TestNvidia_Metadata(t *testing.T) {
// with nvenc we reopen the outputs so exercise that
runTestTranscoder_Metadata(t, Nvidia)
}
1 change: 1 addition & 0 deletions ffmpeg/transcoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ int transcode_init(struct transcode_thread *h, input_params *inp,
octx->muxer = &params[i].muxer;
octx->audio = &params[i].audio;
octx->video = &params[i].video;
octx->metadata = params[i].metadata;
octx->vfilters = params[i].vfilters;
octx->sfilters = params[i].sfilters;
octx->xcoderParams = params[i].xcoderParams;
Expand Down
1 change: 1 addition & 0 deletions ffmpeg/transcoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ typedef struct {
component_opts muxer;
component_opts audio;
component_opts video;
AVDictionary *metadata;
} output_params;

typedef struct {
Expand Down

0 comments on commit fe5aff1

Please sign in to comment.