Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add media duration to lpms_get_codec_info for GetCodecInfo #407

Merged
merged 27 commits into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
eef214e
add fps and duration to GetCodecInfo
ad-astra-video Oct 31, 2023
1fcc47e
update fps and dur calc
ad-astra-video Nov 3, 2023
904f309
add duration if video or audio present
ad-astra-video Jul 3, 2024
6a2b014
add cmd script to test fps and duration
ad-astra-video Jul 3, 2024
0e84f60
revert to using AV_TIME_BASE and add notes for future improvements
ad-astra-video Jul 3, 2024
2b723a4
Fix duration for audio only file
eliteprox Jul 5, 2024
b601475
Code cleanup
eliteprox Jul 5, 2024
bad8498
Fix duration calculation
eliteprox Jul 5, 2024
146d718
Cleanup test
eliteprox Jul 5, 2024
75bd67c
Merge branch 'add-codec-info' of github.com:eliteprox/lpms into add-c…
eliteprox Jul 8, 2024
e6389f2
Move fps duration test to ffmpeg test, add descriptive comment
eliteprox Jul 8, 2024
f05997e
Add tests, cleanup from review
eliteprox Jul 9, 2024
f0eda1a
Generate test files with ffmpeg, check expected duration and fps, rem…
eliteprox Jul 9, 2024
f3c8917
Remove test file
eliteprox Jul 9, 2024
d025d0a
Fix tests and review comments
eliteprox Jul 9, 2024
6579e6e
Save indention
eliteprox Jul 9, 2024
67db771
Remove seek
eliteprox Jul 9, 2024
cc58010
simplify test
eliteprox Jul 10, 2024
8cdef44
Add webm type to test
eliteprox Jul 10, 2024
a8f19c4
add max_analyze_duration and remove strays
eliteprox Jul 10, 2024
d99d32b
Optimize duration calculation
eliteprox Jul 10, 2024
f2edd37
Use the largest pts for last_pts and smallest pts for first
eliteprox Jul 10, 2024
1fd0f5c
Remove calculate_stream_duration, add ffprobe to tests
eliteprox Jul 11, 2024
afaf25d
remove max_analyze_duration
eliteprox Jul 11, 2024
56c2328
Update ffmpeg/ffmpeg_test.go
eliteprox Jul 11, 2024
0e12477
Update ffmpeg/extras.c
eliteprox Jul 11, 2024
c85f817
add ffprobe expected duration and fps values to test
eliteprox Jul 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions cmd/test/get_fps_dur.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package main

import (
"fmt"
"os"
"text/tabwriter"
"time"

"github.com/livepeer/lpms/ffmpeg"
)

func main() {
eliteprox marked this conversation as resolved.
Show resolved Hide resolved
p := "/opt/livepeer/test-videos"
items, _ := os.ReadDir(p)
w := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', tabwriter.Debug)

fmt.Fprintln(w, "File\tTook (ms)\tFPS\tDur\tACodec")
for _, item := range items {
vid_path := p + "/" + item.Name()
start := time.Now()
_, mfi, err := ffmpeg.GetCodecInfo(vid_path)
if err == nil {
took := time.Since(start).Milliseconds()
line := fmt.Sprintf("%v\t%v\t%v\t%v\t%v", item.Name(), took, mfi.FPS, mfi.Dur, mfi.Acodec)
fmt.Fprintln(w, line)
} else {
fmt.Printf("error getting codec info: %w\n", err)
}
}

w.Flush()
}
34 changes: 34 additions & 0 deletions ffmpeg/extras.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,28 @@ int lpms_rtmp2hls(char *listen, char *outf, char *ts_tmpl, char* seg_time, char
return ret == AVERROR_EOF ? 0 : ret;
}

