Skip to content

Commit a17d3c6

Browse files
eliteproxrickstaa
authored andcommitted
Add media duration to lpms_get_codec_info for GetCodecInfo (#407)
* add fps and duration to GetCodecInfo
1 parent de94555 commit a17d3c6

File tree

5 files changed

+156
-2
lines changed

5 files changed

+156
-2
lines changed

ffmpeg/decoder.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ int open_input(input_params *params, struct input_ctx *ctx)
337337

338338
ctx->transmuxing = params->transmuxe;
339339

340-
// open demuxer
340+
// open demuxer/ open demuxer
341341
AVDictionary **demuxer_opts = NULL;
342342
if (params->demuxer.opts) demuxer_opts = &params->demuxer.opts;
343343
ret = avformat_open_input(&ic, inp, NULL, demuxer_opts);

ffmpeg/extras.c

+4
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,9 @@ int lpms_get_codec_info(char *fname, pcodec_info out)
164164
// instead of returning -1
165165
ret = GET_CODEC_STREAMS_MISSING;
166166
}
167+
if (ic->duration != AV_NOPTS_VALUE) {
168+
out->dur = ic->duration / AV_TIME_BASE;
169+
}
167170
// Return
168171
if (video_present && vc->name) {
169172
strncpy(out->video_codec, vc->name, MIN(strlen(out->video_codec), strlen(vc->name))+1);
@@ -176,6 +179,7 @@ int lpms_get_codec_info(char *fname, pcodec_info out)
176179
}
177180
out->width = ic->streams[vstream]->codecpar->width;
178181
out->height = ic->streams[vstream]->codecpar->height;
182+
out->fps = av_q2d(ic->streams[vstream]->r_frame_rate);
179183
} else {
180184
// Indicate failure to extract video codec from given container
181185
out->video_codec[0] = 0;

ffmpeg/extras.h

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ typedef struct s_codec_info {
77
int pixel_format;
88
int width;
99
int height;
10+
double fps;
11+
double dur;
1012
} codec_info, *pcodec_info;
1113

1214
int lpms_rtmp2hls(char *listen, char *outf, char *ts_tmpl, char *seg_time, char *seg_start);

ffmpeg/ffmpeg.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,8 @@ type MediaFormatInfo struct {
245245
Acodec, Vcodec string
246246
PixFormat PixelFormat
247247
Width, Height int
248+
FPS float32
249+
DurSecs int64
248250
}
249251

250252
func (f *MediaFormatInfo) ScaledHeight(width int) int {
@@ -277,6 +279,8 @@ func GetCodecInfo(fname string) (CodecStatus, MediaFormatInfo, error) {
277279
format.PixFormat = PixelFormat{int(params_c.pixel_format)}
278280
format.Width = int(params_c.width)
279281
format.Height = int(params_c.height)
282+
format.FPS = float32(params_c.fps)
283+
format.DurSecs = int64(params_c.dur)
280284
return status, format, nil
281285
}
282286

@@ -979,7 +983,7 @@ func (t *Transcoder) Transcode(input *TranscodeOptionsIn, ps []TranscodeOptions)
979983
input.Profile.FramerateDen = 1
980984
}
981985

982-
// Do not try tofree in this function because in the C code avformat_open_input()
986+
// Do not try to free in this function because in the C code avformat_open_input()
983987
// will destroy this
984988
demuxerOpts.opts = newAVOpts(map[string]string{
985989
"framerate": fmt.Sprintf("%d/%d", input.Profile.Framerate, input.Profile.FramerateDen),

ffmpeg/ffmpeg_test.go

+144
Original file line numberDiff line numberDiff line change
@@ -1869,3 +1869,147 @@ func TestResolution_Clamp(t *testing.T) {
18691869
checkError = require.Error
18701870
test(l, Size{300, 600}, portrait, Size{300, 600})
18711871
}
1872+
1873+
func TestTranscoder_VFR(t *testing.T) {
1874+
run, dir := setupTest(t)
1875+
defer os.RemoveAll(dir)
1876+
1877+
// prepare the input by generating a vfr video and verify its properties
1878+
cmd := `
1879+
ffmpeg -hide_banner -i "$1/../transcoder/test.ts" -an -vf "setpts='\
1880+
if(eq(N, 0), 33373260,\
1881+
if(eq(N, 1), 33375870,\
1882+
if(eq(N, 2), 33379560,\
1883+
if(eq(N, 3), 33381360,\
1884+
if(eq(N, 4), 33384960,\
1885+
if(eq(N, 5), 33387660,\
1886+
if(eq(N, 6), 33391350,\
1887+
if(eq(N, 7), 33394950,\
1888+
if(eq(N, 8), 33397650,\
1889+
if(eq(N, 9), 33400350,\
1890+
if(eq(N, 10), 33403050,\
1891+
if(eq(N, 11), 33405750,\
1892+
if(eq(N, 12), 33408450,\
1893+
if(eq(N, 13), 33412050,\
1894+
if(eq(N, 14), 33414750,\
1895+
if(eq(N, 15), 33418350,\
1896+
if(eq(N, 16), 33421950,\
1897+
if(eq(N, 17), 33423750,\
1898+
if(eq(N, 18), 33426450,\
1899+
if(eq(N, 19), 33430950,\
1900+
if(eq(N, 20), 33435450,\
1901+
if(eq(N, 21), 33437340,\
1902+
if(eq(N, 22), 33440040,\
1903+
if(eq(N, 23), 33441840,\
1904+
if(eq(N, 24), 33445440,\
1905+
if(eq(N, 25), 33449040,\
1906+
if(eq(N, 26), 33451740,\
1907+
if(eq(N, 27), 33455340,\
1908+
if(eq(N, 28), 33458040,\
1909+
if(eq(N, 29), 33459750, 0\
1910+
))))))))))))))))))))))))))))))',scale=320:240" -c:v libx264 -bf 0 -frames:v 30 -copyts -enc_time_base 1:90000 -vsync passthrough -muxdelay 0 in.ts
1911+
1912+
ffprobe -hide_banner -i in.ts -select_streams v:0 -show_entries packet=pts,duration -of csv=p=0 | sed '/^$/d' > input-pts.out
1913+
1914+
# Double check that we've correctly generated the expected pts for input
1915+
cat << PTS_EOF > expected-input-pts.out
1916+
33373260,N/A
1917+
33375870,N/A
1918+
33379560,N/A
1919+
33381360,N/A
1920+
33384960,N/A
1921+
33387660,N/A
1922+
33391350,N/A
1923+
33394950,N/A
1924+
33397650,N/A
1925+
33400350,N/A
1926+
33403050,N/A
1927+
33405750,N/A
1928+
33408450,N/A
1929+
33412050,N/A
1930+
33414750,N/A
1931+
33418350,N/A
1932+
33421950,N/A
1933+
33423750,N/A
1934+
33426450,N/A
1935+
33430950,N/A
1936+
33435450,N/A
1937+
33437340,N/A
1938+
33440040,N/A
1939+
33441840,N/A
1940+
33445440,N/A
1941+
33449040,N/A
1942+
33451740,N/A
1943+
33455340,N/A
1944+
33458040,N/A
1945+
33459750,N/A
1946+
PTS_EOF
1947+
1948+
diff -u expected-input-pts.out input-pts.out
1949+
`
1950+
1951+
run(cmd)
1952+
1953+
err := Transcode(
1954+
dir+"/in.ts",
1955+
dir, []VideoProfile{P240p30fps4x3})
1956+
require.Nil(t, err)
1957+
1958+
// check output
1959+
cmd = `
1960+
# reproduce expected lpms output using ffmpeg
1961+
ffmpeg -debug_ts -loglevel trace -i in.ts -vf 'scale=136x240,fps=30/1:eof_action=pass' -c:v libx264 -copyts -muxdelay 0 out-ffmpeg.ts
1962+
1963+
ffprobe -show_packets out-ffmpeg.ts | grep dts= > ffmpeg-dts.out
1964+
ffprobe -show_packets out0in.ts | grep dts= > lpms-dts.out
1965+
1966+
diff -u lpms-dts.out ffmpeg-dts.out
1967+
`
1968+
run(cmd)
1969+
}
1970+
1971+
func TestDurationFPS_GetCodecInfo(t *testing.T) {
1972+
run, dir := setupTest(t)
1973+
defer os.RemoveAll(dir)
1974+
1975+
//Generate test files
1976+
cmd := `
1977+
cp "$1/../data/duplicate-audio-dts.ts" test.ts
1978+
ffprobe -loglevel warning -show_format test.ts | grep duration=2.008555
1979+
ffprobe -loglevel warning -show_streams -select_streams v test.ts | grep r_frame_rate=30/1
1980+
cp "$1/../data/bunny.mp4" test.mp4
1981+
ffmpeg -loglevel warning -i test.mp4 -c:v copy -c:a copy -t 2 test-short.mp4
1982+
ffprobe -loglevel warning -show_format test-short.mp4 | grep duration=2.043356
1983+
ffprobe -loglevel warning -show_streams -select_streams v test-short.mp4 | grep r_frame_rate=24/1
1984+
ffmpeg -loglevel warning -i test-short.mp4 -c:v libvpx -c:a vorbis -strict -2 -t 2 test.webm
1985+
ffprobe -loglevel warning -show_format test.webm | grep duration=2.049000
1986+
ffprobe -loglevel warning -show_streams -select_streams v test.webm | grep r_frame_rate=24/1
1987+
ffmpeg -loglevel warning -i test-short.mp4 -vn -c:a aac -b:a 128k test.m4a
1988+
ffprobe -loglevel warning -show_format test.m4a | grep duration=2.042993
1989+
ffmpeg -loglevel warning -i test-short.mp4 -vn -c:a flac test.flac
1990+
ffprobe -loglevel warning -show_format test.flac | grep duration=2.043356
1991+
`
1992+
run(cmd)
1993+
1994+
files := []struct {
1995+
Filename string
1996+
Duration int64
1997+
FPS float32
1998+
}{
1999+
{Filename: "test-short.mp4", Duration: 2, FPS: 24},
2000+
{Filename: "test.ts", Duration: 2, FPS: 30.0},
2001+
{Filename: "test.flac", Duration: 2, FPS: 0.0},
2002+
{Filename: "test.webm", Duration: 2, FPS: 24},
2003+
{Filename: "test.m4a", Duration: 2, FPS: 0.0},
2004+
}
2005+
for _, file := range files {
2006+
t.Run(file.Filename, func(t *testing.T) {
2007+
assert := assert.New(t)
2008+
status, format, err := GetCodecInfo(path.Join(dir, file.Filename))
2009+
assert.Nil(err, "getcodecinfo error")
2010+
assert.Equal(CodecStatusOk, status, "status not ok")
2011+
assert.Equal(file.Duration, format.DurSecs, "duration mismatch")
2012+
assert.Equal(file.FPS, format.FPS, "fps mismatch")
2013+
})
2014+
}
2015+
}

0 commit comments

Comments
 (0)