Skip to content

Commit

Permalink
ffmpeg: Add demuxer options.
Browse files Browse the repository at this point in the history
  • Loading branch information
j0sh committed Nov 18, 2024
1 parent ffde232 commit b8d8035
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 8 deletions.
13 changes: 11 additions & 2 deletions ffmpeg/decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -355,10 +355,19 @@ int open_input(input_params *params, struct input_ctx *ctx)

ctx->transmuxing = params->transmuxing;

// open demuxer/ open demuxer
const AVInputFormat *fmt = NULL;
if (params->demuxer.name) {
fmt = av_find_input_format(params->demuxer.name);
if (!fmt) {
ret = AVERROR_DEMUXER_NOT_FOUND;
LPMS_ERR(open_input_err, "Invalid demuxer name")
}
}

// open demuxer
AVDictionary **demuxer_opts = NULL;
if (params->demuxer.opts) demuxer_opts = &params->demuxer.opts;
ret = avformat_open_input(&ic, inp, NULL, demuxer_opts);
ret = avformat_open_input(&ic, inp, fmt, demuxer_opts);
if (ret < 0) LPMS_ERR(open_input_err, "demuxer: Unable to open input");
// If avformat_open_input replaced the options AVDictionary with options that were not found free it
if (demuxer_opts) av_dict_free(demuxer_opts);
Expand Down
20 changes: 15 additions & 5 deletions ffmpeg/ffmpeg.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ type TranscodeOptionsIn struct {
Device string
Transmuxing bool
Profile VideoProfile
Demuxer ComponentOptions
}

type TranscodeOptions struct {
Expand Down Expand Up @@ -948,6 +949,12 @@ func (t *Transcoder) Transcode(input *TranscodeOptionsIn, ps []TranscodeOptions)

var demuxerOpts C.component_opts

if input.Demuxer.Name != "" {
demuxerName := C.CString(input.Demuxer.Name)
defer C.free(unsafe.Pointer(demuxerName))
demuxerOpts.name = demuxerName
}

ext := filepath.Ext(input.Fname)
// If the input has an image file extension setup the image2 demuxer
if ext == ".png" {
Expand All @@ -963,14 +970,17 @@ func (t *Transcoder) Transcode(input *TranscodeOptionsIn, ps []TranscodeOptions)
input.Profile.FramerateDen = 1
}

// Do not try to free in this function because in the C code avformat_open_input()
// will destroy this
demuxerOpts.opts = newAVOpts(map[string]string{
"framerate": fmt.Sprintf("%d/%d", input.Profile.Framerate, input.Profile.FramerateDen),
})
// changing the input map here is maybe not great
input.Demuxer.Opts["framerate"] = fmt.Sprintf("%d/%d", input.Profile.Framerate, input.Profile.FramerateDen)
}
}

if len(input.Demuxer.Opts) > 0 {
// Do not free in this function because avformat_open_input()
// in the C code will destroy this
demuxerOpts.opts = newAVOpts(input.Demuxer.Opts)
}

inp := &C.input_params{fname: fname, hw_type: hw_type, device: device, xcoderParams: xcoderParams,
handle: t.handle, demuxer: demuxerOpts}
if input.Transmuxing {
Expand Down
62 changes: 62 additions & 0 deletions ffmpeg/ffmpeg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2377,3 +2377,65 @@ func runRotationTests(t *testing.T, accel Acceleration) {
`
run(cmd)
}

func TestTranscoder_DemuxerOpts(t *testing.T) {
// generate test files: a few frames of raw video
run, dir := setupTest(t)
defer os.RemoveAll(dir)

cmd := `
# use an unusual pixel format
ffmpeg -i "$1/../transcoder/test.ts" -an -c:v rawvideo -pix_fmt gbrp12be -s 320x240 -r 1 -frames:v 3 -f rawvideo test.raw
ffprobe -show_streams -count_frames -pixel_format gbrp12be -video_size 320x240 -f rawvideo test.raw 2>&1 | grep nb_read_frames=3
`
run(cmd)
res, err := Transcode3(
&TranscodeOptionsIn{
Fname: dir + "/test.raw",
Demuxer: ComponentOptions{
Name: "rawvideo",
Opts: map[string]string{
"fflags": "+discardcorrupt+nobuffer",
"pixel_format": "gbrp12be",
"video_size": "320x240",
},
},
},
[]TranscodeOptions{{
Oname: dir + "/out-%d.png",
Profile: VideoProfile{
Name: "-",
Resolution: "200x150",
Bitrate: "10k",
},
}})
assert.Nil(t, err, "transcoder returned error")
assert := assert.New(t)
// we transcode 3 but decode/encode 2 due to nobuffer
assert.Equal(2, res.Decoded.Frames, "decoded frame count did not match")
assert.Equal(2, res.Encoded[0].Frames, "encoded frame count did not match")
assert.Equal(int64(2*320*240), res.Decoded.Pixels, "decoded pixel count did not match")
assert.Equal(int64(2*200*150), res.Encoded[0].Pixels, "encoded frame count did not match")
}

func TestTranscoder_DemuxerOptsError(t *testing.T) {

// nonexistent demuxer
_, err := Transcode3(&TranscodeOptionsIn{
Fname: "../transcoder/test.ts",
Demuxer: ComponentOptions{
Name: "nonexistent",
},
}, nil)
assert.Equal(t, "Demuxer not found", err.Error())

// wrong demuxer
_, err = Transcode3(&TranscodeOptionsIn{
Fname: "../transcoder/test.ts",
Demuxer: ComponentOptions{
Name: "mp4",
},
}, nil)
assert.Equal(t, "Invalid data found when processing input", err.Error())

}
10 changes: 9 additions & 1 deletion ffmpeg/transcoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,15 @@ int transcode_init(struct transcode_thread *h, input_params *inp,
if (!ictx->ic) {
// reopen demuxer for the input segment if needed
// XXX could open_input() be re-used here?
ret = avformat_open_input(&ictx->ic, inp->fname, NULL, demuxer_opts);
const AVInputFormat *fmt = NULL;
if (inp->demuxer.name) {
fmt = av_find_input_format(inp->demuxer.name);
if (!fmt) {
ret = AVERROR_DEMUXER_NOT_FOUND;
LPMS_ERR(transcode_cleanup, "Invalid demuxer name")
}
}
ret = avformat_open_input(&ictx->ic, inp->fname, fmt, demuxer_opts);
if (ret < 0) LPMS_ERR(transcode_cleanup, "Unable to reopen demuxer");
// If avformat_open_input replaced the options AVDictionary with options that were not found free it
if (demuxer_opts) av_dict_free(demuxer_opts);
Expand Down

0 comments on commit b8d8035

Please sign in to comment.