double calculate_duration(AVFormatContext *ic, int astream) {
AVPacket pkt;
av_init_packet(&pkt);
double duration = 0;
int64_t last_pts = AV_NOPTS_VALUE;
while (av_read_frame(ic, &pkt) >= 0) {
eliteprox marked this conversation as resolved.
Show resolved Hide resolved
if (pkt.stream_index == astream) {
eliteprox marked this conversation as resolved.
Show resolved Hide resolved
if (pkt.pts != AV_NOPTS_VALUE) {
if (last_pts != AV_NOPTS_VALUE) {
// Calculate the difference between the current and last PTS
int64_t pts_diff = pkt.pts - last_pts;
// Convert the PTS difference to seconds and add to duration
duration += pts_diff * av_q2d(ic->streams[astream]->time_base);
eliteprox marked this conversation as resolved.
Show resolved Hide resolved
}
last_pts = pkt.pts;
}
av_packet_unref(&pkt);
}
}
return duration;
}

#define GET_CODEC_INTERNAL_ERROR -1
#define GET_CODEC_OK 0
#define GET_CODEC_NEEDS_BYPASS 1
Expand All @@ -149,6 +171,9 @@ int lpms_get_codec_info(char *fname, pcodec_info out)
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
AVFormatContext *ic = NULL;
AVCodec *ac, *vc;

int64_t last_pts = AV_NOPTS_VALUE;
eliteprox marked this conversation as resolved.
Show resolved Hide resolved

int ret = GET_CODEC_OK, vstream = 0, astream = 0;

ret = avformat_open_input(&ic, fname, NULL, NULL);
Expand All @@ -163,6 +188,13 @@ int lpms_get_codec_info(char *fname, pcodec_info out)
if(!audio_present && !video_present) {
// instead of returning -1
ret = GET_CODEC_STREAMS_MISSING;
} else if (video_present) {
out->dur = ic->duration / AV_TIME_BASE;
} else if (audio_present && !video_present) {
out->dur = calculate_duration(ic, astream);
eliteprox marked this conversation as resolved.
Show resolved Hide resolved
if (out->dur == 0) {
out->dur = ic->duration / AV_TIME_BASE;
}
}
// Return
if (video_present && vc->name) {
Expand All @@ -176,6 +208,7 @@ int lpms_get_codec_info(char *fname, pcodec_info out)
}
out->width = ic->streams[vstream]->codecpar->width;
out->height = ic->streams[vstream]->codecpar->height;
out->fps = av_q2d(ic->streams[vstream]->avg_frame_rate);
eliteprox marked this conversation as resolved.
Show resolved Hide resolved
} else {
// Indicate failure to extract video codec from given container
out->video_codec[0] = 0;
Expand All @@ -186,6 +219,7 @@ int lpms_get_codec_info(char *fname, pcodec_info out)
// Indicate failure to extract audio codec from given container
out->audio_codec[0] = 0;
}

eliteprox marked this conversation as resolved.
Show resolved Hide resolved
#undef MIN
close_format_context:
if (ic) avformat_close_input(&ic);
Expand Down
2 changes: 2 additions & 0 deletions ffmpeg/extras.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ typedef struct s_codec_info {
int pixel_format;
int width;
int height;
double fps;
double dur;
} codec_info, *pcodec_info;

int lpms_rtmp2hls(char *listen, char *outf, char *ts_tmpl, char *seg_time, char *seg_start);
Expand Down
5 changes: 5 additions & 0 deletions ffmpeg/ffmpeg.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ type MediaFormatInfo struct {
Acodec, Vcodec string
PixFormat PixelFormat
Width, Height int
FPS float32
Dur float32
eliteprox marked this conversation as resolved.
Show resolved Hide resolved
}

func (f *MediaFormatInfo) ScaledHeight(width int) int {
Expand Down Expand Up @@ -277,6 +279,9 @@ func GetCodecInfo(fname string) (CodecStatus, MediaFormatInfo, error) {
format.PixFormat = PixelFormat{int(params_c.pixel_format)}
format.Width = int(params_c.width)
format.Height = int(params_c.height)
format.FPS = float32(params_c.fps)
format.Dur = float32(params_c.dur)

return status, format, nil
}

Expand Down