Fix OverflowException when scanning media with a very short duration (#13949)

This commit is contained in:
Bond-009 2025-04-19 21:08:29 +02:00 committed by GitHub
parent 7df6e0b16f
commit 74230131a1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 244 additions and 1 deletions

View File

@ -965,7 +965,7 @@ namespace MediaBrowser.MediaEncoding.Probing
// Get average bitrate info from tag "NUMBER_OF_BYTES" and "DURATION" if possible.
var durationInSeconds = GetRuntimeSecondsFromTags(streamInfo);
var bytes = GetNumberOfBytesFromTags(streamInfo);
if (durationInSeconds is not null && bytes is not null)
if (durationInSeconds is not null && durationInSeconds.Value >= 1 && bytes is not null)
{
bps = Convert.ToInt32(bytes * 8 / durationInSeconds, CultureInfo.InvariantCulture);
if (bps > 0)

View File

@ -288,6 +288,40 @@ namespace Jellyfin.MediaEncoding.Tests.Probing
Assert.True(res.VideoStream.IsDefault);
}
[Fact]
public void GetMediaInfo_VideoWithSingleFrameMjpeg_Success()
{
var bytes = File.ReadAllBytes("Test Data/Probing/video_single_frame_mjpeg.json");
var internalMediaInfoResult = JsonSerializer.Deserialize<InternalMediaInfoResult>(bytes, _jsonOptions);
MediaInfo res = _probeResultNormalizer.GetMediaInfo(internalMediaInfoResult, VideoType.VideoFile, false, "Test Data/Probing/video_interlaced.mp4", MediaProtocol.File);
Assert.Equal(3, res.MediaStreams.Count);
Assert.NotNull(res.VideoStream);
Assert.Equal(res.MediaStreams[0], res.VideoStream);
Assert.Equal(0, res.VideoStream.Index);
Assert.Equal("h264", res.VideoStream.Codec);
Assert.Equal("High", res.VideoStream.Profile);
Assert.Equal(MediaStreamType.Video, res.VideoStream.Type);
Assert.Equal(1080, res.VideoStream.Height);
Assert.Equal(1920, res.VideoStream.Width);
Assert.False(res.VideoStream.IsInterlaced);
Assert.Equal("16:9", res.VideoStream.AspectRatio);
Assert.Equal("yuv420p", res.VideoStream.PixelFormat);
Assert.Equal(42d, res.VideoStream.Level);
Assert.Equal(1, res.VideoStream.RefFrames);
Assert.True(res.VideoStream.IsAVC);
Assert.Equal(50f, res.VideoStream.RealFrameRate);
Assert.Equal("1/1000", res.VideoStream.TimeBase);
Assert.Equal(8, res.VideoStream.BitDepth);
Assert.True(res.VideoStream.IsDefault);
var mjpeg = res.MediaStreams[2];
Assert.NotNull(mjpeg);
Assert.Equal("mjpeg", mjpeg.Codec);
}
[Fact]
public void GetMediaInfo_MusicVideo_Success()
{

View File

@ -0,0 +1,209 @@
{
"streams": [
{
"index": 0,
"codec_name": "h264",
"codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10",
"profile": "High",
"codec_type": "video",
"codec_tag_string": "[0][0][0][0]",
"codec_tag": "0x0000",
"width": 1920,
"height": 1080,
"coded_width": 1920,
"coded_height": 1080,
"closed_captions": 0,
"film_grain": 0,
"has_b_frames": 0,
"sample_aspect_ratio": "1:1",
"display_aspect_ratio": "16:9",
"pix_fmt": "yuv420p",
"level": 42,
"chroma_location": "left",
"field_order": "progressive",
"refs": 1,
"is_avc": "true",
"nal_length_size": "4",
"r_frame_rate": "50/1",
"avg_frame_rate": "50/1",
"time_base": "1/1000",
"start_pts": 0,
"start_time": "0.000000",
"bits_per_raw_sample": "8",
"extradata_size": 55,
"disposition": {
"default": 1,
"dub": 0,
"original": 0,
"comment": 0,
"lyrics": 0,
"karaoke": 0,
"forced": 0,
"hearing_impaired": 0,
"visual_impaired": 0,
"clean_effects": 0,
"attached_pic": 0,
"timed_thumbnails": 0,
"non_diegetic": 0,
"captions": 0,
"descriptions": 0,
"metadata": 0,
"dependent": 0,
"still_image": 0
},
"tags": {
"language": "deu",
"HANDLER_NAME": "VideoHandler",
"VENDOR_ID": "[0][0][0][0]",
"BPS": "3950584",
"DURATION": "00:00:10.000000000",
"NUMBER_OF_FRAMES": "500",
"NUMBER_OF_BYTES": "4938231",
"_STATISTICS_WRITING_APP": "mkvpropedit v90.0 ('Hanging On') 64-bit",
"_STATISTICS_WRITING_DATE_UTC": "2025-04-19 10:37:57",
"_STATISTICS_TAGS": "BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES"
}
},
{
"index": 1,
"codec_name": "aac",
"codec_long_name": "AAC (Advanced Audio Coding)",
"profile": "LC",
"codec_type": "audio",
"codec_tag_string": "[0][0][0][0]",
"codec_tag": "0x0000",
"sample_fmt": "fltp",
"sample_rate": "48000",
"channels": 2,
"channel_layout": "stereo",
"bits_per_sample": 0,
"initial_padding": 0,
"r_frame_rate": "0/0",
"avg_frame_rate": "0/0",
"time_base": "1/1000",
"start_pts": 0,
"start_time": "0.000000",
"extradata_size": 2,
"disposition": {
"default": 1,
"dub": 0,
"original": 0,
"comment": 0,
"lyrics": 0,
"karaoke": 0,
"forced": 0,
"hearing_impaired": 0,
"visual_impaired": 0,
"clean_effects": 0,
"attached_pic": 0,
"timed_thumbnails": 0,
"non_diegetic": 0,
"captions": 0,
"descriptions": 0,
"metadata": 0,
"dependent": 0,
"still_image": 0
},
"tags": {
"language": "deu",
"HANDLER_NAME": "SoundHandler",
"VENDOR_ID": "[0][0][0][0]",
"BPS": "255785",
"DURATION": "00:00:09.984000000",
"NUMBER_OF_FRAMES": "469",
"NUMBER_OF_BYTES": "319220",
"_STATISTICS_WRITING_APP": "mkvpropedit v90.0 ('Hanging On') 64-bit",
"_STATISTICS_WRITING_DATE_UTC": "2025-04-19 10:37:57",
"_STATISTICS_TAGS": "BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES"
}
},
{
"index": 2,
"codec_name": "mjpeg",
"codec_long_name": "Motion JPEG",
"profile": "Baseline",
"codec_type": "video",
"codec_tag_string": "[0][0][0][0]",
"codec_tag": "0x0000",
"width": 960,
"height": 540,
"coded_width": 960,
"coded_height": 540,
"closed_captions": 0,
"film_grain": 0,
"has_b_frames": 0,
"sample_aspect_ratio": "1:1",
"display_aspect_ratio": "16:9",
"pix_fmt": "yuvj420p",
"level": -99,
"color_range": "pc",
"color_space": "bt470bg",
"chroma_location": "center",
"refs": 1,
"r_frame_rate": "1000/1",
"avg_frame_rate": "30000/1",
"time_base": "1/1000",
"start_pts": 0,
"start_time": "0.000000",
"bits_per_raw_sample": "8",
"disposition": {
"default": 0,
"dub": 0,
"original": 0,
"comment": 0,
"lyrics": 0,
"karaoke": 0,
"forced": 0,
"hearing_impaired": 0,
"visual_impaired": 0,
"clean_effects": 0,
"attached_pic": 0,
"timed_thumbnails": 0,
"non_diegetic": 0,
"captions": 0,
"descriptions": 0,
"metadata": 0,
"dependent": 0,
"still_image": 0
},
"tags": {
"BPS": "0",
"DURATION": "00:00:00.000011111",
"NUMBER_OF_FRAMES": "1",
"NUMBER_OF_BYTES": "155034",
"_STATISTICS_WRITING_APP": "mkvpropedit v90.0 ('Hanging On') 64-bit",
"_STATISTICS_WRITING_DATE_UTC": "2025-04-19 10:37:57",
"_STATISTICS_TAGS": "BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES"
}
}
],
"chapters": [],
"format": {
"filename": "file:broken_mkv_covers - 01x03 - statistics added using mkvpropedit.mkv",
"nb_streams": 3,
"nb_programs": 0,
"nb_stream_groups": 0,
"format_name": "matroska,webm",
"format_long_name": "Matroska / WebM",
"start_time": "0.000000",
"duration": "10.005000",
"size": "5425928",
"bit_rate": "4338573",
"probe_score": 100,
"tags": {
"title": "Folge 1: Jackpot Immobilie · Wie wir klug vererben",
"EPISODE_SORT": "1",
"MAJOR_BRAND": "isom",
"MINOR_VERSION": "512",
"COMPATIBLE_BRANDS": "isomiso2avc1mp41",
"DATE": "20250318",
"SEASON_NUMBER": "1",
"COMMENT": "https://www.ardmediathek.de/video/Y3JpZDovL2JyLmRlL2Jyb2FkY2FzdC8zZWFmYTcxOC1mZDJmLTRmZTMtYWE4Ny03ZjdlNWViNTk1NDhfb25saW5lYnJvYWRjYXN0",
"DESCRIPTION": "Jeder kennt es: Enge Familienmitglieder sprechen plötzlich nicht mehr miteinander, der Streit ums Erbe entzweit die Familie. Was steht im Testament? Kann sich die Erbengemeinschaft einigen? Wie läuft das mit der Erbschaftssteuer und was sagt das Erbrecht?\n\nDas \"Lohnt sich das?\"-Team hat zwei Familien gefunden, die das Tabu rund ums Erben brechen. Sie erzählen, um wie viel Geld es geht, aber auch, was dieses Immobilienerbe mit ihrer Familie gemacht hat. Warum es einmal gelingt, Häuser in Millionenhöhe ohne jegliche Erbschaftssteuer zu vererben, während andere Geschwister sich über ihr Elternhaus komplett zerstritten haben. Erbfolge, Freibeträge, Nießbrauch - für alle Basics rund ums Erben ist Ralph Caspers zuständig, der kompetent erklärt.",
"SYNOPSIS": "Jeder kennt es: Enge Familienmitglieder sprechen plötzlich nicht mehr miteinander, der Streit ums Erbe entzweit die Familie. Was steht im Testament? Kann sich die Erbengemeinschaft einigen? Wie läuft das mit der Erbschaftssteuer und was sagt das Erbrecht?\n\nDas \"Lohnt sich das?\"-Team hat zwei Familien gefunden, die das Tabu rund ums Erben brechen. Sie erzählen, um wie viel Geld es geht, aber auch, was dieses Immobilienerbe mit ihrer Familie gemacht hat. Warum es einmal gelingt, Häuser in Millionenhöhe ohne jegliche Erbschaftssteuer zu vererben, während andere Geschwister sich über ihr Elternhaus komplett zerstritten haben. Erbfolge, Freibeträge, Nießbrauch - für alle Basics rund ums Erben ist Ralph Caspers zuständig, der kompetent erklärt.",
"SHOW": "Generation Wohnkrise. Lohnt sich das?",
"EPISODE_ID": "Folge 1: Jackpot Immobilie · Wie wir klug vererben",
"ENCODER": "Lavf61.7.100"
}
}
}