2021-05-20 22:10:19 +02:00
#nullable disable
2020-08-04 16:20:52 +02:00
2019-01-13 21:02:23 +01:00
using System ;
2018-12-14 10:40:55 +01:00
using System.Collections.Generic ;
using System.Globalization ;
using System.IO ;
using System.Linq ;
using System.Text ;
2021-07-27 17:09:23 +02:00
using System.Text.RegularExpressions ;
2018-12-14 10:40:55 +01:00
using System.Xml ;
2023-03-25 11:52:02 -06:00
using Jellyfin.Data.Enums ;
2021-07-09 02:06:38 +02:00
using Jellyfin.Extensions ;
Sort embedded collections in Nfo files
Because the Nfo files emit the collections as they are in-memory, the
files are not stable in format, genres, tags, albums, people, etc. are emitted in random orders. Add ordering of the collections when emitting the Nfo files so the file remains stable (unchanged) when underlying media information doesn't change.
In the process of this, it became clear that most of the providers and probes don't trim the strings like people's names, genre names, etc. so did a pass of Trim cleanup too.
Specific ordering: (alphabetical/numeric ascending after trimming blanks and defaulting to zero for missing numbers)
BaseItem: Directors, Writers, Trailers (by Url), Production Locations, Genres, Studios, Tags, Custom Provider Data (by key), Linked Children (by Path>LibraryItemId), Backdrop Images (by path), Actors (by SortOrder>Name)
AlbumNfo: Artists, Album Artists, Tracks (by ParentIndexNumber>IndexNumber>Name)
ArtistNfo: Albums (by Production Year>SortName>Name)
MovieNfo: Artists
Fix Debug build lint
Fix CI debug build lint issue.
Fix review issues
Fixed debug-build lint issues.
Emits the `disc` number to NFO for tracks with a non-zero ParentIndexNumber and only emit `position` if non-zero.
Removed the exception filtering I put in for testing.
Don't emit actors for MusicAlbums or MusicArtists
Swap from String.Trimmed() to ?.Trim()
Addressing PR feedback
Can't use ReadOnlySpan in an async method
Removed now-unused namespace
2023-05-15 00:38:27 -05:00
using MediaBrowser.Controller.Extensions ;
2018-12-14 10:40:55 +01:00
using MediaBrowser.Controller.Library ;
2018-12-31 00:28:23 +01:00
using MediaBrowser.Model.Dto ;
using MediaBrowser.Model.Entities ;
2019-03-14 22:31:51 +01:00
using MediaBrowser.Model.Globalization ;
2018-12-14 10:40:55 +01:00
using MediaBrowser.Model.MediaInfo ;
2018-12-31 00:28:23 +01:00
using Microsoft.Extensions.Logging ;
2018-12-14 10:40:55 +01:00
namespace MediaBrowser.MediaEncoding.Probing
{
2023-07-28 07:16:45 +02:00
/// <summary>
/// Class responsible for normalizing FFprobe output.
/// </summary>
2023-10-08 01:16:00 +02:00
public partial class ProbeResultNormalizer
2018-12-14 10:40:55 +01:00
{
2020-08-04 17:08:09 +02:00
// When extracting subtitles, the maximum length to consider (to avoid invalid filenames)
private const int MaxSubtitleDescriptionExtractionLength = 100 ;
private const string ArtistReplaceValue = " | " ;
2025-09-12 21:58:28 +02:00
private static readonly char [ ] _basicDelimiters = [ '/' , ';' ] ;
private static readonly char [ ] _nameDelimiters = [ . . _basicDelimiters , '|' , '\\' ] ;
private static readonly char [ ] _genreDelimiters = [ . . _basicDelimiters , ',' ] ;
private static readonly string [ ] _webmVideoCodecs = [ "av1" , "vp8" , "vp9" ] ;
private static readonly string [ ] _webmAudioCodecs = [ "opus" , "vorbis" ] ;
2020-08-04 17:08:09 +02:00
2018-12-14 10:40:55 +01:00
private readonly ILogger _logger ;
2019-03-14 22:31:51 +01:00
private readonly ILocalizationManager _localization ;
2018-12-14 10:40:55 +01:00
2021-05-05 14:39:50 +02:00
private string [ ] _splitWhiteList ;
2020-08-04 17:08:09 +02:00
2023-07-28 07:16:45 +02:00
/// <summary>
/// Initializes a new instance of the <see cref="ProbeResultNormalizer"/> class.
/// </summary>
/// <param name="logger">The <see cref="ILogger{ProbeResultNormalizer}"/> for use with the <see cref="ProbeResultNormalizer"/> instance.</param>
/// <param name="localization">The <see cref="ILocalizationManager"/> for use with the <see cref="ProbeResultNormalizer"/> instance.</param>
2020-02-23 10:53:51 +01:00
public ProbeResultNormalizer ( ILogger logger , ILocalizationManager localization )
2018-12-14 10:40:55 +01:00
{
_logger = logger ;
2019-03-14 22:31:51 +01:00
_localization = localization ;
2018-12-14 10:40:55 +01:00
}
2021-07-10 17:04:00 +02:00
private IReadOnlyList < string > SplitWhitelist = > _splitWhiteList ? ? = new string [ ]
{
"AC/DC" ,
2022-09-10 23:30:53 +03:00
"A/T/O/S" ,
2022-01-27 21:52:57 +01:00
"As/Hi Soundworks" ,
2021-07-10 17:04:00 +02:00
"Au/Ra" ,
2021-12-12 01:26:47 +01:00
"Bremer/McCoy" ,
2022-09-11 20:27:58 +03:00
"b/bqスタヂオ" ,
"DOV/S" ,
"DJ'TEKINA//SOMETHING" ,
"IX/ON" ,
"J-CORE SLi//CER" ,
"M(a/u)SH" ,
"Kaoru/Brilliance" ,
"signum/ii" ,
"Richiter(LORB/DUGEM DI BARAT)" ,
2021-07-10 17:04:00 +02:00
"이달의 소녀 1/3" ,
2022-01-27 21:52:57 +01:00
"R!N / Gemie" ,
2021-07-10 17:04:00 +02:00
"LOONA 1/3" ,
"LOONA / yyxy" ,
"LOONA / ODD EYE CIRCLE" ,
2021-10-06 10:32:28 +02:00
"K/DA" ,
2022-09-11 20:27:58 +03:00
"22/7" ,
"諭吉佳作/men" ,
2023-01-26 00:28:17 +01:00
"//dARTH nULL" ,
"Phantom/Ghost" ,
2023-04-20 07:39:34 -06:00
"She/Her/Hers" ,
2023-04-29 13:47:09 +02:00
"5/8erl in Ehr'n" ,
2023-05-04 15:04:38 -04:00
"Smith/Kotzen" ,
2023-10-02 23:00:51 -04:00
"We;Na" ,
2024-03-15 14:05:38 -04:00
"LSR/CITY" ,
2021-07-10 17:04:00 +02:00
} ;
2021-05-05 14:39:50 +02:00
2023-07-28 07:16:45 +02:00
/// <summary>
/// Transforms a FFprobe response into its <see cref="MediaInfo"/> equivalent.
/// </summary>
/// <param name="data">The <see cref="InternalMediaInfoResult"/>.</param>
/// <param name="videoType">The <see cref="VideoType"/>.</param>
/// <param name="isAudio">A boolean indicating whether the media is audio.</param>
/// <param name="path">Path to media file.</param>
/// <param name="protocol">Path media protocol.</param>
/// <returns>The <see cref="MediaInfo"/>.</returns>
2018-12-14 10:40:55 +01:00
public MediaInfo GetMediaInfo ( InternalMediaInfoResult data , VideoType ? videoType , bool isAudio , string path , MediaProtocol protocol )
{
var info = new MediaInfo
{
Path = path ,
2020-08-20 12:16:24 +02:00
Protocol = protocol ,
VideoType = videoType
2018-12-14 10:40:55 +01:00
} ;
FFProbeHelpers . NormalizeFFProbeResult ( data ) ;
SetSize ( data , info ) ;
2020-02-23 10:53:51 +01:00
var internalStreams = data . Streams ? ? Array . Empty < MediaStreamInfo > ( ) ;
2025-04-03 08:06:02 +08:00
var internalFrames = data . Frames ? ? Array . Empty < MediaFrameInfo > ( ) ;
2018-12-14 10:40:55 +01:00
2025-04-03 08:06:02 +08:00
info . MediaStreams = internalStreams . Select ( s = > GetMediaStream ( isAudio , s , data . Format , internalFrames ) )
2022-12-05 15:01:13 +01:00
. Where ( i = > i is not null )
2018-12-14 10:40:55 +01:00
// Drop subtitle streams if we don't know the codec because it will just cause failures if we don't know how to handle them
. Where ( i = > i . Type ! = MediaStreamType . Subtitle | | ! string . IsNullOrWhiteSpace ( i . Codec ) )
. ToList ( ) ;
2021-04-17 11:19:09 +01:00
info . MediaAttachments = internalStreams . Select ( GetMediaAttachment )
2022-12-05 15:01:13 +01:00
. Where ( i = > i is not null )
2019-10-03 11:51:28 -04:00
. ToList ( ) ;
2022-12-05 15:01:13 +01:00
if ( data . Format is not null )
2018-12-14 10:40:55 +01:00
{
2023-12-25 20:52:39 +03:00
info . Container = NormalizeFormat ( data . Format . FormatName , info . MediaStreams ) ;
2018-12-14 10:40:55 +01:00
2023-02-19 16:52:29 +01:00
if ( int . TryParse ( data . Format . BitRate , CultureInfo . InvariantCulture , out var value ) )
2018-12-14 10:40:55 +01:00
{
2023-02-19 16:52:29 +01:00
info . Bitrate = value ;
2018-12-14 10:40:55 +01:00
}
}
var tags = new Dictionary < string , string > ( StringComparer . OrdinalIgnoreCase ) ;
2023-02-01 14:58:04 +01:00
var tagStreamType = isAudio ? CodecType . Audio : CodecType . Video ;
2018-12-14 10:40:55 +01:00
2023-02-01 14:58:04 +01:00
var tagStream = data . Streams ? . FirstOrDefault ( i = > i . CodecType = = tagStreamType ) ;
2018-12-14 10:40:55 +01:00
2022-12-05 15:01:13 +01:00
if ( tagStream ? . Tags is not null )
2021-07-09 02:06:38 +02:00
{
foreach ( var ( key , value ) in tagStream . Tags )
2018-12-14 10:40:55 +01:00
{
2021-07-09 02:06:38 +02:00
tags [ key ] = value ;
2018-12-14 10:40:55 +01:00
}
}
2022-12-05 15:01:13 +01:00
if ( data . Format ? . Tags is not null )
2018-12-14 10:40:55 +01:00
{
2021-07-09 02:06:38 +02:00
foreach ( var ( key , value ) in data . Format . Tags )
2018-12-14 10:40:55 +01:00
{
2021-07-09 02:06:38 +02:00
tags [ key ] = value ;
2018-12-14 10:40:55 +01:00
}
}
FetchGenres ( info , tags ) ;
2021-07-09 02:06:38 +02:00
info . Name = tags . GetFirstNotNullNorWhiteSpaceValue ( "title" , "title-eng" ) ;
info . ForcedSortName = tags . GetFirstNotNullNorWhiteSpaceValue ( "sort_name" , "title-sort" , "titlesort" ) ;
info . Overview = tags . GetFirstNotNullNorWhiteSpaceValue ( "synopsis" , "description" , "desc" ) ;
2018-12-14 10:40:55 +01:00
2020-02-17 14:56:31 +01:00
info . IndexNumber = FFProbeHelpers . GetDictionaryNumericValue ( tags , "episode_sort" ) ;
info . ParentIndexNumber = FFProbeHelpers . GetDictionaryNumericValue ( tags , "season_number" ) ;
2021-07-09 02:06:38 +02:00
info . ShowName = tags . GetValueOrDefault ( "show_name" ) ;
2018-12-14 10:40:55 +01:00
info . ProductionYear = FFProbeHelpers . GetDictionaryNumericValue ( tags , "date" ) ;
2021-04-04 23:34:29 +02:00
// Several different forms of retail/premiere date
info . PremiereDate =
2021-07-05 03:27:03 +02:00
FFProbeHelpers . GetDictionaryDateTime ( tags , "originaldate" ) ? ?
2021-04-04 23:34:29 +02:00
FFProbeHelpers . GetDictionaryDateTime ( tags , "retaildate" ) ? ?
2018-12-14 10:40:55 +01:00
FFProbeHelpers . GetDictionaryDateTime ( tags , "retail date" ) ? ?
FFProbeHelpers . GetDictionaryDateTime ( tags , "retail_date" ) ? ?
2021-04-04 15:08:08 +02:00
FFProbeHelpers . GetDictionaryDateTime ( tags , "date_released" ) ? ?
2022-12-19 10:52:09 -08:00
FFProbeHelpers . GetDictionaryDateTime ( tags , "date" ) ? ?
FFProbeHelpers . GetDictionaryDateTime ( tags , "creation_time" ) ;
2018-12-14 10:40:55 +01:00
2021-04-04 23:34:29 +02:00
// Set common metadata for music (audio) and music videos (video)
2021-07-09 02:06:38 +02:00
info . Album = tags . GetValueOrDefault ( "album" ) ;
2021-04-04 23:34:29 +02:00
2021-07-09 02:06:38 +02:00
if ( tags . TryGetValue ( "artists" , out var artists ) & & ! string . IsNullOrWhiteSpace ( artists ) )
2021-04-04 23:34:29 +02:00
{
2025-09-12 21:58:28 +02:00
info . Artists = SplitDistinctArtists ( artists , _basicDelimiters , false ) . ToArray ( ) ;
2021-04-04 23:34:29 +02:00
}
else
{
2021-07-09 02:06:38 +02:00
var artist = tags . GetFirstNotNullNorWhiteSpaceValue ( "artist" ) ;
2022-12-05 15:00:20 +01:00
info . Artists = artist is null
2021-07-09 02:06:38 +02:00
? Array . Empty < string > ( )
: SplitDistinctArtists ( artist , _nameDelimiters , true ) . ToArray ( ) ;
2021-04-04 23:34:29 +02:00
}
2021-07-09 02:06:38 +02:00
// Guess ProductionYear from PremiereDate if missing
2021-04-04 23:34:29 +02:00
if ( ! info . ProductionYear . HasValue & & info . PremiereDate . HasValue )
{
info . ProductionYear = info . PremiereDate . Value . Year ;
}
// Set mediaType-specific metadata
2018-12-14 10:40:55 +01:00
if ( isAudio )
{
SetAudioRuntimeTicks ( data , info ) ;
// tags are normally located under data.format, but we've seen some cases with ogg where they're part of the info stream
// so let's create a combined list of both
SetAudioInfoFromTags ( info , tags ) ;
}
else
{
FetchStudios ( info , tags , "copyright" ) ;
2021-07-09 02:06:38 +02:00
var iTunExtc = tags . GetFirstNotNullNorWhiteSpaceValue ( "iTunEXTC" ) ;
2022-12-05 15:01:13 +01:00
if ( iTunExtc is not null )
2018-12-14 10:40:55 +01:00
{
2021-07-09 02:06:38 +02:00
var parts = iTunExtc . Split ( '|' , StringSplitOptions . RemoveEmptyEntries ) ;
2019-01-07 23:27:46 +00:00
// Example
2018-12-14 10:40:55 +01:00
// mpaa|G|100|For crude humor
if ( parts . Length > 1 )
{
info . OfficialRating = parts [ 1 ] ;
if ( parts . Length > 3 )
{
info . OfficialRatingDescription = parts [ 3 ] ;
}
}
}
2021-07-09 02:06:38 +02:00
var iTunXml = tags . GetFirstNotNullNorWhiteSpaceValue ( "iTunMOVI" ) ;
2022-12-05 15:01:13 +01:00
if ( iTunXml is not null )
2018-12-14 10:40:55 +01:00
{
2021-07-09 02:06:38 +02:00
FetchFromItunesInfo ( iTunXml , info ) ;
2018-12-14 10:40:55 +01:00
}
2022-12-05 15:01:13 +01:00
if ( data . Format is not null & & ! string . IsNullOrEmpty ( data . Format . Duration ) )
2018-12-14 10:40:55 +01:00
{
2021-09-26 08:14:36 -06:00
info . RunTimeTicks = TimeSpan . FromSeconds ( double . Parse ( data . Format . Duration , CultureInfo . InvariantCulture ) ) . Ticks ;
2018-12-14 10:40:55 +01:00
}
FetchWtvInfo ( info , data ) ;
2022-12-05 15:01:13 +01:00
if ( data . Chapters is not null )
2018-12-14 10:40:55 +01:00
{
info . Chapters = data . Chapters . Select ( GetChapterInfo ) . ToArray ( ) ;
}
ExtractTimestamp ( info ) ;
2021-07-09 02:06:38 +02:00
if ( tags . TryGetValue ( "stereo_mode" , out var stereoMode ) & & string . Equals ( stereoMode , "left_right" , StringComparison . OrdinalIgnoreCase ) )
2018-12-14 10:40:55 +01:00
{
info . Video3DFormat = Video3DFormat . FullSideBySide ;
}
foreach ( var mediaStream in info . MediaStreams )
{
if ( mediaStream . Type = = MediaStreamType . Audio & & ! mediaStream . BitRate . HasValue )
{
mediaStream . BitRate = GetEstimatedAudioBitrate ( mediaStream . Codec , mediaStream . Channels ) ;
}
}
var videoStreamsBitrate = info . MediaStreams . Where ( i = > i . Type = = MediaStreamType . Video ) . Select ( i = > i . BitRate ? ? 0 ) . Sum ( ) ;
// If ffprobe reported the container bitrate as being the same as the video stream bitrate, then it's wrong
if ( videoStreamsBitrate = = ( info . Bitrate ? ? 0 ) )
{
info . InferTotalBitrate ( true ) ;
}
}
return info ;
}
2023-12-25 20:52:39 +03:00
private string NormalizeFormat ( string format , IReadOnlyList < MediaStream > mediaStreams )
2018-12-14 10:40:55 +01:00
{
if ( string . IsNullOrWhiteSpace ( format ) )
{
return null ;
}
2023-07-28 07:16:45 +02:00
// Input can be a list of multiple, comma-delimited formats - each of them needs to be checked
var splitFormat = format . Split ( ',' ) ;
for ( var i = 0 ; i < splitFormat . Length ; i + + )
2018-12-14 10:40:55 +01:00
{
2023-07-28 07:16:45 +02:00
// Handle MPEG-1 container
if ( string . Equals ( splitFormat [ i ] , "mpegvideo" , StringComparison . OrdinalIgnoreCase ) )
{
splitFormat [ i ] = "mpeg" ;
}
2018-12-14 10:40:55 +01:00
2024-06-23 11:40:50 -04:00
// Handle MPEG-TS container
else if ( string . Equals ( splitFormat [ i ] , "mpegts" , StringComparison . OrdinalIgnoreCase ) )
2023-07-28 07:16:45 +02:00
{
splitFormat [ i ] = "ts" ;
}
2023-02-17 00:26:03 +01:00
2023-07-28 07:16:45 +02:00
// Handle matroska container
else if ( string . Equals ( splitFormat [ i ] , "matroska" , StringComparison . OrdinalIgnoreCase ) )
{
splitFormat [ i ] = "mkv" ;
}
2023-12-25 20:52:39 +03:00
// Handle WebM
else if ( string . Equals ( splitFormat [ i ] , "webm" , StringComparison . OrdinalIgnoreCase ) )
{
// Limit WebM to supported codecs
if ( mediaStreams . Any ( stream = > ( stream . Type = = MediaStreamType . Video & & ! _webmVideoCodecs . Contains ( stream . Codec , StringComparison . OrdinalIgnoreCase ) )
| | ( stream . Type = = MediaStreamType . Audio & & ! _webmAudioCodecs . Contains ( stream . Codec , StringComparison . OrdinalIgnoreCase ) ) ) )
{
splitFormat [ i ] = string . Empty ;
}
}
2023-02-17 00:26:03 +01:00
}
2018-12-14 10:40:55 +01:00
2023-12-25 20:52:39 +03:00
return string . Join ( ',' , splitFormat . Where ( s = > ! string . IsNullOrEmpty ( s ) ) ) ;
2018-12-14 10:40:55 +01:00
}
2025-08-27 18:34:00 -05:00
private static int? GetEstimatedAudioBitrate ( string codec , int? channels )
2018-12-14 10:40:55 +01:00
{
if ( ! channels . HasValue )
{
return null ;
}
var channelsValue = channels . Value ;
2020-11-11 17:08:50 +08:00
if ( string . Equals ( codec , "aac" , StringComparison . OrdinalIgnoreCase )
| | string . Equals ( codec , "mp3" , StringComparison . OrdinalIgnoreCase ) )
2018-12-14 10:40:55 +01:00
{
2021-07-09 02:06:38 +02:00
switch ( channelsValue )
2018-12-14 10:40:55 +01:00
{
2021-07-09 02:06:38 +02:00
case < = 2 :
return 192000 ;
case > = 5 :
return 320000 ;
2018-12-14 10:40:55 +01:00
}
}
2020-11-11 17:08:50 +08:00
if ( string . Equals ( codec , "ac3" , StringComparison . OrdinalIgnoreCase )
| | string . Equals ( codec , "eac3" , StringComparison . OrdinalIgnoreCase ) )
{
2021-07-09 02:06:38 +02:00
switch ( channelsValue )
2020-11-11 17:08:50 +08:00
{
2021-07-09 02:06:38 +02:00
case < = 2 :
return 192000 ;
case > = 5 :
return 640000 ;
2020-11-11 17:08:50 +08:00
}
}
if ( string . Equals ( codec , "flac" , StringComparison . OrdinalIgnoreCase )
| | string . Equals ( codec , "alac" , StringComparison . OrdinalIgnoreCase ) )
{
2021-07-09 02:06:38 +02:00
switch ( channelsValue )
2020-11-11 17:08:50 +08:00
{
2021-07-09 02:06:38 +02:00
case < = 2 :
return 960000 ;
case > = 5 :
return 2880000 ;
2020-11-11 17:08:50 +08:00
}
}
2018-12-14 10:40:55 +01:00
return null ;
}
private void FetchFromItunesInfo ( string xml , MediaInfo info )
{
// Make things simpler and strip out the dtd
var plistIndex = xml . IndexOf ( "<plist" , StringComparison . OrdinalIgnoreCase ) ;
if ( plistIndex ! = - 1 )
{
xml = xml . Substring ( plistIndex ) ;
}
xml = "<?xml version=\"1.0\"?>" + xml ;
// <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>cast</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Blender Foundation</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Janus Bager Kristensen</string>\n\t\t</dict>\n\t</array>\n\t<key>directors</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Sacha Goedegebure</string>\n\t\t</dict>\n\t</array>\n\t<key>studio</key>\n\t<string>Blender Foundation</string>\n</dict>\n</plist>\n
using ( var stream = new MemoryStream ( Encoding . UTF8 . GetBytes ( xml ) ) )
2019-02-02 16:12:16 +01:00
using ( var streamReader = new StreamReader ( stream ) )
2018-12-14 10:40:55 +01:00
{
2019-02-02 16:12:16 +01:00
try
2018-12-14 10:40:55 +01:00
{
2019-02-02 16:12:16 +01:00
using ( var reader = XmlReader . Create ( streamReader ) )
2018-12-14 10:40:55 +01:00
{
2019-02-02 16:12:16 +01:00
reader . MoveToContent ( ) ;
reader . Read ( ) ;
2018-12-14 10:40:55 +01:00
2019-02-02 16:12:16 +01:00
// Loop through each element
while ( ! reader . EOF & & reader . ReadState = = ReadState . Interactive )
{
if ( reader . NodeType = = XmlNodeType . Element )
2018-12-14 10:40:55 +01:00
{
2019-02-02 16:12:16 +01:00
switch ( reader . Name )
2018-12-14 10:40:55 +01:00
{
2019-02-02 16:12:16 +01:00
case "dict" :
if ( reader . IsEmptyElement )
{
reader . Read ( ) ;
continue ;
}
2020-06-16 09:43:52 +12:00
2019-02-02 16:12:16 +01:00
using ( var subtree = reader . ReadSubtree ( ) )
{
ReadFromDictNode ( subtree , info ) ;
}
2020-06-16 09:43:52 +12:00
2019-02-02 16:12:16 +01:00
break ;
default :
reader . Skip ( ) ;
break ;
2018-12-14 10:40:55 +01:00
}
}
2019-02-02 16:12:16 +01:00
else
{
reader . Read ( ) ;
}
2018-12-14 10:40:55 +01:00
}
}
2019-02-02 16:12:16 +01:00
}
catch ( XmlException )
{
// I've seen probe examples where the iTunMOVI value is just "<"
// So we should not allow this to fail the entire probing operation
2018-12-14 10:40:55 +01:00
}
}
}
private void ReadFromDictNode ( XmlReader reader , MediaInfo info )
{
string currentKey = null ;
2019-01-13 21:37:13 +01:00
var pairs = new List < NameValuePair > ( ) ;
2018-12-14 10:40:55 +01:00
reader . MoveToContent ( ) ;
reader . Read ( ) ;
// Loop through each element
while ( ! reader . EOF & & reader . ReadState = = ReadState . Interactive )
{
if ( reader . NodeType = = XmlNodeType . Element )
{
switch ( reader . Name )
{
case "key" :
if ( ! string . IsNullOrWhiteSpace ( currentKey ) )
{
ProcessPairs ( currentKey , pairs , info ) ;
}
2020-06-16 09:43:52 +12:00
2018-12-14 10:40:55 +01:00
currentKey = reader . ReadElementContentAsString ( ) ;
pairs = new List < NameValuePair > ( ) ;
break ;
case "string" :
var value = reader . ReadElementContentAsString ( ) ;
if ( ! string . IsNullOrWhiteSpace ( value ) )
{
pairs . Add ( new NameValuePair
{
Name = value ,
Value = value
} ) ;
}
2020-06-16 09:43:52 +12:00
2018-12-14 10:40:55 +01:00
break ;
case "array" :
if ( reader . IsEmptyElement )
{
reader . Read ( ) ;
continue ;
}
2020-06-16 09:43:52 +12:00
2018-12-14 10:40:55 +01:00
using ( var subtree = reader . ReadSubtree ( ) )
{
if ( ! string . IsNullOrWhiteSpace ( currentKey ) )
{
pairs . AddRange ( ReadValueArray ( subtree ) ) ;
}
}
2020-06-16 09:43:52 +12:00
2018-12-14 10:40:55 +01:00
break ;
default :
reader . Skip ( ) ;
break ;
}
}
else
{
reader . Read ( ) ;
}
}
}
private List < NameValuePair > ReadValueArray ( XmlReader reader )
{
2019-01-13 21:37:13 +01:00
var pairs = new List < NameValuePair > ( ) ;
2018-12-14 10:40:55 +01:00
reader . MoveToContent ( ) ;
reader . Read ( ) ;
// Loop through each element
while ( ! reader . EOF & & reader . ReadState = = ReadState . Interactive )
{
if ( reader . NodeType = = XmlNodeType . Element )
{
switch ( reader . Name )
{
case "dict" :
if ( reader . IsEmptyElement )
{
reader . Read ( ) ;
continue ;
}
2020-06-16 09:43:52 +12:00
2018-12-14 10:40:55 +01:00
using ( var subtree = reader . ReadSubtree ( ) )
{
var dict = GetNameValuePair ( subtree ) ;
2022-12-05 15:01:13 +01:00
if ( dict is not null )
2018-12-14 10:40:55 +01:00
{
pairs . Add ( dict ) ;
}
}
2020-06-16 09:43:52 +12:00
2018-12-14 10:40:55 +01:00
break ;
default :
reader . Skip ( ) ;
break ;
}
}
else
{
reader . Read ( ) ;
}
}
return pairs ;
}
2025-08-27 18:34:00 -05:00
private static void ProcessPairs ( string key , List < NameValuePair > pairs , MediaInfo info )
2018-12-14 10:40:55 +01:00
{
2023-10-24 00:10:31 +02:00
List < BaseItemPerson > peoples = new List < BaseItemPerson > ( ) ;
Sort embedded collections in Nfo files
Because the Nfo files emit the collections as they are in-memory, the
files are not stable in format, genres, tags, albums, people, etc. are emitted in random orders. Add ordering of the collections when emitting the Nfo files so the file remains stable (unchanged) when underlying media information doesn't change.
In the process of this, it became clear that most of the providers and probes don't trim the strings like people's names, genre names, etc. so did a pass of Trim cleanup too.
Specific ordering: (alphabetical/numeric ascending after trimming blanks and defaulting to zero for missing numbers)
BaseItem: Directors, Writers, Trailers (by Url), Production Locations, Genres, Studios, Tags, Custom Provider Data (by key), Linked Children (by Path>LibraryItemId), Backdrop Images (by path), Actors (by SortOrder>Name)
AlbumNfo: Artists, Album Artists, Tracks (by ParentIndexNumber>IndexNumber>Name)
ArtistNfo: Albums (by Production Year>SortName>Name)
MovieNfo: Artists
Fix Debug build lint
Fix CI debug build lint issue.
Fix review issues
Fixed debug-build lint issues.
Emits the `disc` number to NFO for tracks with a non-zero ParentIndexNumber and only emit `position` if non-zero.
Removed the exception filtering I put in for testing.
Don't emit actors for MusicAlbums or MusicArtists
Swap from String.Trimmed() to ?.Trim()
Addressing PR feedback
Can't use ReadOnlySpan in an async method
Removed now-unused namespace
2023-05-15 00:38:27 -05:00
var distinctPairs = pairs . Select ( p = > p . Value )
. Where ( i = > ! string . IsNullOrWhiteSpace ( i ) )
. Trimmed ( )
. Distinct ( StringComparer . OrdinalIgnoreCase ) ;
2018-12-14 10:40:55 +01:00
if ( string . Equals ( key , "studio" , StringComparison . OrdinalIgnoreCase ) )
{
Sort embedded collections in Nfo files
Because the Nfo files emit the collections as they are in-memory, the
files are not stable in format, genres, tags, albums, people, etc. are emitted in random orders. Add ordering of the collections when emitting the Nfo files so the file remains stable (unchanged) when underlying media information doesn't change.
In the process of this, it became clear that most of the providers and probes don't trim the strings like people's names, genre names, etc. so did a pass of Trim cleanup too.
Specific ordering: (alphabetical/numeric ascending after trimming blanks and defaulting to zero for missing numbers)
BaseItem: Directors, Writers, Trailers (by Url), Production Locations, Genres, Studios, Tags, Custom Provider Data (by key), Linked Children (by Path>LibraryItemId), Backdrop Images (by path), Actors (by SortOrder>Name)
AlbumNfo: Artists, Album Artists, Tracks (by ParentIndexNumber>IndexNumber>Name)
ArtistNfo: Albums (by Production Year>SortName>Name)
MovieNfo: Artists
Fix Debug build lint
Fix CI debug build lint issue.
Fix review issues
Fixed debug-build lint issues.
Emits the `disc` number to NFO for tracks with a non-zero ParentIndexNumber and only emit `position` if non-zero.
Removed the exception filtering I put in for testing.
Don't emit actors for MusicAlbums or MusicArtists
Swap from String.Trimmed() to ?.Trim()
Addressing PR feedback
Can't use ReadOnlySpan in an async method
Removed now-unused namespace
2023-05-15 00:38:27 -05:00
info . Studios = distinctPairs . ToArray ( ) ;
2018-12-14 10:40:55 +01:00
}
else if ( string . Equals ( key , "screenwriters" , StringComparison . OrdinalIgnoreCase ) )
{
Sort embedded collections in Nfo files
Because the Nfo files emit the collections as they are in-memory, the
files are not stable in format, genres, tags, albums, people, etc. are emitted in random orders. Add ordering of the collections when emitting the Nfo files so the file remains stable (unchanged) when underlying media information doesn't change.
In the process of this, it became clear that most of the providers and probes don't trim the strings like people's names, genre names, etc. so did a pass of Trim cleanup too.
Specific ordering: (alphabetical/numeric ascending after trimming blanks and defaulting to zero for missing numbers)
BaseItem: Directors, Writers, Trailers (by Url), Production Locations, Genres, Studios, Tags, Custom Provider Data (by key), Linked Children (by Path>LibraryItemId), Backdrop Images (by path), Actors (by SortOrder>Name)
AlbumNfo: Artists, Album Artists, Tracks (by ParentIndexNumber>IndexNumber>Name)
ArtistNfo: Albums (by Production Year>SortName>Name)
MovieNfo: Artists
Fix Debug build lint
Fix CI debug build lint issue.
Fix review issues
Fixed debug-build lint issues.
Emits the `disc` number to NFO for tracks with a non-zero ParentIndexNumber and only emit `position` if non-zero.
Removed the exception filtering I put in for testing.
Don't emit actors for MusicAlbums or MusicArtists
Swap from String.Trimmed() to ?.Trim()
Addressing PR feedback
Can't use ReadOnlySpan in an async method
Removed now-unused namespace
2023-05-15 00:38:27 -05:00
foreach ( var pair in distinctPairs )
2018-12-14 10:40:55 +01:00
{
peoples . Add ( new BaseItemPerson
{
Sort embedded collections in Nfo files
Because the Nfo files emit the collections as they are in-memory, the
files are not stable in format, genres, tags, albums, people, etc. are emitted in random orders. Add ordering of the collections when emitting the Nfo files so the file remains stable (unchanged) when underlying media information doesn't change.
In the process of this, it became clear that most of the providers and probes don't trim the strings like people's names, genre names, etc. so did a pass of Trim cleanup too.
Specific ordering: (alphabetical/numeric ascending after trimming blanks and defaulting to zero for missing numbers)
BaseItem: Directors, Writers, Trailers (by Url), Production Locations, Genres, Studios, Tags, Custom Provider Data (by key), Linked Children (by Path>LibraryItemId), Backdrop Images (by path), Actors (by SortOrder>Name)
AlbumNfo: Artists, Album Artists, Tracks (by ParentIndexNumber>IndexNumber>Name)
ArtistNfo: Albums (by Production Year>SortName>Name)
MovieNfo: Artists
Fix Debug build lint
Fix CI debug build lint issue.
Fix review issues
Fixed debug-build lint issues.
Emits the `disc` number to NFO for tracks with a non-zero ParentIndexNumber and only emit `position` if non-zero.
Removed the exception filtering I put in for testing.
Don't emit actors for MusicAlbums or MusicArtists
Swap from String.Trimmed() to ?.Trim()
Addressing PR feedback
Can't use ReadOnlySpan in an async method
Removed now-unused namespace
2023-05-15 00:38:27 -05:00
Name = pair ,
2023-03-25 11:52:02 -06:00
Type = PersonKind . Writer
2018-12-14 10:40:55 +01:00
} ) ;
}
}
else if ( string . Equals ( key , "producers" , StringComparison . OrdinalIgnoreCase ) )
{
Sort embedded collections in Nfo files
Because the Nfo files emit the collections as they are in-memory, the
files are not stable in format, genres, tags, albums, people, etc. are emitted in random orders. Add ordering of the collections when emitting the Nfo files so the file remains stable (unchanged) when underlying media information doesn't change.
In the process of this, it became clear that most of the providers and probes don't trim the strings like people's names, genre names, etc. so did a pass of Trim cleanup too.
Specific ordering: (alphabetical/numeric ascending after trimming blanks and defaulting to zero for missing numbers)
BaseItem: Directors, Writers, Trailers (by Url), Production Locations, Genres, Studios, Tags, Custom Provider Data (by key), Linked Children (by Path>LibraryItemId), Backdrop Images (by path), Actors (by SortOrder>Name)
AlbumNfo: Artists, Album Artists, Tracks (by ParentIndexNumber>IndexNumber>Name)
ArtistNfo: Albums (by Production Year>SortName>Name)
MovieNfo: Artists
Fix Debug build lint
Fix CI debug build lint issue.
Fix review issues
Fixed debug-build lint issues.
Emits the `disc` number to NFO for tracks with a non-zero ParentIndexNumber and only emit `position` if non-zero.
Removed the exception filtering I put in for testing.
Don't emit actors for MusicAlbums or MusicArtists
Swap from String.Trimmed() to ?.Trim()
Addressing PR feedback
Can't use ReadOnlySpan in an async method
Removed now-unused namespace
2023-05-15 00:38:27 -05:00
foreach ( var pair in distinctPairs )
2018-12-14 10:40:55 +01:00
{
peoples . Add ( new BaseItemPerson
{
Sort embedded collections in Nfo files
Because the Nfo files emit the collections as they are in-memory, the
files are not stable in format, genres, tags, albums, people, etc. are emitted in random orders. Add ordering of the collections when emitting the Nfo files so the file remains stable (unchanged) when underlying media information doesn't change.
In the process of this, it became clear that most of the providers and probes don't trim the strings like people's names, genre names, etc. so did a pass of Trim cleanup too.
Specific ordering: (alphabetical/numeric ascending after trimming blanks and defaulting to zero for missing numbers)
BaseItem: Directors, Writers, Trailers (by Url), Production Locations, Genres, Studios, Tags, Custom Provider Data (by key), Linked Children (by Path>LibraryItemId), Backdrop Images (by path), Actors (by SortOrder>Name)
AlbumNfo: Artists, Album Artists, Tracks (by ParentIndexNumber>IndexNumber>Name)
ArtistNfo: Albums (by Production Year>SortName>Name)
MovieNfo: Artists
Fix Debug build lint
Fix CI debug build lint issue.
Fix review issues
Fixed debug-build lint issues.
Emits the `disc` number to NFO for tracks with a non-zero ParentIndexNumber and only emit `position` if non-zero.
Removed the exception filtering I put in for testing.
Don't emit actors for MusicAlbums or MusicArtists
Swap from String.Trimmed() to ?.Trim()
Addressing PR feedback
Can't use ReadOnlySpan in an async method
Removed now-unused namespace
2023-05-15 00:38:27 -05:00
Name = pair ,
2023-03-25 11:52:02 -06:00
Type = PersonKind . Producer
2018-12-14 10:40:55 +01:00
} ) ;
}
}
else if ( string . Equals ( key , "directors" , StringComparison . OrdinalIgnoreCase ) )
{
Sort embedded collections in Nfo files
Because the Nfo files emit the collections as they are in-memory, the
files are not stable in format, genres, tags, albums, people, etc. are emitted in random orders. Add ordering of the collections when emitting the Nfo files so the file remains stable (unchanged) when underlying media information doesn't change.
In the process of this, it became clear that most of the providers and probes don't trim the strings like people's names, genre names, etc. so did a pass of Trim cleanup too.
Specific ordering: (alphabetical/numeric ascending after trimming blanks and defaulting to zero for missing numbers)
BaseItem: Directors, Writers, Trailers (by Url), Production Locations, Genres, Studios, Tags, Custom Provider Data (by key), Linked Children (by Path>LibraryItemId), Backdrop Images (by path), Actors (by SortOrder>Name)
AlbumNfo: Artists, Album Artists, Tracks (by ParentIndexNumber>IndexNumber>Name)
ArtistNfo: Albums (by Production Year>SortName>Name)
MovieNfo: Artists
Fix Debug build lint
Fix CI debug build lint issue.
Fix review issues
Fixed debug-build lint issues.
Emits the `disc` number to NFO for tracks with a non-zero ParentIndexNumber and only emit `position` if non-zero.
Removed the exception filtering I put in for testing.
Don't emit actors for MusicAlbums or MusicArtists
Swap from String.Trimmed() to ?.Trim()
Addressing PR feedback
Can't use ReadOnlySpan in an async method
Removed now-unused namespace
2023-05-15 00:38:27 -05:00
foreach ( var pair in distinctPairs )
2018-12-14 10:40:55 +01:00
{
peoples . Add ( new BaseItemPerson
{
Sort embedded collections in Nfo files
Because the Nfo files emit the collections as they are in-memory, the
files are not stable in format, genres, tags, albums, people, etc. are emitted in random orders. Add ordering of the collections when emitting the Nfo files so the file remains stable (unchanged) when underlying media information doesn't change.
In the process of this, it became clear that most of the providers and probes don't trim the strings like people's names, genre names, etc. so did a pass of Trim cleanup too.
Specific ordering: (alphabetical/numeric ascending after trimming blanks and defaulting to zero for missing numbers)
BaseItem: Directors, Writers, Trailers (by Url), Production Locations, Genres, Studios, Tags, Custom Provider Data (by key), Linked Children (by Path>LibraryItemId), Backdrop Images (by path), Actors (by SortOrder>Name)
AlbumNfo: Artists, Album Artists, Tracks (by ParentIndexNumber>IndexNumber>Name)
ArtistNfo: Albums (by Production Year>SortName>Name)
MovieNfo: Artists
Fix Debug build lint
Fix CI debug build lint issue.
Fix review issues
Fixed debug-build lint issues.
Emits the `disc` number to NFO for tracks with a non-zero ParentIndexNumber and only emit `position` if non-zero.
Removed the exception filtering I put in for testing.
Don't emit actors for MusicAlbums or MusicArtists
Swap from String.Trimmed() to ?.Trim()
Addressing PR feedback
Can't use ReadOnlySpan in an async method
Removed now-unused namespace
2023-05-15 00:38:27 -05:00
Name = pair ,
2023-03-25 11:52:02 -06:00
Type = PersonKind . Director
2018-12-14 10:40:55 +01:00
} ) ;
}
}
info . People = peoples . ToArray ( ) ;
}
2025-08-27 18:34:00 -05:00
private static NameValuePair GetNameValuePair ( XmlReader reader )
2018-12-14 10:40:55 +01:00
{
string name = null ;
string value = null ;
reader . MoveToContent ( ) ;
reader . Read ( ) ;
// Loop through each element
while ( ! reader . EOF & & reader . ReadState = = ReadState . Interactive )
{
if ( reader . NodeType = = XmlNodeType . Element )
{
switch ( reader . Name )
{
case "key" :
Sort embedded collections in Nfo files
Because the Nfo files emit the collections as they are in-memory, the
files are not stable in format, genres, tags, albums, people, etc. are emitted in random orders. Add ordering of the collections when emitting the Nfo files so the file remains stable (unchanged) when underlying media information doesn't change.
In the process of this, it became clear that most of the providers and probes don't trim the strings like people's names, genre names, etc. so did a pass of Trim cleanup too.
Specific ordering: (alphabetical/numeric ascending after trimming blanks and defaulting to zero for missing numbers)
BaseItem: Directors, Writers, Trailers (by Url), Production Locations, Genres, Studios, Tags, Custom Provider Data (by key), Linked Children (by Path>LibraryItemId), Backdrop Images (by path), Actors (by SortOrder>Name)
AlbumNfo: Artists, Album Artists, Tracks (by ParentIndexNumber>IndexNumber>Name)
ArtistNfo: Albums (by Production Year>SortName>Name)
MovieNfo: Artists
Fix Debug build lint
Fix CI debug build lint issue.
Fix review issues
Fixed debug-build lint issues.
Emits the `disc` number to NFO for tracks with a non-zero ParentIndexNumber and only emit `position` if non-zero.
Removed the exception filtering I put in for testing.
Don't emit actors for MusicAlbums or MusicArtists
Swap from String.Trimmed() to ?.Trim()
Addressing PR feedback
Can't use ReadOnlySpan in an async method
Removed now-unused namespace
2023-05-15 00:38:27 -05:00
name = reader . ReadNormalizedString ( ) ;
2018-12-14 10:40:55 +01:00
break ;
case "string" :
Sort embedded collections in Nfo files
Because the Nfo files emit the collections as they are in-memory, the
files are not stable in format, genres, tags, albums, people, etc. are emitted in random orders. Add ordering of the collections when emitting the Nfo files so the file remains stable (unchanged) when underlying media information doesn't change.
In the process of this, it became clear that most of the providers and probes don't trim the strings like people's names, genre names, etc. so did a pass of Trim cleanup too.
Specific ordering: (alphabetical/numeric ascending after trimming blanks and defaulting to zero for missing numbers)
BaseItem: Directors, Writers, Trailers (by Url), Production Locations, Genres, Studios, Tags, Custom Provider Data (by key), Linked Children (by Path>LibraryItemId), Backdrop Images (by path), Actors (by SortOrder>Name)
AlbumNfo: Artists, Album Artists, Tracks (by ParentIndexNumber>IndexNumber>Name)
ArtistNfo: Albums (by Production Year>SortName>Name)
MovieNfo: Artists
Fix Debug build lint
Fix CI debug build lint issue.
Fix review issues
Fixed debug-build lint issues.
Emits the `disc` number to NFO for tracks with a non-zero ParentIndexNumber and only emit `position` if non-zero.
Removed the exception filtering I put in for testing.
Don't emit actors for MusicAlbums or MusicArtists
Swap from String.Trimmed() to ?.Trim()
Addressing PR feedback
Can't use ReadOnlySpan in an async method
Removed now-unused namespace
2023-05-15 00:38:27 -05:00
value = reader . ReadNormalizedString ( ) ;
2018-12-14 10:40:55 +01:00
break ;
default :
reader . Skip ( ) ;
break ;
}
}
else
{
reader . Read ( ) ;
}
}
Sort embedded collections in Nfo files
Because the Nfo files emit the collections as they are in-memory, the
files are not stable in format, genres, tags, albums, people, etc. are emitted in random orders. Add ordering of the collections when emitting the Nfo files so the file remains stable (unchanged) when underlying media information doesn't change.
In the process of this, it became clear that most of the providers and probes don't trim the strings like people's names, genre names, etc. so did a pass of Trim cleanup too.
Specific ordering: (alphabetical/numeric ascending after trimming blanks and defaulting to zero for missing numbers)
BaseItem: Directors, Writers, Trailers (by Url), Production Locations, Genres, Studios, Tags, Custom Provider Data (by key), Linked Children (by Path>LibraryItemId), Backdrop Images (by path), Actors (by SortOrder>Name)
AlbumNfo: Artists, Album Artists, Tracks (by ParentIndexNumber>IndexNumber>Name)
ArtistNfo: Albums (by Production Year>SortName>Name)
MovieNfo: Artists
Fix Debug build lint
Fix CI debug build lint issue.
Fix review issues
Fixed debug-build lint issues.
Emits the `disc` number to NFO for tracks with a non-zero ParentIndexNumber and only emit `position` if non-zero.
Removed the exception filtering I put in for testing.
Don't emit actors for MusicAlbums or MusicArtists
Swap from String.Trimmed() to ?.Trim()
Addressing PR feedback
Can't use ReadOnlySpan in an async method
Removed now-unused namespace
2023-05-15 00:38:27 -05:00
if ( string . IsNullOrEmpty ( name )
| | string . IsNullOrEmpty ( value ) )
2018-12-14 10:40:55 +01:00
{
return null ;
}
return new NameValuePair
{
Name = name ,
Value = value
} ;
}
2025-08-27 18:34:00 -05:00
private static string NormalizeSubtitleCodec ( string codec )
2018-12-14 10:40:55 +01:00
{
if ( string . Equals ( codec , "dvb_subtitle" , StringComparison . OrdinalIgnoreCase ) )
{
2024-06-23 11:40:59 -04:00
codec = "DVBSUB" ;
2018-12-14 10:40:55 +01:00
}
2024-06-23 11:40:59 -04:00
else if ( string . Equals ( codec , "dvb_teletext" , StringComparison . OrdinalIgnoreCase ) )
2018-12-14 10:40:55 +01:00
{
2024-06-23 11:40:59 -04:00
codec = "DVBTXT" ;
2018-12-14 10:40:55 +01:00
}
2024-06-23 11:40:59 -04:00
else if ( string . Equals ( codec , "dvd_subtitle" , StringComparison . OrdinalIgnoreCase ) )
2018-12-14 10:40:55 +01:00
{
2024-06-23 11:40:59 -04:00
codec = "DVDSUB" ; // .sub+.idx
}
else if ( string . Equals ( codec , "hdmv_pgs_subtitle" , StringComparison . OrdinalIgnoreCase ) )
{
codec = "PGSSUB" ; // .sup
2018-12-14 10:40:55 +01:00
}
return codec ;
}
2019-10-03 11:51:28 -04:00
/// <summary>
2020-06-16 10:37:52 +12:00
/// Converts ffprobe stream info to our MediaAttachment class.
2019-10-03 11:51:28 -04:00
/// </summary>
/// <param name="streamInfo">The stream info.</param>
/// <returns>MediaAttachments.</returns>
private MediaAttachment GetMediaAttachment ( MediaStreamInfo streamInfo )
{
2023-02-01 14:58:04 +01:00
if ( streamInfo . CodecType ! = CodecType . Attachment
2021-10-11 21:25:12 +02:00
& & streamInfo . Disposition ? . GetValueOrDefault ( "attached_pic" ) ! = 1 )
2019-10-03 11:51:28 -04:00
{
return null ;
}
var attachment = new MediaAttachment
{
2020-01-08 18:13:11 +01:00
Codec = streamInfo . CodecName ,
Index = streamInfo . Index
2019-10-03 11:51:28 -04:00
} ;
2020-01-08 18:13:11 +01:00
if ( ! string . IsNullOrWhiteSpace ( streamInfo . CodecTagString ) )
2019-10-03 11:51:28 -04:00
{
2020-03-24 16:12:06 +01:00
attachment . CodecTag = streamInfo . CodecTagString ;
2019-10-03 11:51:28 -04:00
}
2022-12-05 15:01:13 +01:00
if ( streamInfo . Tags is not null )
2019-10-03 11:51:28 -04:00
{
2020-01-08 18:13:11 +01:00
attachment . FileName = GetDictionaryValue ( streamInfo . Tags , "filename" ) ;
attachment . MimeType = GetDictionaryValue ( streamInfo . Tags , "mimetype" ) ;
attachment . Comment = GetDictionaryValue ( streamInfo . Tags , "comment" ) ;
2019-10-03 11:51:28 -04:00
}
return attachment ;
}
2018-12-14 10:40:55 +01:00
/// <summary>
2020-06-16 10:37:52 +12:00
/// Converts ffprobe stream info to our MediaStream class.
2018-12-14 10:40:55 +01:00
/// </summary>
/// <param name="isAudio">if set to <c>true</c> [is info].</param>
/// <param name="streamInfo">The stream info.</param>
/// <param name="formatInfo">The format info.</param>
2025-04-03 08:06:02 +08:00
/// <param name="frameInfoList">The frame info.</param>
2018-12-14 10:40:55 +01:00
/// <returns>MediaStream.</returns>
2025-04-03 08:06:02 +08:00
private MediaStream GetMediaStream ( bool isAudio , MediaStreamInfo streamInfo , MediaFormatInfo formatInfo , IReadOnlyList < MediaFrameInfo > frameInfoList )
2018-12-14 10:40:55 +01:00
{
// These are mp4 chapters
Fix exceptions while scanning
Fixes these exceptions:
```
[2019-12-22 20:48:14.779 +01:00] [ERR] Error in WaitForExit
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.GetWaitState()
at System.Diagnostics.Process.WaitForExitCore(Int32 milliseconds)
at System.Diagnostics.Process.WaitForExit(Int32 milliseconds)
at Emby.Server.Implementations.Diagnostics.CommonProcess.WaitForExit(Int32 timeMs) in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 100
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 785
[2019-12-22 20:48:14.790 +01:00] [INF] Killing ffmpeg process
[2019-12-22 20:48:14.795 +01:00] [ERR] Error killing process
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.Kill()
at Emby.Server.Implementations.Diagnostics.CommonProcess.Kill() in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 95
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 799
[2019-12-22 20:48:14.808 +01:00] [ERR] Error in "ffprobe"
System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $.streams[0].start_pts | LineNumber: 32 | BytePositionInLine: 26.
---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
at System.Text.Json.Utf8JsonReader.GetString()
at System.Text.Json.Serialization.Converters.JsonConverterString.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.JsonPropertyInfoNotNullable`4.OnRead(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonPropertyInfo.Read(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonSerializer.HandleValue(JsonTokenType tokenType, JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& readStack, Utf8JsonReader& reader, Exception ex)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadCore(JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken)
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.GetMediaInfoInternal(String inputPath, String primaryPath, MediaProtocol protocol, Boolean extractChapters, String probeSizeArgument, Boolean isAudio, Nullable`1 videoType, Boolean forceEnableLogging, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 399
at MediaBrowser.Providers.MediaInfo.FFProbeVideoInfo.ProbeVideo[T](T item, MetadataRefreshOptions options, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs:line 122
at MediaBrowser.Providers.Manager.MetadataService`2.RunCustomProvider(ICustomMetadataProvider`1 provider, TItemType item, String logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/Manager/MetadataService.cs:line 815
```
2019-12-22 21:39:26 +01:00
if ( string . Equals ( streamInfo . CodecName , "mov_text" , StringComparison . OrdinalIgnoreCase ) )
2018-12-14 10:40:55 +01:00
{
// Edit: but these are also sometimes subtitles?
2020-06-14 21:11:11 +12:00
// return null;
2018-12-14 10:40:55 +01:00
}
var stream = new MediaStream
{
Fix exceptions while scanning
Fixes these exceptions:
```
[2019-12-22 20:48:14.779 +01:00] [ERR] Error in WaitForExit
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.GetWaitState()
at System.Diagnostics.Process.WaitForExitCore(Int32 milliseconds)
at System.Diagnostics.Process.WaitForExit(Int32 milliseconds)
at Emby.Server.Implementations.Diagnostics.CommonProcess.WaitForExit(Int32 timeMs) in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 100
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 785
[2019-12-22 20:48:14.790 +01:00] [INF] Killing ffmpeg process
[2019-12-22 20:48:14.795 +01:00] [ERR] Error killing process
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.Kill()
at Emby.Server.Implementations.Diagnostics.CommonProcess.Kill() in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 95
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 799
[2019-12-22 20:48:14.808 +01:00] [ERR] Error in "ffprobe"
System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $.streams[0].start_pts | LineNumber: 32 | BytePositionInLine: 26.
---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
at System.Text.Json.Utf8JsonReader.GetString()
at System.Text.Json.Serialization.Converters.JsonConverterString.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.JsonPropertyInfoNotNullable`4.OnRead(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonPropertyInfo.Read(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonSerializer.HandleValue(JsonTokenType tokenType, JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& readStack, Utf8JsonReader& reader, Exception ex)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadCore(JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken)
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.GetMediaInfoInternal(String inputPath, String primaryPath, MediaProtocol protocol, Boolean extractChapters, String probeSizeArgument, Boolean isAudio, Nullable`1 videoType, Boolean forceEnableLogging, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 399
at MediaBrowser.Providers.MediaInfo.FFProbeVideoInfo.ProbeVideo[T](T item, MetadataRefreshOptions options, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs:line 122
at MediaBrowser.Providers.Manager.MetadataService`2.RunCustomProvider(ICustomMetadataProvider`1 provider, TItemType item, String logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/Manager/MetadataService.cs:line 815
```
2019-12-22 21:39:26 +01:00
Codec = streamInfo . CodecName ,
Profile = streamInfo . Profile ,
Level = streamInfo . Level ,
Index = streamInfo . Index ,
PixelFormat = streamInfo . PixelFormat ,
NalLengthSize = streamInfo . NalLengthSize ,
TimeBase = streamInfo . TimeBase ,
2023-02-01 14:58:04 +01:00
CodecTimeBase = streamInfo . CodecTimeBase ,
IsAVC = streamInfo . IsAvc
2018-12-14 10:40:55 +01:00
} ;
// Filter out junk
2021-03-09 03:04:47 +01:00
if ( ! string . IsNullOrWhiteSpace ( streamInfo . CodecTagString ) & & ! streamInfo . CodecTagString . Contains ( "[0]" , StringComparison . OrdinalIgnoreCase ) )
2018-12-14 10:40:55 +01:00
{
Fix exceptions while scanning
Fixes these exceptions:
```
[2019-12-22 20:48:14.779 +01:00] [ERR] Error in WaitForExit
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.GetWaitState()
at System.Diagnostics.Process.WaitForExitCore(Int32 milliseconds)
at System.Diagnostics.Process.WaitForExit(Int32 milliseconds)
at Emby.Server.Implementations.Diagnostics.CommonProcess.WaitForExit(Int32 timeMs) in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 100
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 785
[2019-12-22 20:48:14.790 +01:00] [INF] Killing ffmpeg process
[2019-12-22 20:48:14.795 +01:00] [ERR] Error killing process
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.Kill()
at Emby.Server.Implementations.Diagnostics.CommonProcess.Kill() in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 95
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 799
[2019-12-22 20:48:14.808 +01:00] [ERR] Error in "ffprobe"
System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $.streams[0].start_pts | LineNumber: 32 | BytePositionInLine: 26.
---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
at System.Text.Json.Utf8JsonReader.GetString()
at System.Text.Json.Serialization.Converters.JsonConverterString.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.JsonPropertyInfoNotNullable`4.OnRead(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonPropertyInfo.Read(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonSerializer.HandleValue(JsonTokenType tokenType, JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& readStack, Utf8JsonReader& reader, Exception ex)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadCore(JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken)
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.GetMediaInfoInternal(String inputPath, String primaryPath, MediaProtocol protocol, Boolean extractChapters, String probeSizeArgument, Boolean isAudio, Nullable`1 videoType, Boolean forceEnableLogging, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 399
at MediaBrowser.Providers.MediaInfo.FFProbeVideoInfo.ProbeVideo[T](T item, MetadataRefreshOptions options, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs:line 122
at MediaBrowser.Providers.Manager.MetadataService`2.RunCustomProvider(ICustomMetadataProvider`1 provider, TItemType item, String logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/Manager/MetadataService.cs:line 815
```
2019-12-22 21:39:26 +01:00
stream . CodecTag = streamInfo . CodecTagString ;
2018-12-14 10:40:55 +01:00
}
2022-12-05 15:01:13 +01:00
if ( streamInfo . Tags is not null )
2018-12-14 10:40:55 +01:00
{
Fix exceptions while scanning
Fixes these exceptions:
```
[2019-12-22 20:48:14.779 +01:00] [ERR] Error in WaitForExit
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.GetWaitState()
at System.Diagnostics.Process.WaitForExitCore(Int32 milliseconds)
at System.Diagnostics.Process.WaitForExit(Int32 milliseconds)
at Emby.Server.Implementations.Diagnostics.CommonProcess.WaitForExit(Int32 timeMs) in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 100
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 785
[2019-12-22 20:48:14.790 +01:00] [INF] Killing ffmpeg process
[2019-12-22 20:48:14.795 +01:00] [ERR] Error killing process
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.Kill()
at Emby.Server.Implementations.Diagnostics.CommonProcess.Kill() in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 95
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 799
[2019-12-22 20:48:14.808 +01:00] [ERR] Error in "ffprobe"
System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $.streams[0].start_pts | LineNumber: 32 | BytePositionInLine: 26.
---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
at System.Text.Json.Utf8JsonReader.GetString()
at System.Text.Json.Serialization.Converters.JsonConverterString.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.JsonPropertyInfoNotNullable`4.OnRead(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonPropertyInfo.Read(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonSerializer.HandleValue(JsonTokenType tokenType, JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& readStack, Utf8JsonReader& reader, Exception ex)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadCore(JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken)
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.GetMediaInfoInternal(String inputPath, String primaryPath, MediaProtocol protocol, Boolean extractChapters, String probeSizeArgument, Boolean isAudio, Nullable`1 videoType, Boolean forceEnableLogging, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 399
at MediaBrowser.Providers.MediaInfo.FFProbeVideoInfo.ProbeVideo[T](T item, MetadataRefreshOptions options, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs:line 122
at MediaBrowser.Providers.Manager.MetadataService`2.RunCustomProvider(ICustomMetadataProvider`1 provider, TItemType item, String logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/Manager/MetadataService.cs:line 815
```
2019-12-22 21:39:26 +01:00
stream . Language = GetDictionaryValue ( streamInfo . Tags , "language" ) ;
stream . Comment = GetDictionaryValue ( streamInfo . Tags , "comment" ) ;
stream . Title = GetDictionaryValue ( streamInfo . Tags , "title" ) ;
2018-12-14 10:40:55 +01:00
}
2023-02-01 14:58:04 +01:00
if ( streamInfo . CodecType = = CodecType . Audio )
2018-12-14 10:40:55 +01:00
{
stream . Type = MediaStreamType . Audio ;
2024-07-21 00:58:05 -04:00
stream . LocalizedDefault = _localization . GetLocalizedString ( "Default" ) ;
stream . LocalizedExternal = _localization . GetLocalizedString ( "External" ) ;
2018-12-14 10:40:55 +01:00
Fix exceptions while scanning
Fixes these exceptions:
```
[2019-12-22 20:48:14.779 +01:00] [ERR] Error in WaitForExit
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.GetWaitState()
at System.Diagnostics.Process.WaitForExitCore(Int32 milliseconds)
at System.Diagnostics.Process.WaitForExit(Int32 milliseconds)
at Emby.Server.Implementations.Diagnostics.CommonProcess.WaitForExit(Int32 timeMs) in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 100
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 785
[2019-12-22 20:48:14.790 +01:00] [INF] Killing ffmpeg process
[2019-12-22 20:48:14.795 +01:00] [ERR] Error killing process
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.Kill()
at Emby.Server.Implementations.Diagnostics.CommonProcess.Kill() in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 95
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 799
[2019-12-22 20:48:14.808 +01:00] [ERR] Error in "ffprobe"
System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $.streams[0].start_pts | LineNumber: 32 | BytePositionInLine: 26.
---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
at System.Text.Json.Utf8JsonReader.GetString()
at System.Text.Json.Serialization.Converters.JsonConverterString.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.JsonPropertyInfoNotNullable`4.OnRead(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonPropertyInfo.Read(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonSerializer.HandleValue(JsonTokenType tokenType, JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& readStack, Utf8JsonReader& reader, Exception ex)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadCore(JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken)
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.GetMediaInfoInternal(String inputPath, String primaryPath, MediaProtocol protocol, Boolean extractChapters, String probeSizeArgument, Boolean isAudio, Nullable`1 videoType, Boolean forceEnableLogging, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 399
at MediaBrowser.Providers.MediaInfo.FFProbeVideoInfo.ProbeVideo[T](T item, MetadataRefreshOptions options, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs:line 122
at MediaBrowser.Providers.Manager.MetadataService`2.RunCustomProvider(ICustomMetadataProvider`1 provider, TItemType item, String logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/Manager/MetadataService.cs:line 815
```
2019-12-22 21:39:26 +01:00
stream . Channels = streamInfo . Channels ;
2018-12-14 10:40:55 +01:00
2023-02-19 16:52:29 +01:00
if ( int . TryParse ( streamInfo . SampleRate , CultureInfo . InvariantCulture , out var sampleRate ) )
2018-12-14 10:40:55 +01:00
{
2023-02-19 16:52:29 +01:00
stream . SampleRate = sampleRate ;
2018-12-14 10:40:55 +01:00
}
Fix exceptions while scanning
Fixes these exceptions:
```
[2019-12-22 20:48:14.779 +01:00] [ERR] Error in WaitForExit
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.GetWaitState()
at System.Diagnostics.Process.WaitForExitCore(Int32 milliseconds)
at System.Diagnostics.Process.WaitForExit(Int32 milliseconds)
at Emby.Server.Implementations.Diagnostics.CommonProcess.WaitForExit(Int32 timeMs) in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 100
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 785
[2019-12-22 20:48:14.790 +01:00] [INF] Killing ffmpeg process
[2019-12-22 20:48:14.795 +01:00] [ERR] Error killing process
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.Kill()
at Emby.Server.Implementations.Diagnostics.CommonProcess.Kill() in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 95
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 799
[2019-12-22 20:48:14.808 +01:00] [ERR] Error in "ffprobe"
System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $.streams[0].start_pts | LineNumber: 32 | BytePositionInLine: 26.
---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
at System.Text.Json.Utf8JsonReader.GetString()
at System.Text.Json.Serialization.Converters.JsonConverterString.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.JsonPropertyInfoNotNullable`4.OnRead(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonPropertyInfo.Read(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonSerializer.HandleValue(JsonTokenType tokenType, JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& readStack, Utf8JsonReader& reader, Exception ex)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadCore(JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken)
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.GetMediaInfoInternal(String inputPath, String primaryPath, MediaProtocol protocol, Boolean extractChapters, String probeSizeArgument, Boolean isAudio, Nullable`1 videoType, Boolean forceEnableLogging, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 399
at MediaBrowser.Providers.MediaInfo.FFProbeVideoInfo.ProbeVideo[T](T item, MetadataRefreshOptions options, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs:line 122
at MediaBrowser.Providers.Manager.MetadataService`2.RunCustomProvider(ICustomMetadataProvider`1 provider, TItemType item, String logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/Manager/MetadataService.cs:line 815
```
2019-12-22 21:39:26 +01:00
stream . ChannelLayout = ParseChannelLayout ( streamInfo . ChannelLayout ) ;
2018-12-14 10:40:55 +01:00
Fix exceptions while scanning
Fixes these exceptions:
```
[2019-12-22 20:48:14.779 +01:00] [ERR] Error in WaitForExit
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.GetWaitState()
at System.Diagnostics.Process.WaitForExitCore(Int32 milliseconds)
at System.Diagnostics.Process.WaitForExit(Int32 milliseconds)
at Emby.Server.Implementations.Diagnostics.CommonProcess.WaitForExit(Int32 timeMs) in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 100
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 785
[2019-12-22 20:48:14.790 +01:00] [INF] Killing ffmpeg process
[2019-12-22 20:48:14.795 +01:00] [ERR] Error killing process
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.Kill()
at Emby.Server.Implementations.Diagnostics.CommonProcess.Kill() in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 95
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 799
[2019-12-22 20:48:14.808 +01:00] [ERR] Error in "ffprobe"
System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $.streams[0].start_pts | LineNumber: 32 | BytePositionInLine: 26.
---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
at System.Text.Json.Utf8JsonReader.GetString()
at System.Text.Json.Serialization.Converters.JsonConverterString.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.JsonPropertyInfoNotNullable`4.OnRead(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonPropertyInfo.Read(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonSerializer.HandleValue(JsonTokenType tokenType, JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& readStack, Utf8JsonReader& reader, Exception ex)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadCore(JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken)
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.GetMediaInfoInternal(String inputPath, String primaryPath, MediaProtocol protocol, Boolean extractChapters, String probeSizeArgument, Boolean isAudio, Nullable`1 videoType, Boolean forceEnableLogging, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 399
at MediaBrowser.Providers.MediaInfo.FFProbeVideoInfo.ProbeVideo[T](T item, MetadataRefreshOptions options, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs:line 122
at MediaBrowser.Providers.Manager.MetadataService`2.RunCustomProvider(ICustomMetadataProvider`1 provider, TItemType item, String logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/Manager/MetadataService.cs:line 815
```
2019-12-22 21:39:26 +01:00
if ( streamInfo . BitsPerSample > 0 )
2018-12-14 10:40:55 +01:00
{
Fix exceptions while scanning
Fixes these exceptions:
```
[2019-12-22 20:48:14.779 +01:00] [ERR] Error in WaitForExit
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.GetWaitState()
at System.Diagnostics.Process.WaitForExitCore(Int32 milliseconds)
at System.Diagnostics.Process.WaitForExit(Int32 milliseconds)
at Emby.Server.Implementations.Diagnostics.CommonProcess.WaitForExit(Int32 timeMs) in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 100
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 785
[2019-12-22 20:48:14.790 +01:00] [INF] Killing ffmpeg process
[2019-12-22 20:48:14.795 +01:00] [ERR] Error killing process
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.Kill()
at Emby.Server.Implementations.Diagnostics.CommonProcess.Kill() in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 95
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 799
[2019-12-22 20:48:14.808 +01:00] [ERR] Error in "ffprobe"
System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $.streams[0].start_pts | LineNumber: 32 | BytePositionInLine: 26.
---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
at System.Text.Json.Utf8JsonReader.GetString()
at System.Text.Json.Serialization.Converters.JsonConverterString.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.JsonPropertyInfoNotNullable`4.OnRead(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonPropertyInfo.Read(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonSerializer.HandleValue(JsonTokenType tokenType, JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& readStack, Utf8JsonReader& reader, Exception ex)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadCore(JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken)
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.GetMediaInfoInternal(String inputPath, String primaryPath, MediaProtocol protocol, Boolean extractChapters, String probeSizeArgument, Boolean isAudio, Nullable`1 videoType, Boolean forceEnableLogging, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 399
at MediaBrowser.Providers.MediaInfo.FFProbeVideoInfo.ProbeVideo[T](T item, MetadataRefreshOptions options, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs:line 122
at MediaBrowser.Providers.Manager.MetadataService`2.RunCustomProvider(ICustomMetadataProvider`1 provider, TItemType item, String logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/Manager/MetadataService.cs:line 815
```
2019-12-22 21:39:26 +01:00
stream . BitDepth = streamInfo . BitsPerSample ;
2018-12-14 10:40:55 +01:00
}
Fix exceptions while scanning
Fixes these exceptions:
```
[2019-12-22 20:48:14.779 +01:00] [ERR] Error in WaitForExit
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.GetWaitState()
at System.Diagnostics.Process.WaitForExitCore(Int32 milliseconds)
at System.Diagnostics.Process.WaitForExit(Int32 milliseconds)
at Emby.Server.Implementations.Diagnostics.CommonProcess.WaitForExit(Int32 timeMs) in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 100
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 785
[2019-12-22 20:48:14.790 +01:00] [INF] Killing ffmpeg process
[2019-12-22 20:48:14.795 +01:00] [ERR] Error killing process
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.Kill()
at Emby.Server.Implementations.Diagnostics.CommonProcess.Kill() in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 95
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 799
[2019-12-22 20:48:14.808 +01:00] [ERR] Error in "ffprobe"
System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $.streams[0].start_pts | LineNumber: 32 | BytePositionInLine: 26.
---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
at System.Text.Json.Utf8JsonReader.GetString()
at System.Text.Json.Serialization.Converters.JsonConverterString.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.JsonPropertyInfoNotNullable`4.OnRead(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonPropertyInfo.Read(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonSerializer.HandleValue(JsonTokenType tokenType, JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& readStack, Utf8JsonReader& reader, Exception ex)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadCore(JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken)
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.GetMediaInfoInternal(String inputPath, String primaryPath, MediaProtocol protocol, Boolean extractChapters, String probeSizeArgument, Boolean isAudio, Nullable`1 videoType, Boolean forceEnableLogging, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 399
at MediaBrowser.Providers.MediaInfo.FFProbeVideoInfo.ProbeVideo[T](T item, MetadataRefreshOptions options, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs:line 122
at MediaBrowser.Providers.Manager.MetadataService`2.RunCustomProvider(ICustomMetadataProvider`1 provider, TItemType item, String logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/Manager/MetadataService.cs:line 815
```
2019-12-22 21:39:26 +01:00
else if ( streamInfo . BitsPerRawSample > 0 )
2018-12-14 10:40:55 +01:00
{
Fix exceptions while scanning
Fixes these exceptions:
```
[2019-12-22 20:48:14.779 +01:00] [ERR] Error in WaitForExit
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.GetWaitState()
at System.Diagnostics.Process.WaitForExitCore(Int32 milliseconds)
at System.Diagnostics.Process.WaitForExit(Int32 milliseconds)
at Emby.Server.Implementations.Diagnostics.CommonProcess.WaitForExit(Int32 timeMs) in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 100
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 785
[2019-12-22 20:48:14.790 +01:00] [INF] Killing ffmpeg process
[2019-12-22 20:48:14.795 +01:00] [ERR] Error killing process
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.Kill()
at Emby.Server.Implementations.Diagnostics.CommonProcess.Kill() in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 95
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 799
[2019-12-22 20:48:14.808 +01:00] [ERR] Error in "ffprobe"
System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $.streams[0].start_pts | LineNumber: 32 | BytePositionInLine: 26.
---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
at System.Text.Json.Utf8JsonReader.GetString()
at System.Text.Json.Serialization.Converters.JsonConverterString.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.JsonPropertyInfoNotNullable`4.OnRead(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonPropertyInfo.Read(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonSerializer.HandleValue(JsonTokenType tokenType, JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& readStack, Utf8JsonReader& reader, Exception ex)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadCore(JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken)
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.GetMediaInfoInternal(String inputPath, String primaryPath, MediaProtocol protocol, Boolean extractChapters, String probeSizeArgument, Boolean isAudio, Nullable`1 videoType, Boolean forceEnableLogging, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 399
at MediaBrowser.Providers.MediaInfo.FFProbeVideoInfo.ProbeVideo[T](T item, MetadataRefreshOptions options, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs:line 122
at MediaBrowser.Providers.Manager.MetadataService`2.RunCustomProvider(ICustomMetadataProvider`1 provider, TItemType item, String logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/Manager/MetadataService.cs:line 815
```
2019-12-22 21:39:26 +01:00
stream . BitDepth = streamInfo . BitsPerRawSample ;
2018-12-14 10:40:55 +01:00
}
2021-09-30 22:24:46 +02:00
if ( string . IsNullOrEmpty ( stream . Title ) )
{
2022-02-28 17:44:23 +01:00
// mp4 missing track title workaround: fall back to handler_name if populated and not the default "SoundHandler"
2021-09-30 22:24:46 +02:00
string handlerName = GetDictionaryValue ( streamInfo . Tags , "handler_name" ) ;
2022-02-28 17:44:23 +01:00
if ( ! string . IsNullOrEmpty ( handlerName ) & & ! string . Equals ( handlerName , "SoundHandler" , StringComparison . OrdinalIgnoreCase ) )
2021-09-30 22:24:46 +02:00
{
stream . Title = handlerName ;
}
}
2018-12-14 10:40:55 +01:00
}
2023-02-01 14:58:04 +01:00
else if ( streamInfo . CodecType = = CodecType . Subtitle )
2018-12-14 10:40:55 +01:00
{
stream . Type = MediaStreamType . Subtitle ;
stream . Codec = NormalizeSubtitleCodec ( stream . Codec ) ;
2021-02-20 23:13:04 +01:00
stream . LocalizedUndefined = _localization . GetLocalizedString ( "Undefined" ) ;
stream . LocalizedDefault = _localization . GetLocalizedString ( "Default" ) ;
stream . LocalizedForced = _localization . GetLocalizedString ( "Forced" ) ;
2022-03-10 22:20:35 +01:00
stream . LocalizedExternal = _localization . GetLocalizedString ( "External" ) ;
2022-10-07 07:48:31 -04:00
stream . LocalizedHearingImpaired = _localization . GetLocalizedString ( "HearingImpaired" ) ;
2021-09-30 22:24:46 +02:00
2024-01-28 19:40:49 +08:00
// Graphical subtitle may have width and height info
stream . Width = streamInfo . Width ;
stream . Height = streamInfo . Height ;
2021-09-30 22:24:46 +02:00
if ( string . IsNullOrEmpty ( stream . Title ) )
{
// mp4 missing track title workaround: fall back to handler_name if populated and not the default "SubtitleHandler"
string handlerName = GetDictionaryValue ( streamInfo . Tags , "handler_name" ) ;
if ( ! string . IsNullOrEmpty ( handlerName ) & & ! string . Equals ( handlerName , "SubtitleHandler" , StringComparison . OrdinalIgnoreCase ) )
{
stream . Title = handlerName ;
}
}
2018-12-14 10:40:55 +01:00
}
2023-02-01 14:58:04 +01:00
else if ( streamInfo . CodecType = = CodecType . Video )
2018-12-14 10:40:55 +01:00
{
Fix exceptions while scanning
Fixes these exceptions:
```
[2019-12-22 20:48:14.779 +01:00] [ERR] Error in WaitForExit
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.GetWaitState()
at System.Diagnostics.Process.WaitForExitCore(Int32 milliseconds)
at System.Diagnostics.Process.WaitForExit(Int32 milliseconds)
at Emby.Server.Implementations.Diagnostics.CommonProcess.WaitForExit(Int32 timeMs) in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 100
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 785
[2019-12-22 20:48:14.790 +01:00] [INF] Killing ffmpeg process
[2019-12-22 20:48:14.795 +01:00] [ERR] Error killing process
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.Kill()
at Emby.Server.Implementations.Diagnostics.CommonProcess.Kill() in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 95
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 799
[2019-12-22 20:48:14.808 +01:00] [ERR] Error in "ffprobe"
System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $.streams[0].start_pts | LineNumber: 32 | BytePositionInLine: 26.
---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
at System.Text.Json.Utf8JsonReader.GetString()
at System.Text.Json.Serialization.Converters.JsonConverterString.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.JsonPropertyInfoNotNullable`4.OnRead(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonPropertyInfo.Read(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonSerializer.HandleValue(JsonTokenType tokenType, JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& readStack, Utf8JsonReader& reader, Exception ex)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadCore(JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken)
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.GetMediaInfoInternal(String inputPath, String primaryPath, MediaProtocol protocol, Boolean extractChapters, String probeSizeArgument, Boolean isAudio, Nullable`1 videoType, Boolean forceEnableLogging, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 399
at MediaBrowser.Providers.MediaInfo.FFProbeVideoInfo.ProbeVideo[T](T item, MetadataRefreshOptions options, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs:line 122
at MediaBrowser.Providers.Manager.MetadataService`2.RunCustomProvider(ICustomMetadataProvider`1 provider, TItemType item, String logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/Manager/MetadataService.cs:line 815
```
2019-12-22 21:39:26 +01:00
stream . AverageFrameRate = GetFrameRate ( streamInfo . AverageFrameRate ) ;
stream . RealFrameRate = GetFrameRate ( streamInfo . RFrameRate ) ;
2018-12-14 10:40:55 +01:00
2023-01-19 14:19:56 +01:00
stream . IsInterlaced = ! string . IsNullOrWhiteSpace ( streamInfo . FieldOrder )
2022-03-11 08:55:30 +13:00
& & ! string . Equals ( streamInfo . FieldOrder , "progressive" , StringComparison . OrdinalIgnoreCase ) ;
2021-11-12 16:30:30 +01:00
if ( isAudio
2024-06-23 11:40:44 -04:00
| | string . Equals ( stream . Codec , "bmp" , StringComparison . OrdinalIgnoreCase )
| | string . Equals ( stream . Codec , "gif" , StringComparison . OrdinalIgnoreCase )
| | string . Equals ( stream . Codec , "png" , StringComparison . OrdinalIgnoreCase )
| | string . Equals ( stream . Codec , "webp" , StringComparison . OrdinalIgnoreCase ) )
2018-12-14 10:40:55 +01:00
{
stream . Type = MediaStreamType . EmbeddedImage ;
}
else if ( string . Equals ( stream . Codec , "mjpeg" , StringComparison . OrdinalIgnoreCase ) )
{
// How to differentiate between video and embedded image?
2021-10-07 22:37:59 +02:00
// The only difference I've seen thus far is presence of codec tag, also embedded images have high (unusual) framerates
if ( ! string . IsNullOrWhiteSpace ( stream . CodecTag ) )
2018-12-14 10:40:55 +01:00
{
2021-10-07 22:37:59 +02:00
stream . Type = MediaStreamType . Video ;
2018-12-14 10:40:55 +01:00
}
else
{
2021-10-07 22:37:59 +02:00
stream . Type = MediaStreamType . EmbeddedImage ;
2018-12-14 10:40:55 +01:00
}
}
else
{
stream . Type = MediaStreamType . Video ;
}
Fix exceptions while scanning
Fixes these exceptions:
```
[2019-12-22 20:48:14.779 +01:00] [ERR] Error in WaitForExit
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.GetWaitState()
at System.Diagnostics.Process.WaitForExitCore(Int32 milliseconds)
at System.Diagnostics.Process.WaitForExit(Int32 milliseconds)
at Emby.Server.Implementations.Diagnostics.CommonProcess.WaitForExit(Int32 timeMs) in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 100
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 785
[2019-12-22 20:48:14.790 +01:00] [INF] Killing ffmpeg process
[2019-12-22 20:48:14.795 +01:00] [ERR] Error killing process
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.Kill()
at Emby.Server.Implementations.Diagnostics.CommonProcess.Kill() in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 95
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 799
[2019-12-22 20:48:14.808 +01:00] [ERR] Error in "ffprobe"
System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $.streams[0].start_pts | LineNumber: 32 | BytePositionInLine: 26.
---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
at System.Text.Json.Utf8JsonReader.GetString()
at System.Text.Json.Serialization.Converters.JsonConverterString.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.JsonPropertyInfoNotNullable`4.OnRead(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonPropertyInfo.Read(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonSerializer.HandleValue(JsonTokenType tokenType, JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& readStack, Utf8JsonReader& reader, Exception ex)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadCore(JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken)
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.GetMediaInfoInternal(String inputPath, String primaryPath, MediaProtocol protocol, Boolean extractChapters, String probeSizeArgument, Boolean isAudio, Nullable`1 videoType, Boolean forceEnableLogging, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 399
at MediaBrowser.Providers.MediaInfo.FFProbeVideoInfo.ProbeVideo[T](T item, MetadataRefreshOptions options, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs:line 122
at MediaBrowser.Providers.Manager.MetadataService`2.RunCustomProvider(ICustomMetadataProvider`1 provider, TItemType item, String logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/Manager/MetadataService.cs:line 815
```
2019-12-22 21:39:26 +01:00
stream . Width = streamInfo . Width ;
stream . Height = streamInfo . Height ;
2018-12-14 10:40:55 +01:00
stream . AspectRatio = GetAspectRatio ( streamInfo ) ;
Fix exceptions while scanning
Fixes these exceptions:
```
[2019-12-22 20:48:14.779 +01:00] [ERR] Error in WaitForExit
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.GetWaitState()
at System.Diagnostics.Process.WaitForExitCore(Int32 milliseconds)
at System.Diagnostics.Process.WaitForExit(Int32 milliseconds)
at Emby.Server.Implementations.Diagnostics.CommonProcess.WaitForExit(Int32 timeMs) in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 100
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 785
[2019-12-22 20:48:14.790 +01:00] [INF] Killing ffmpeg process
[2019-12-22 20:48:14.795 +01:00] [ERR] Error killing process
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.Kill()
at Emby.Server.Implementations.Diagnostics.CommonProcess.Kill() in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 95
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 799
[2019-12-22 20:48:14.808 +01:00] [ERR] Error in "ffprobe"
System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $.streams[0].start_pts | LineNumber: 32 | BytePositionInLine: 26.
---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
at System.Text.Json.Utf8JsonReader.GetString()
at System.Text.Json.Serialization.Converters.JsonConverterString.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.JsonPropertyInfoNotNullable`4.OnRead(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonPropertyInfo.Read(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonSerializer.HandleValue(JsonTokenType tokenType, JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& readStack, Utf8JsonReader& reader, Exception ex)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadCore(JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken)
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.GetMediaInfoInternal(String inputPath, String primaryPath, MediaProtocol protocol, Boolean extractChapters, String probeSizeArgument, Boolean isAudio, Nullable`1 videoType, Boolean forceEnableLogging, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 399
at MediaBrowser.Providers.MediaInfo.FFProbeVideoInfo.ProbeVideo[T](T item, MetadataRefreshOptions options, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs:line 122
at MediaBrowser.Providers.Manager.MetadataService`2.RunCustomProvider(ICustomMetadataProvider`1 provider, TItemType item, String logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/Manager/MetadataService.cs:line 815
```
2019-12-22 21:39:26 +01:00
if ( streamInfo . BitsPerSample > 0 )
2018-12-14 10:40:55 +01:00
{
Fix exceptions while scanning
Fixes these exceptions:
```
[2019-12-22 20:48:14.779 +01:00] [ERR] Error in WaitForExit
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.GetWaitState()
at System.Diagnostics.Process.WaitForExitCore(Int32 milliseconds)
at System.Diagnostics.Process.WaitForExit(Int32 milliseconds)
at Emby.Server.Implementations.Diagnostics.CommonProcess.WaitForExit(Int32 timeMs) in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 100
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 785
[2019-12-22 20:48:14.790 +01:00] [INF] Killing ffmpeg process
[2019-12-22 20:48:14.795 +01:00] [ERR] Error killing process
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.Kill()
at Emby.Server.Implementations.Diagnostics.CommonProcess.Kill() in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 95
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 799
[2019-12-22 20:48:14.808 +01:00] [ERR] Error in "ffprobe"
System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $.streams[0].start_pts | LineNumber: 32 | BytePositionInLine: 26.
---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
at System.Text.Json.Utf8JsonReader.GetString()
at System.Text.Json.Serialization.Converters.JsonConverterString.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.JsonPropertyInfoNotNullable`4.OnRead(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonPropertyInfo.Read(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonSerializer.HandleValue(JsonTokenType tokenType, JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& readStack, Utf8JsonReader& reader, Exception ex)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadCore(JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken)
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.GetMediaInfoInternal(String inputPath, String primaryPath, MediaProtocol protocol, Boolean extractChapters, String probeSizeArgument, Boolean isAudio, Nullable`1 videoType, Boolean forceEnableLogging, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 399
at MediaBrowser.Providers.MediaInfo.FFProbeVideoInfo.ProbeVideo[T](T item, MetadataRefreshOptions options, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs:line 122
at MediaBrowser.Providers.Manager.MetadataService`2.RunCustomProvider(ICustomMetadataProvider`1 provider, TItemType item, String logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/Manager/MetadataService.cs:line 815
```
2019-12-22 21:39:26 +01:00
stream . BitDepth = streamInfo . BitsPerSample ;
2018-12-14 10:40:55 +01:00
}
Fix exceptions while scanning
Fixes these exceptions:
```
[2019-12-22 20:48:14.779 +01:00] [ERR] Error in WaitForExit
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.GetWaitState()
at System.Diagnostics.Process.WaitForExitCore(Int32 milliseconds)
at System.Diagnostics.Process.WaitForExit(Int32 milliseconds)
at Emby.Server.Implementations.Diagnostics.CommonProcess.WaitForExit(Int32 timeMs) in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 100
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 785
[2019-12-22 20:48:14.790 +01:00] [INF] Killing ffmpeg process
[2019-12-22 20:48:14.795 +01:00] [ERR] Error killing process
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.Kill()
at Emby.Server.Implementations.Diagnostics.CommonProcess.Kill() in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 95
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 799
[2019-12-22 20:48:14.808 +01:00] [ERR] Error in "ffprobe"
System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $.streams[0].start_pts | LineNumber: 32 | BytePositionInLine: 26.
---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
at System.Text.Json.Utf8JsonReader.GetString()
at System.Text.Json.Serialization.Converters.JsonConverterString.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.JsonPropertyInfoNotNullable`4.OnRead(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonPropertyInfo.Read(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonSerializer.HandleValue(JsonTokenType tokenType, JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& readStack, Utf8JsonReader& reader, Exception ex)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadCore(JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken)
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.GetMediaInfoInternal(String inputPath, String primaryPath, MediaProtocol protocol, Boolean extractChapters, String probeSizeArgument, Boolean isAudio, Nullable`1 videoType, Boolean forceEnableLogging, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 399
at MediaBrowser.Providers.MediaInfo.FFProbeVideoInfo.ProbeVideo[T](T item, MetadataRefreshOptions options, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs:line 122
at MediaBrowser.Providers.Manager.MetadataService`2.RunCustomProvider(ICustomMetadataProvider`1 provider, TItemType item, String logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/Manager/MetadataService.cs:line 815
```
2019-12-22 21:39:26 +01:00
else if ( streamInfo . BitsPerRawSample > 0 )
2018-12-14 10:40:55 +01:00
{
Fix exceptions while scanning
Fixes these exceptions:
```
[2019-12-22 20:48:14.779 +01:00] [ERR] Error in WaitForExit
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.GetWaitState()
at System.Diagnostics.Process.WaitForExitCore(Int32 milliseconds)
at System.Diagnostics.Process.WaitForExit(Int32 milliseconds)
at Emby.Server.Implementations.Diagnostics.CommonProcess.WaitForExit(Int32 timeMs) in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 100
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 785
[2019-12-22 20:48:14.790 +01:00] [INF] Killing ffmpeg process
[2019-12-22 20:48:14.795 +01:00] [ERR] Error killing process
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.Kill()
at Emby.Server.Implementations.Diagnostics.CommonProcess.Kill() in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 95
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 799
[2019-12-22 20:48:14.808 +01:00] [ERR] Error in "ffprobe"
System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $.streams[0].start_pts | LineNumber: 32 | BytePositionInLine: 26.
---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
at System.Text.Json.Utf8JsonReader.GetString()
at System.Text.Json.Serialization.Converters.JsonConverterString.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.JsonPropertyInfoNotNullable`4.OnRead(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonPropertyInfo.Read(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonSerializer.HandleValue(JsonTokenType tokenType, JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& readStack, Utf8JsonReader& reader, Exception ex)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadCore(JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken)
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.GetMediaInfoInternal(String inputPath, String primaryPath, MediaProtocol protocol, Boolean extractChapters, String probeSizeArgument, Boolean isAudio, Nullable`1 videoType, Boolean forceEnableLogging, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 399
at MediaBrowser.Providers.MediaInfo.FFProbeVideoInfo.ProbeVideo[T](T item, MetadataRefreshOptions options, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs:line 122
at MediaBrowser.Providers.Manager.MetadataService`2.RunCustomProvider(ICustomMetadataProvider`1 provider, TItemType item, String logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/Manager/MetadataService.cs:line 815
```
2019-12-22 21:39:26 +01:00
stream . BitDepth = streamInfo . BitsPerRawSample ;
2018-12-14 10:40:55 +01:00
}
2021-07-25 00:52:16 +08:00
if ( ! stream . BitDepth . HasValue )
{
2021-12-02 00:49:50 +08:00
if ( ! string . IsNullOrEmpty ( streamInfo . PixelFormat ) )
2021-07-25 00:52:16 +08:00
{
2021-12-02 00:49:50 +08:00
if ( string . Equals ( streamInfo . PixelFormat , "yuv420p" , StringComparison . OrdinalIgnoreCase )
| | string . Equals ( streamInfo . PixelFormat , "yuv444p" , StringComparison . OrdinalIgnoreCase ) )
{
stream . BitDepth = 8 ;
}
else if ( string . Equals ( streamInfo . PixelFormat , "yuv420p10le" , StringComparison . OrdinalIgnoreCase )
2021-12-24 16:50:40 +08:00
| | string . Equals ( streamInfo . PixelFormat , "yuv444p10le" , StringComparison . OrdinalIgnoreCase ) )
2021-12-02 00:49:50 +08:00
{
stream . BitDepth = 10 ;
}
else if ( string . Equals ( streamInfo . PixelFormat , "yuv420p12le" , StringComparison . OrdinalIgnoreCase )
2021-12-24 16:50:40 +08:00
| | string . Equals ( streamInfo . PixelFormat , "yuv444p12le" , StringComparison . OrdinalIgnoreCase ) )
2021-12-02 00:49:50 +08:00
{
stream . BitDepth = 12 ;
}
2021-07-25 00:52:16 +08:00
}
}
2018-12-14 10:40:55 +01:00
// http://stackoverflow.com/questions/17353387/how-to-detect-anamorphic-video-with-ffprobe
2025-08-27 18:34:00 -05:00
if ( string . Equals ( streamInfo . SampleAspectRatio , "1:1" , StringComparison . Ordinal ) )
2025-08-15 20:52:43 -04:00
{
stream . IsAnamorphic = false ;
}
2025-08-27 18:34:00 -05:00
else if ( ! string . Equals ( streamInfo . SampleAspectRatio , "0:1" , StringComparison . Ordinal ) )
2025-08-15 20:52:43 -04:00
{
stream . IsAnamorphic = true ;
}
2025-08-27 18:34:00 -05:00
else if ( string . Equals ( streamInfo . DisplayAspectRatio , "0:1" , StringComparison . Ordinal ) )
2025-08-15 20:52:43 -04:00
{
stream . IsAnamorphic = false ;
}
else if ( ! string . Equals (
streamInfo . DisplayAspectRatio ,
// Force GetAspectRatio() to derive ratio from Width/Height directly by using null DAR
GetAspectRatio ( new MediaStreamInfo
{
Width = streamInfo . Width ,
Height = streamInfo . Height ,
DisplayAspectRatio = null
} ) ,
2025-08-27 18:34:00 -05:00
StringComparison . Ordinal ) )
2025-08-15 20:52:43 -04:00
{
stream . IsAnamorphic = true ;
}
else
{
stream . IsAnamorphic = false ;
}
2018-12-14 10:40:55 +01:00
Fix exceptions while scanning
Fixes these exceptions:
```
[2019-12-22 20:48:14.779 +01:00] [ERR] Error in WaitForExit
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.GetWaitState()
at System.Diagnostics.Process.WaitForExitCore(Int32 milliseconds)
at System.Diagnostics.Process.WaitForExit(Int32 milliseconds)
at Emby.Server.Implementations.Diagnostics.CommonProcess.WaitForExit(Int32 timeMs) in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 100
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 785
[2019-12-22 20:48:14.790 +01:00] [INF] Killing ffmpeg process
[2019-12-22 20:48:14.795 +01:00] [ERR] Error killing process
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.Kill()
at Emby.Server.Implementations.Diagnostics.CommonProcess.Kill() in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 95
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 799
[2019-12-22 20:48:14.808 +01:00] [ERR] Error in "ffprobe"
System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $.streams[0].start_pts | LineNumber: 32 | BytePositionInLine: 26.
---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
at System.Text.Json.Utf8JsonReader.GetString()
at System.Text.Json.Serialization.Converters.JsonConverterString.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.JsonPropertyInfoNotNullable`4.OnRead(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonPropertyInfo.Read(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonSerializer.HandleValue(JsonTokenType tokenType, JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& readStack, Utf8JsonReader& reader, Exception ex)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadCore(JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken)
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.GetMediaInfoInternal(String inputPath, String primaryPath, MediaProtocol protocol, Boolean extractChapters, String probeSizeArgument, Boolean isAudio, Nullable`1 videoType, Boolean forceEnableLogging, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 399
at MediaBrowser.Providers.MediaInfo.FFProbeVideoInfo.ProbeVideo[T](T item, MetadataRefreshOptions options, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs:line 122
at MediaBrowser.Providers.Manager.MetadataService`2.RunCustomProvider(ICustomMetadataProvider`1 provider, TItemType item, String logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/Manager/MetadataService.cs:line 815
```
2019-12-22 21:39:26 +01:00
if ( streamInfo . Refs > 0 )
2018-12-14 10:40:55 +01:00
{
Fix exceptions while scanning
Fixes these exceptions:
```
[2019-12-22 20:48:14.779 +01:00] [ERR] Error in WaitForExit
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.GetWaitState()
at System.Diagnostics.Process.WaitForExitCore(Int32 milliseconds)
at System.Diagnostics.Process.WaitForExit(Int32 milliseconds)
at Emby.Server.Implementations.Diagnostics.CommonProcess.WaitForExit(Int32 timeMs) in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 100
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 785
[2019-12-22 20:48:14.790 +01:00] [INF] Killing ffmpeg process
[2019-12-22 20:48:14.795 +01:00] [ERR] Error killing process
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.Kill()
at Emby.Server.Implementations.Diagnostics.CommonProcess.Kill() in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 95
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 799
[2019-12-22 20:48:14.808 +01:00] [ERR] Error in "ffprobe"
System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $.streams[0].start_pts | LineNumber: 32 | BytePositionInLine: 26.
---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
at System.Text.Json.Utf8JsonReader.GetString()
at System.Text.Json.Serialization.Converters.JsonConverterString.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.JsonPropertyInfoNotNullable`4.OnRead(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonPropertyInfo.Read(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonSerializer.HandleValue(JsonTokenType tokenType, JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& readStack, Utf8JsonReader& reader, Exception ex)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadCore(JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken)
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.GetMediaInfoInternal(String inputPath, String primaryPath, MediaProtocol protocol, Boolean extractChapters, String probeSizeArgument, Boolean isAudio, Nullable`1 videoType, Boolean forceEnableLogging, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 399
at MediaBrowser.Providers.MediaInfo.FFProbeVideoInfo.ProbeVideo[T](T item, MetadataRefreshOptions options, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs:line 122
at MediaBrowser.Providers.Manager.MetadataService`2.RunCustomProvider(ICustomMetadataProvider`1 provider, TItemType item, String logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/Manager/MetadataService.cs:line 815
```
2019-12-22 21:39:26 +01:00
stream . RefFrames = streamInfo . Refs ;
2018-12-14 10:40:55 +01:00
}
2020-05-14 18:11:32 +02:00
2020-07-25 00:57:34 +08:00
if ( ! string . IsNullOrEmpty ( streamInfo . ColorRange ) )
{
stream . ColorRange = streamInfo . ColorRange ;
}
if ( ! string . IsNullOrEmpty ( streamInfo . ColorSpace ) )
{
stream . ColorSpace = streamInfo . ColorSpace ;
}
2020-05-14 18:11:32 +02:00
if ( ! string . IsNullOrEmpty ( streamInfo . ColorTransfer ) )
{
stream . ColorTransfer = streamInfo . ColorTransfer ;
}
2020-05-14 18:52:42 +02:00
if ( ! string . IsNullOrEmpty ( streamInfo . ColorPrimaries ) )
{
stream . ColorPrimaries = streamInfo . ColorPrimaries ;
}
2022-06-26 20:55:36 -04:00
2022-12-05 15:01:13 +01:00
if ( streamInfo . SideDataList is not null )
2022-06-26 20:55:36 -04:00
{
foreach ( var data in streamInfo . SideDataList )
{
// Parse Dolby Vision metadata from side_data
if ( string . Equals ( data . SideDataType , "DOVI configuration record" , StringComparison . OrdinalIgnoreCase ) )
{
stream . DvVersionMajor = data . DvVersionMajor ;
stream . DvVersionMinor = data . DvVersionMinor ;
stream . DvProfile = data . DvProfile ;
stream . DvLevel = data . DvLevel ;
stream . RpuPresentFlag = data . RpuPresentFlag ;
stream . ElPresentFlag = data . ElPresentFlag ;
stream . BlPresentFlag = data . BlPresentFlag ;
stream . DvBlSignalCompatibilityId = data . DvBlSignalCompatibilityId ;
2024-03-30 05:55:15 +08:00
}
2022-06-26 20:55:36 -04:00
2024-03-30 05:55:15 +08:00
// Parse video rotation metadata from side_data
else if ( string . Equals ( data . SideDataType , "Display Matrix" , StringComparison . OrdinalIgnoreCase ) )
{
stream . Rotation = data . Rotation ;
2022-06-26 20:55:36 -04:00
}
2025-10-27 15:43:18 -04:00
// Parse video frame cropping metadata from side_data
// TODO: save them and make HW filters to apply them in HWA pipelines
else if ( string . Equals ( data . SideDataType , "Frame Cropping" , StringComparison . OrdinalIgnoreCase ) )
{
// Streams containing artificially added frame cropping
// metadata should not be marked as anamorphic.
stream . IsAnamorphic = false ;
}
2022-06-26 20:55:36 -04:00
}
}
2025-04-03 08:06:02 +08:00
var frameInfo = frameInfoList ? . FirstOrDefault ( i = > i . StreamIndex = = stream . Index ) ;
2025-09-12 21:58:23 +02:00
if ( frameInfo ? . SideDataList is not null
& & frameInfo . SideDataList . Any ( data = > string . Equals ( data . SideDataType , "HDR Dynamic Metadata SMPTE2094-40 (HDR10+)" , StringComparison . OrdinalIgnoreCase ) ) )
2025-04-03 08:06:02 +08:00
{
2025-09-12 21:58:23 +02:00
stream . Hdr10PlusPresentFlag = true ;
2025-04-03 08:06:02 +08:00
}
2018-12-14 10:40:55 +01:00
}
2023-02-01 14:58:04 +01:00
else if ( streamInfo . CodecType = = CodecType . Data )
2022-10-01 08:53:54 -06:00
{
stream . Type = MediaStreamType . Data ;
}
2018-12-14 10:40:55 +01:00
else
{
return null ;
}
// Get stream bitrate
var bitrate = 0 ;
2023-02-19 16:52:29 +01:00
if ( int . TryParse ( streamInfo . BitRate , CultureInfo . InvariantCulture , out var value ) )
2018-12-14 10:40:55 +01:00
{
2023-02-19 16:52:29 +01:00
bitrate = value ;
2018-12-14 10:40:55 +01:00
}
2020-11-29 22:46:26 +08:00
// The bitrate info of FLAC musics and some videos is included in formatInfo.
if ( bitrate = = 0
2022-12-05 15:01:13 +01:00
& & formatInfo is not null
2020-12-01 10:53:56 +08:00
& & ( stream . Type = = MediaStreamType . Video | | ( isAudio & & stream . Type = = MediaStreamType . Audio ) ) )
2018-12-14 10:40:55 +01:00
{
// If the stream info doesn't have a bitrate get the value from the media format info
2023-02-19 16:52:29 +01:00
if ( int . TryParse ( formatInfo . BitRate , CultureInfo . InvariantCulture , out value ) )
2018-12-14 10:40:55 +01:00
{
bitrate = value ;
}
}
if ( bitrate > 0 )
{
stream . BitRate = bitrate ;
}
2020-11-11 17:08:50 +08:00
// Extract bitrate info from tag "BPS" if possible.
if ( ! stream . BitRate . HasValue
2023-02-01 14:58:04 +01:00
& & ( streamInfo . CodecType = = CodecType . Audio
| | streamInfo . CodecType = = CodecType . Video ) )
2020-11-11 17:08:50 +08:00
{
var bps = GetBPSFromTags ( streamInfo ) ;
2021-07-09 02:06:38 +02:00
if ( bps > 0 )
2020-11-11 17:08:50 +08:00
{
stream . BitRate = bps ;
}
2023-02-01 14:58:04 +01:00
else
2020-11-11 17:08:50 +08:00
{
2023-02-01 14:58:04 +01:00
// Get average bitrate info from tag "NUMBER_OF_BYTES" and "DURATION" if possible.
var durationInSeconds = GetRuntimeSecondsFromTags ( streamInfo ) ;
var bytes = GetNumberOfBytesFromTags ( streamInfo ) ;
2025-04-19 21:08:29 +02:00
if ( durationInSeconds is not null & & durationInSeconds . Value > = 1 & & bytes is not null )
2020-11-11 17:08:50 +08:00
{
2023-02-01 14:58:04 +01:00
bps = Convert . ToInt32 ( bytes * 8 / durationInSeconds , CultureInfo . InvariantCulture ) ;
if ( bps > 0 )
{
stream . BitRate = bps ;
}
2020-11-11 17:08:50 +08:00
}
}
}
Fix exceptions while scanning
Fixes these exceptions:
```
[2019-12-22 20:48:14.779 +01:00] [ERR] Error in WaitForExit
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.GetWaitState()
at System.Diagnostics.Process.WaitForExitCore(Int32 milliseconds)
at System.Diagnostics.Process.WaitForExit(Int32 milliseconds)
at Emby.Server.Implementations.Diagnostics.CommonProcess.WaitForExit(Int32 timeMs) in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 100
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 785
[2019-12-22 20:48:14.790 +01:00] [INF] Killing ffmpeg process
[2019-12-22 20:48:14.795 +01:00] [ERR] Error killing process
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.Kill()
at Emby.Server.Implementations.Diagnostics.CommonProcess.Kill() in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 95
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 799
[2019-12-22 20:48:14.808 +01:00] [ERR] Error in "ffprobe"
System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $.streams[0].start_pts | LineNumber: 32 | BytePositionInLine: 26.
---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
at System.Text.Json.Utf8JsonReader.GetString()
at System.Text.Json.Serialization.Converters.JsonConverterString.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.JsonPropertyInfoNotNullable`4.OnRead(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonPropertyInfo.Read(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonSerializer.HandleValue(JsonTokenType tokenType, JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& readStack, Utf8JsonReader& reader, Exception ex)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadCore(JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken)
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.GetMediaInfoInternal(String inputPath, String primaryPath, MediaProtocol protocol, Boolean extractChapters, String probeSizeArgument, Boolean isAudio, Nullable`1 videoType, Boolean forceEnableLogging, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 399
at MediaBrowser.Providers.MediaInfo.FFProbeVideoInfo.ProbeVideo[T](T item, MetadataRefreshOptions options, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs:line 122
at MediaBrowser.Providers.Manager.MetadataService`2.RunCustomProvider(ICustomMetadataProvider`1 provider, TItemType item, String logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/Manager/MetadataService.cs:line 815
```
2019-12-22 21:39:26 +01:00
var disposition = streamInfo . Disposition ;
2022-12-05 15:01:13 +01:00
if ( disposition is not null )
2018-12-14 10:40:55 +01:00
{
Fix exceptions while scanning
Fixes these exceptions:
```
[2019-12-22 20:48:14.779 +01:00] [ERR] Error in WaitForExit
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.GetWaitState()
at System.Diagnostics.Process.WaitForExitCore(Int32 milliseconds)
at System.Diagnostics.Process.WaitForExit(Int32 milliseconds)
at Emby.Server.Implementations.Diagnostics.CommonProcess.WaitForExit(Int32 timeMs) in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 100
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 785
[2019-12-22 20:48:14.790 +01:00] [INF] Killing ffmpeg process
[2019-12-22 20:48:14.795 +01:00] [ERR] Error killing process
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.Kill()
at Emby.Server.Implementations.Diagnostics.CommonProcess.Kill() in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 95
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 799
[2019-12-22 20:48:14.808 +01:00] [ERR] Error in "ffprobe"
System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $.streams[0].start_pts | LineNumber: 32 | BytePositionInLine: 26.
---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
at System.Text.Json.Utf8JsonReader.GetString()
at System.Text.Json.Serialization.Converters.JsonConverterString.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.JsonPropertyInfoNotNullable`4.OnRead(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonPropertyInfo.Read(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonSerializer.HandleValue(JsonTokenType tokenType, JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& readStack, Utf8JsonReader& reader, Exception ex)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadCore(JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken)
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.GetMediaInfoInternal(String inputPath, String primaryPath, MediaProtocol protocol, Boolean extractChapters, String probeSizeArgument, Boolean isAudio, Nullable`1 videoType, Boolean forceEnableLogging, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 399
at MediaBrowser.Providers.MediaInfo.FFProbeVideoInfo.ProbeVideo[T](T item, MetadataRefreshOptions options, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs:line 122
at MediaBrowser.Providers.Manager.MetadataService`2.RunCustomProvider(ICustomMetadataProvider`1 provider, TItemType item, String logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/Manager/MetadataService.cs:line 815
```
2019-12-22 21:39:26 +01:00
if ( disposition . GetValueOrDefault ( "default" ) = = 1 )
{
stream . IsDefault = true ;
}
2018-12-14 10:40:55 +01:00
Fix exceptions while scanning
Fixes these exceptions:
```
[2019-12-22 20:48:14.779 +01:00] [ERR] Error in WaitForExit
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.GetWaitState()
at System.Diagnostics.Process.WaitForExitCore(Int32 milliseconds)
at System.Diagnostics.Process.WaitForExit(Int32 milliseconds)
at Emby.Server.Implementations.Diagnostics.CommonProcess.WaitForExit(Int32 timeMs) in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 100
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 785
[2019-12-22 20:48:14.790 +01:00] [INF] Killing ffmpeg process
[2019-12-22 20:48:14.795 +01:00] [ERR] Error killing process
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.Kill()
at Emby.Server.Implementations.Diagnostics.CommonProcess.Kill() in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 95
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 799
[2019-12-22 20:48:14.808 +01:00] [ERR] Error in "ffprobe"
System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $.streams[0].start_pts | LineNumber: 32 | BytePositionInLine: 26.
---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
at System.Text.Json.Utf8JsonReader.GetString()
at System.Text.Json.Serialization.Converters.JsonConverterString.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.JsonPropertyInfoNotNullable`4.OnRead(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonPropertyInfo.Read(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonSerializer.HandleValue(JsonTokenType tokenType, JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& readStack, Utf8JsonReader& reader, Exception ex)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadCore(JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken)
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.GetMediaInfoInternal(String inputPath, String primaryPath, MediaProtocol protocol, Boolean extractChapters, String probeSizeArgument, Boolean isAudio, Nullable`1 videoType, Boolean forceEnableLogging, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 399
at MediaBrowser.Providers.MediaInfo.FFProbeVideoInfo.ProbeVideo[T](T item, MetadataRefreshOptions options, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs:line 122
at MediaBrowser.Providers.Manager.MetadataService`2.RunCustomProvider(ICustomMetadataProvider`1 provider, TItemType item, String logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/Manager/MetadataService.cs:line 815
```
2019-12-22 21:39:26 +01:00
if ( disposition . GetValueOrDefault ( "forced" ) = = 1 )
{
stream . IsForced = true ;
}
2022-10-07 06:38:05 -04:00
if ( disposition . GetValueOrDefault ( "hearing_impaired" ) = = 1 )
{
stream . IsHearingImpaired = true ;
}
2018-12-14 10:40:55 +01:00
}
NormalizeStreamTitle ( stream ) ;
return stream ;
}
2025-08-27 18:34:00 -05:00
private static void NormalizeStreamTitle ( MediaStream stream )
2018-12-14 10:40:55 +01:00
{
2023-02-01 14:58:04 +01:00
if ( string . Equals ( stream . Title , "cc" , StringComparison . OrdinalIgnoreCase )
| | stream . Type = = MediaStreamType . EmbeddedImage )
2018-12-14 10:40:55 +01:00
{
stream . Title = null ;
}
}
/// <summary>
2020-06-16 10:37:52 +12:00
/// Gets a string from an FFProbeResult tags dictionary.
2018-12-14 10:40:55 +01:00
/// </summary>
/// <param name="tags">The tags.</param>
/// <param name="key">The key.</param>
/// <returns>System.String.</returns>
2025-08-27 18:34:00 -05:00
private static string GetDictionaryValue ( IReadOnlyDictionary < string , string > tags , string key )
2018-12-14 10:40:55 +01:00
{
2022-12-05 15:00:20 +01:00
if ( tags is null )
2018-12-14 10:40:55 +01:00
{
return null ;
}
2019-01-13 21:46:33 +01:00
tags . TryGetValue ( key , out var val ) ;
2021-07-09 02:06:38 +02:00
2018-12-14 10:40:55 +01:00
return val ;
}
2025-08-27 18:34:00 -05:00
private static string ParseChannelLayout ( string input )
2018-12-14 10:40:55 +01:00
{
if ( string . IsNullOrEmpty ( input ) )
{
2021-07-09 02:06:38 +02:00
return null ;
2018-12-14 10:40:55 +01:00
}
2023-02-01 14:58:04 +01:00
return input . AsSpan ( ) . LeftPart ( '(' ) . ToString ( ) ;
2018-12-14 10:40:55 +01:00
}
2025-08-27 18:34:00 -05:00
private static string GetAspectRatio ( MediaStreamInfo info )
2018-12-14 10:40:55 +01:00
{
Fix exceptions while scanning
Fixes these exceptions:
```
[2019-12-22 20:48:14.779 +01:00] [ERR] Error in WaitForExit
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.GetWaitState()
at System.Diagnostics.Process.WaitForExitCore(Int32 milliseconds)
at System.Diagnostics.Process.WaitForExit(Int32 milliseconds)
at Emby.Server.Implementations.Diagnostics.CommonProcess.WaitForExit(Int32 timeMs) in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 100
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 785
[2019-12-22 20:48:14.790 +01:00] [INF] Killing ffmpeg process
[2019-12-22 20:48:14.795 +01:00] [ERR] Error killing process
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.Kill()
at Emby.Server.Implementations.Diagnostics.CommonProcess.Kill() in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 95
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 799
[2019-12-22 20:48:14.808 +01:00] [ERR] Error in "ffprobe"
System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $.streams[0].start_pts | LineNumber: 32 | BytePositionInLine: 26.
---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
at System.Text.Json.Utf8JsonReader.GetString()
at System.Text.Json.Serialization.Converters.JsonConverterString.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.JsonPropertyInfoNotNullable`4.OnRead(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonPropertyInfo.Read(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonSerializer.HandleValue(JsonTokenType tokenType, JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& readStack, Utf8JsonReader& reader, Exception ex)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadCore(JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken)
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.GetMediaInfoInternal(String inputPath, String primaryPath, MediaProtocol protocol, Boolean extractChapters, String probeSizeArgument, Boolean isAudio, Nullable`1 videoType, Boolean forceEnableLogging, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 399
at MediaBrowser.Providers.MediaInfo.FFProbeVideoInfo.ProbeVideo[T](T item, MetadataRefreshOptions options, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs:line 122
at MediaBrowser.Providers.Manager.MetadataService`2.RunCustomProvider(ICustomMetadataProvider`1 provider, TItemType item, String logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/Manager/MetadataService.cs:line 815
```
2019-12-22 21:39:26 +01:00
var original = info . DisplayAspectRatio ;
2018-12-14 10:40:55 +01:00
var parts = ( original ? ? string . Empty ) . Split ( ':' ) ;
2023-02-01 14:58:04 +01:00
if ( ! ( parts . Length = = 2
2023-02-19 16:52:29 +01:00
& & int . TryParse ( parts [ 0 ] , CultureInfo . InvariantCulture , out var width )
& & int . TryParse ( parts [ 1 ] , CultureInfo . InvariantCulture , out var height )
2023-02-01 14:58:04 +01:00
& & width > 0
& & height > 0 ) )
2018-12-14 10:40:55 +01:00
{
Fix exceptions while scanning
Fixes these exceptions:
```
[2019-12-22 20:48:14.779 +01:00] [ERR] Error in WaitForExit
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.GetWaitState()
at System.Diagnostics.Process.WaitForExitCore(Int32 milliseconds)
at System.Diagnostics.Process.WaitForExit(Int32 milliseconds)
at Emby.Server.Implementations.Diagnostics.CommonProcess.WaitForExit(Int32 timeMs) in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 100
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 785
[2019-12-22 20:48:14.790 +01:00] [INF] Killing ffmpeg process
[2019-12-22 20:48:14.795 +01:00] [ERR] Error killing process
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.Kill()
at Emby.Server.Implementations.Diagnostics.CommonProcess.Kill() in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 95
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 799
[2019-12-22 20:48:14.808 +01:00] [ERR] Error in "ffprobe"
System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $.streams[0].start_pts | LineNumber: 32 | BytePositionInLine: 26.
---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
at System.Text.Json.Utf8JsonReader.GetString()
at System.Text.Json.Serialization.Converters.JsonConverterString.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.JsonPropertyInfoNotNullable`4.OnRead(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonPropertyInfo.Read(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonSerializer.HandleValue(JsonTokenType tokenType, JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& readStack, Utf8JsonReader& reader, Exception ex)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadCore(JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken)
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.GetMediaInfoInternal(String inputPath, String primaryPath, MediaProtocol protocol, Boolean extractChapters, String probeSizeArgument, Boolean isAudio, Nullable`1 videoType, Boolean forceEnableLogging, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 399
at MediaBrowser.Providers.MediaInfo.FFProbeVideoInfo.ProbeVideo[T](T item, MetadataRefreshOptions options, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs:line 122
at MediaBrowser.Providers.Manager.MetadataService`2.RunCustomProvider(ICustomMetadataProvider`1 provider, TItemType item, String logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/Manager/MetadataService.cs:line 815
```
2019-12-22 21:39:26 +01:00
width = info . Width ;
height = info . Height ;
2018-12-14 10:40:55 +01:00
}
if ( width > 0 & & height > 0 )
{
double ratio = width ;
ratio / = height ;
if ( IsClose ( ratio , 1.777777778 , . 03 ) )
{
return "16:9" ;
}
if ( IsClose ( ratio , 1.3333333333 , . 05 ) )
{
return "4:3" ;
}
if ( IsClose ( ratio , 1.41 ) )
{
return "1.41:1" ;
}
if ( IsClose ( ratio , 1.5 ) )
{
return "1.5:1" ;
}
if ( IsClose ( ratio , 1.6 ) )
{
return "1.6:1" ;
}
if ( IsClose ( ratio , 1.66666666667 ) )
{
return "5:3" ;
}
if ( IsClose ( ratio , 1.85 , . 02 ) )
{
return "1.85:1" ;
}
if ( IsClose ( ratio , 2.35 , . 025 ) )
{
return "2.35:1" ;
}
if ( IsClose ( ratio , 2.4 , . 025 ) )
{
return "2.40:1" ;
}
}
return original ;
}
2025-08-27 18:34:00 -05:00
private static bool IsClose ( double d1 , double d2 , double variance = . 005 )
2018-12-14 10:40:55 +01:00
{
return Math . Abs ( d1 - d2 ) < = variance ;
}
/// <summary>
/// Gets a frame rate from a string value in ffprobe output
/// This could be a number or in the format of 2997/125.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>System.Nullable{System.Single}.</returns>
2021-12-12 02:22:30 +01:00
internal static float? GetFrameRate ( ReadOnlySpan < char > value )
2018-12-14 10:40:55 +01:00
{
2021-12-12 02:22:30 +01:00
if ( value . IsEmpty )
2018-12-14 10:40:55 +01:00
{
2021-07-09 02:06:38 +02:00
return null ;
}
2018-12-14 10:40:55 +01:00
2021-12-12 02:22:30 +01:00
int index = value . IndexOf ( '/' ) ;
if ( index = = - 1 )
2021-07-09 02:06:38 +02:00
{
2021-12-12 02:22:30 +01:00
return null ;
2021-07-09 02:06:38 +02:00
}
2021-12-12 02:22:30 +01:00
if ( ! float . TryParse ( value [ . . index ] , NumberStyles . Integer , CultureInfo . InvariantCulture , out var dividend )
| | ! float . TryParse ( value [ ( index + 1 ) . . ] , NumberStyles . Integer , CultureInfo . InvariantCulture , out var divisor ) )
2021-07-09 02:06:38 +02:00
{
2021-12-12 02:22:30 +01:00
return null ;
2018-12-14 10:40:55 +01:00
}
2021-12-15 18:33:27 +01:00
return divisor = = 0f ? null : dividend / divisor ;
2018-12-14 10:40:55 +01:00
}
2025-08-27 18:34:00 -05:00
private static void SetAudioRuntimeTicks ( InternalMediaInfoResult result , MediaInfo data )
2018-12-14 10:40:55 +01:00
{
2021-07-09 02:06:38 +02:00
// Get the first info stream
2023-02-01 14:58:04 +01:00
var stream = result . Streams ? . FirstOrDefault ( s = > s . CodecType = = CodecType . Audio ) ;
2022-12-05 15:00:20 +01:00
if ( stream is null )
2018-12-14 10:40:55 +01:00
{
2021-07-09 02:06:38 +02:00
return ;
}
2018-12-14 10:40:55 +01:00
2021-07-09 02:06:38 +02:00
// Get duration from stream properties
var duration = stream . Duration ;
2018-12-14 10:40:55 +01:00
2021-07-09 02:06:38 +02:00
// If it's not there go into format properties
if ( string . IsNullOrEmpty ( duration ) )
{
duration = result . Format . Duration ;
}
2018-12-14 10:40:55 +01:00
2021-07-09 02:06:38 +02:00
// If we got something, parse it
if ( ! string . IsNullOrEmpty ( duration ) )
{
2021-09-26 08:14:36 -06:00
data . RunTimeTicks = TimeSpan . FromSeconds ( double . Parse ( duration , CultureInfo . InvariantCulture ) ) . Ticks ;
2018-12-14 10:40:55 +01:00
}
}
2025-08-27 18:34:00 -05:00
private static int? GetBPSFromTags ( MediaStreamInfo streamInfo )
2020-11-11 17:08:50 +08:00
{
2022-12-05 15:00:20 +01:00
if ( streamInfo ? . Tags is null )
2020-11-11 17:08:50 +08:00
{
2021-07-09 02:06:38 +02:00
return null ;
}
var bps = GetDictionaryValue ( streamInfo . Tags , "BPS-eng" ) ? ? GetDictionaryValue ( streamInfo . Tags , "BPS" ) ;
2023-02-01 14:58:04 +01:00
if ( int . TryParse ( bps , NumberStyles . Integer , CultureInfo . InvariantCulture , out var parsedBps ) )
2021-07-09 02:06:38 +02:00
{
return parsedBps ;
2020-11-11 17:08:50 +08:00
}
return null ;
}
2025-08-27 18:34:00 -05:00
private static double? GetRuntimeSecondsFromTags ( MediaStreamInfo streamInfo )
2020-11-11 17:08:50 +08:00
{
2022-12-05 15:00:20 +01:00
if ( streamInfo ? . Tags is null )
2020-11-11 17:08:50 +08:00
{
2021-07-09 02:06:38 +02:00
return null ;
}
var duration = GetDictionaryValue ( streamInfo . Tags , "DURATION-eng" ) ? ? GetDictionaryValue ( streamInfo . Tags , "DURATION" ) ;
2023-02-19 16:52:29 +01:00
if ( TimeSpan . TryParse ( duration , out var parsedDuration ) )
2021-07-09 02:06:38 +02:00
{
return parsedDuration . TotalSeconds ;
2020-11-11 17:08:50 +08:00
}
return null ;
}
2025-08-27 18:34:00 -05:00
private static long? GetNumberOfBytesFromTags ( MediaStreamInfo streamInfo )
2020-11-11 17:08:50 +08:00
{
2022-12-05 15:00:20 +01:00
if ( streamInfo ? . Tags is null )
2020-11-11 17:08:50 +08:00
{
2021-07-09 02:06:38 +02:00
return null ;
}
var numberOfBytes = GetDictionaryValue ( streamInfo . Tags , "NUMBER_OF_BYTES-eng" )
? ? GetDictionaryValue ( streamInfo . Tags , "NUMBER_OF_BYTES" ) ;
2023-02-01 14:58:04 +01:00
if ( long . TryParse ( numberOfBytes , NumberStyles . Integer , CultureInfo . InvariantCulture , out var parsedBytes ) )
2021-07-09 02:06:38 +02:00
{
return parsedBytes ;
2020-11-11 17:08:50 +08:00
}
return null ;
}
2025-08-27 18:34:00 -05:00
private static void SetSize ( InternalMediaInfoResult data , MediaInfo info )
2018-12-14 10:40:55 +01:00
{
2022-12-05 15:00:20 +01:00
if ( data . Format is null )
2018-12-14 10:40:55 +01:00
{
2021-07-09 02:06:38 +02:00
return ;
2018-12-14 10:40:55 +01:00
}
2021-07-09 02:06:38 +02:00
2021-09-26 08:14:36 -06:00
info . Size = string . IsNullOrEmpty ( data . Format . Size ) ? null : long . Parse ( data . Format . Size , CultureInfo . InvariantCulture ) ;
2018-12-14 10:40:55 +01:00
}
2023-10-24 00:10:31 +02:00
private void SetAudioInfoFromTags ( MediaInfo audio , Dictionary < string , string > tags )
2018-12-14 10:40:55 +01:00
{
2021-04-04 23:34:29 +02:00
var people = new List < BaseItemPerson > ( ) ;
2021-07-09 02:06:38 +02:00
if ( tags . TryGetValue ( "composer" , out var composer ) & & ! string . IsNullOrWhiteSpace ( composer ) )
2018-12-14 10:40:55 +01:00
{
foreach ( var person in Split ( composer , false ) )
{
2023-03-25 11:52:02 -06:00
people . Add ( new BaseItemPerson { Name = person , Type = PersonKind . Composer } ) ;
2018-12-14 10:40:55 +01:00
}
}
2021-07-09 02:06:38 +02:00
if ( tags . TryGetValue ( "conductor" , out var conductor ) & & ! string . IsNullOrWhiteSpace ( conductor ) )
2020-08-04 17:08:09 +02:00
{
foreach ( var person in Split ( conductor , false ) )
{
2023-03-25 11:52:02 -06:00
people . Add ( new BaseItemPerson { Name = person , Type = PersonKind . Conductor } ) ;
2020-08-04 17:08:09 +02:00
}
}
2018-12-14 10:40:55 +01:00
2021-07-09 02:06:38 +02:00
if ( tags . TryGetValue ( "lyricist" , out var lyricist ) & & ! string . IsNullOrWhiteSpace ( lyricist ) )
2020-08-04 17:08:09 +02:00
{
foreach ( var person in Split ( lyricist , false ) )
{
2023-03-25 11:52:02 -06:00
people . Add ( new BaseItemPerson { Name = person , Type = PersonKind . Lyricist } ) ;
2020-08-04 17:08:09 +02:00
}
}
2018-12-14 10:40:55 +01:00
2021-07-27 17:09:23 +02:00
if ( tags . TryGetValue ( "performer" , out var performer ) & & ! string . IsNullOrWhiteSpace ( performer ) )
{
foreach ( var person in Split ( performer , false ) )
{
2023-10-08 01:16:00 +02:00
Match match = PerformerRegex ( ) . Match ( person ) ;
2021-07-27 17:09:23 +02:00
// If the performer doesn't have any instrument/role associated, it won't match. In that case, chances are it's simply a band name, so we skip it.
if ( match . Success )
{
people . Add ( new BaseItemPerson
{
Name = match . Groups [ "name" ] . Value ,
2023-03-25 11:52:02 -06:00
Type = PersonKind . Actor ,
2021-09-26 08:14:36 -06:00
Role = CultureInfo . InvariantCulture . TextInfo . ToTitleCase ( match . Groups [ "instrument" ] . Value )
2021-07-27 17:09:23 +02:00
} ) ;
}
}
}
2021-07-27 23:52:05 +02:00
// In cases where there isn't sufficient information as to which role a writer performed on a recording, tagging software uses the "writer" tag.
2021-07-09 02:06:38 +02:00
if ( tags . TryGetValue ( "writer" , out var writer ) & & ! string . IsNullOrWhiteSpace ( writer ) )
2018-12-14 10:40:55 +01:00
{
foreach ( var person in Split ( writer , false ) )
{
2023-03-25 11:52:02 -06:00
people . Add ( new BaseItemPerson { Name = person , Type = PersonKind . Writer } ) ;
2018-12-14 10:40:55 +01:00
}
}
2021-07-27 23:52:05 +02:00
if ( tags . TryGetValue ( "arranger" , out var arranger ) & & ! string . IsNullOrWhiteSpace ( arranger ) )
{
foreach ( var person in Split ( arranger , false ) )
{
2023-03-25 11:52:02 -06:00
people . Add ( new BaseItemPerson { Name = person , Type = PersonKind . Arranger } ) ;
2021-07-27 23:52:05 +02:00
}
}
if ( tags . TryGetValue ( "engineer" , out var engineer ) & & ! string . IsNullOrWhiteSpace ( engineer ) )
{
foreach ( var person in Split ( engineer , false ) )
{
2023-03-25 11:52:02 -06:00
people . Add ( new BaseItemPerson { Name = person , Type = PersonKind . Engineer } ) ;
2021-07-27 23:52:05 +02:00
}
}
if ( tags . TryGetValue ( "mixer" , out var mixer ) & & ! string . IsNullOrWhiteSpace ( mixer ) )
{
foreach ( var person in Split ( mixer , false ) )
{
2023-03-25 11:52:02 -06:00
people . Add ( new BaseItemPerson { Name = person , Type = PersonKind . Mixer } ) ;
2021-07-27 23:52:05 +02:00
}
}
if ( tags . TryGetValue ( "remixer" , out var remixer ) & & ! string . IsNullOrWhiteSpace ( remixer ) )
{
foreach ( var person in Split ( remixer , false ) )
{
2023-03-25 11:52:02 -06:00
people . Add ( new BaseItemPerson { Name = person , Type = PersonKind . Remixer } ) ;
2021-07-27 23:52:05 +02:00
}
}
2021-04-04 23:34:29 +02:00
audio . People = people . ToArray ( ) ;
2018-12-14 10:40:55 +01:00
2021-07-09 02:06:38 +02:00
// Set album artist
var albumArtist = tags . GetFirstNotNullNorWhiteSpaceValue ( "albumartist" , "album artist" , "album_artist" ) ;
2022-12-05 15:01:13 +01:00
audio . AlbumArtists = albumArtist is not null
2021-07-09 02:06:38 +02:00
? SplitDistinctArtists ( albumArtist , _nameDelimiters , true ) . ToArray ( )
: Array . Empty < string > ( ) ;
2018-12-14 10:40:55 +01:00
2021-07-09 02:06:38 +02:00
// Set album artist to artist if empty
2018-12-14 10:40:55 +01:00
if ( audio . AlbumArtists . Length = = 0 )
{
audio . AlbumArtists = audio . Artists ;
}
// Track number
2021-07-09 02:06:38 +02:00
audio . IndexNumber = GetDictionaryTrackOrDiscNumber ( tags , "track" ) ;
2018-12-14 10:40:55 +01:00
// Disc number
2021-07-09 02:06:38 +02:00
audio . ParentIndexNumber = GetDictionaryTrackOrDiscNumber ( tags , "disc" ) ;
2018-12-14 10:40:55 +01:00
// There's several values in tags may or may not be present
FetchStudios ( audio , tags , "organization" ) ;
FetchStudios ( audio , tags , "ensemble" ) ;
FetchStudios ( audio , tags , "publisher" ) ;
FetchStudios ( audio , tags , "label" ) ;
2021-07-09 02:06:38 +02:00
// These support multiple values, but for now we only store the first.
var mb = GetMultipleMusicBrainzId ( tags . GetValueOrDefault ( "MusicBrainz Album Artist Id" ) )
? ? GetMultipleMusicBrainzId ( tags . GetValueOrDefault ( "MUSICBRAINZ_ALBUMARTISTID" ) ) ;
2024-07-17 15:48:21 +02:00
audio . TrySetProviderId ( MetadataProvider . MusicBrainzAlbumArtist , mb ) ;
2018-12-14 10:40:55 +01:00
2021-07-09 02:06:38 +02:00
mb = GetMultipleMusicBrainzId ( tags . GetValueOrDefault ( "MusicBrainz Artist Id" ) )
? ? GetMultipleMusicBrainzId ( tags . GetValueOrDefault ( "MUSICBRAINZ_ARTISTID" ) ) ;
2024-07-17 15:48:21 +02:00
audio . TrySetProviderId ( MetadataProvider . MusicBrainzArtist , mb ) ;
2018-12-14 10:40:55 +01:00
2021-07-09 02:06:38 +02:00
mb = GetMultipleMusicBrainzId ( tags . GetValueOrDefault ( "MusicBrainz Album Id" ) )
? ? GetMultipleMusicBrainzId ( tags . GetValueOrDefault ( "MUSICBRAINZ_ALBUMID" ) ) ;
2024-07-17 15:48:21 +02:00
audio . TrySetProviderId ( MetadataProvider . MusicBrainzAlbum , mb ) ;
2018-12-14 10:40:55 +01:00
2021-07-09 02:06:38 +02:00
mb = GetMultipleMusicBrainzId ( tags . GetValueOrDefault ( "MusicBrainz Release Group Id" ) )
? ? GetMultipleMusicBrainzId ( tags . GetValueOrDefault ( "MUSICBRAINZ_RELEASEGROUPID" ) ) ;
2024-07-17 15:48:21 +02:00
audio . TrySetProviderId ( MetadataProvider . MusicBrainzReleaseGroup , mb ) ;
2018-12-14 10:40:55 +01:00
2021-07-09 02:06:38 +02:00
mb = GetMultipleMusicBrainzId ( tags . GetValueOrDefault ( "MusicBrainz Release Track Id" ) )
? ? GetMultipleMusicBrainzId ( tags . GetValueOrDefault ( "MUSICBRAINZ_RELEASETRACKID" ) ) ;
2024-07-17 15:48:21 +02:00
audio . TrySetProviderId ( MetadataProvider . MusicBrainzTrack , mb ) ;
2018-12-14 10:40:55 +01:00
}
2025-08-27 18:34:00 -05:00
private static string GetMultipleMusicBrainzId ( string value )
2018-12-14 10:40:55 +01:00
{
if ( string . IsNullOrWhiteSpace ( value ) )
{
return null ;
}
2024-04-24 16:35:15 +02:00
return value . Split ( '/' , StringSplitOptions . RemoveEmptyEntries | StringSplitOptions . TrimEntries )
. FirstOrDefault ( ) ;
2018-12-14 10:40:55 +01:00
}
/// <summary>
/// Splits the specified val.
/// </summary>
/// <param name="val">The val.</param>
/// <param name="allowCommaDelimiter">if set to <c>true</c> [allow comma delimiter].</param>
/// <returns>System.String[][].</returns>
2024-04-24 16:35:15 +02:00
private string [ ] Split ( string val , bool allowCommaDelimiter )
2018-12-14 10:40:55 +01:00
{
2021-07-09 02:06:38 +02:00
// Only use the comma as a delimiter if there are no slashes or pipes.
2018-12-14 10:40:55 +01:00
// We want to be careful not to split names that have commas in them
2024-04-24 16:35:15 +02:00
return ! allowCommaDelimiter | | _nameDelimiters . Any ( i = > val . Contains ( i , StringComparison . Ordinal ) ) ?
val . Split ( _nameDelimiters , StringSplitOptions . RemoveEmptyEntries | StringSplitOptions . TrimEntries ) :
val . Split ( ',' , StringSplitOptions . RemoveEmptyEntries | StringSplitOptions . TrimEntries ) ;
2018-12-14 10:40:55 +01:00
}
2021-07-09 02:06:38 +02:00
private IEnumerable < string > SplitDistinctArtists ( string val , char [ ] delimiters , bool splitFeaturing )
2018-12-14 10:40:55 +01:00
{
if ( splitFeaturing )
{
val = val . Replace ( " featuring " , ArtistReplaceValue , StringComparison . OrdinalIgnoreCase )
. Replace ( " feat. " , ArtistReplaceValue , StringComparison . OrdinalIgnoreCase ) ;
}
var artistsFound = new List < string > ( ) ;
2021-05-05 14:39:50 +02:00
foreach ( var whitelistArtist in SplitWhitelist )
2018-12-14 10:40:55 +01:00
{
var originalVal = val ;
val = val . Replace ( whitelistArtist , "|" , StringComparison . OrdinalIgnoreCase ) ;
if ( ! string . Equals ( originalVal , val , StringComparison . OrdinalIgnoreCase ) )
{
artistsFound . Add ( whitelistArtist ) ;
}
}
2024-04-24 16:35:15 +02:00
var artists = val . Split ( delimiters , StringSplitOptions . RemoveEmptyEntries | StringSplitOptions . TrimEntries ) ;
2018-12-14 10:40:55 +01:00
artistsFound . AddRange ( artists ) ;
2021-07-09 02:06:38 +02:00
return artistsFound . DistinctNames ( ) ;
2018-12-14 10:40:55 +01:00
}
/// <summary>
2020-06-16 10:37:52 +12:00
/// Gets the studios from the tags collection.
2018-12-14 10:40:55 +01:00
/// </summary>
/// <param name="info">The info.</param>
/// <param name="tags">The tags.</param>
/// <param name="tagName">Name of the tag.</param>
2021-07-09 02:06:38 +02:00
private void FetchStudios ( MediaInfo info , IReadOnlyDictionary < string , string > tags , string tagName )
2018-12-14 10:40:55 +01:00
{
2021-07-09 02:06:38 +02:00
var val = tags . GetValueOrDefault ( tagName ) ;
2018-12-14 10:40:55 +01:00
2021-07-09 02:06:38 +02:00
if ( string . IsNullOrEmpty ( val ) )
2018-12-14 10:40:55 +01:00
{
2021-07-09 02:06:38 +02:00
return ;
}
2018-12-14 10:40:55 +01:00
2021-07-09 02:06:38 +02:00
var studios = Split ( val , true ) ;
var studioList = new List < string > ( ) ;
2020-06-16 09:43:52 +12:00
2021-07-09 02:06:38 +02:00
foreach ( var studio in studios )
{
if ( string . IsNullOrWhiteSpace ( studio ) )
{
continue ;
}
2018-12-14 10:40:55 +01:00
2021-07-09 02:06:38 +02:00
// Don't add artist/album artist name to studios, even if it's listed there
2021-12-20 13:31:07 +01:00
if ( info . Artists . Contains ( studio , StringComparison . OrdinalIgnoreCase )
| | info . AlbumArtists . Contains ( studio , StringComparison . OrdinalIgnoreCase ) )
2021-07-09 02:06:38 +02:00
{
continue ;
2018-12-14 10:40:55 +01:00
}
2021-07-09 02:06:38 +02:00
studioList . Add ( studio ) ;
2018-12-14 10:40:55 +01:00
}
2021-07-09 02:06:38 +02:00
info . Studios = studioList
. Distinct ( StringComparer . OrdinalIgnoreCase )
. ToArray ( ) ;
2018-12-14 10:40:55 +01:00
}
/// <summary>
2020-06-16 10:37:52 +12:00
/// Gets the genres from the tags collection.
2018-12-14 10:40:55 +01:00
/// </summary>
/// <param name="info">The information.</param>
/// <param name="tags">The tags.</param>
2021-07-09 02:06:38 +02:00
private void FetchGenres ( MediaInfo info , IReadOnlyDictionary < string , string > tags )
2018-12-14 10:40:55 +01:00
{
2021-07-09 02:06:38 +02:00
var genreVal = tags . GetValueOrDefault ( "genre" ) ;
if ( string . IsNullOrEmpty ( genreVal ) )
{
return ;
}
2018-12-14 10:40:55 +01:00
2021-07-09 02:06:38 +02:00
var genres = new List < string > ( info . Genres ) ;
foreach ( var genre in Split ( genreVal , true ) )
2018-12-14 10:40:55 +01:00
{
Sort embedded collections in Nfo files
Because the Nfo files emit the collections as they are in-memory, the
files are not stable in format, genres, tags, albums, people, etc. are emitted in random orders. Add ordering of the collections when emitting the Nfo files so the file remains stable (unchanged) when underlying media information doesn't change.
In the process of this, it became clear that most of the providers and probes don't trim the strings like people's names, genre names, etc. so did a pass of Trim cleanup too.
Specific ordering: (alphabetical/numeric ascending after trimming blanks and defaulting to zero for missing numbers)
BaseItem: Directors, Writers, Trailers (by Url), Production Locations, Genres, Studios, Tags, Custom Provider Data (by key), Linked Children (by Path>LibraryItemId), Backdrop Images (by path), Actors (by SortOrder>Name)
AlbumNfo: Artists, Album Artists, Tracks (by ParentIndexNumber>IndexNumber>Name)
ArtistNfo: Albums (by Production Year>SortName>Name)
MovieNfo: Artists
Fix Debug build lint
Fix CI debug build lint issue.
Fix review issues
Fixed debug-build lint issues.
Emits the `disc` number to NFO for tracks with a non-zero ParentIndexNumber and only emit `position` if non-zero.
Removed the exception filtering I put in for testing.
Don't emit actors for MusicAlbums or MusicArtists
Swap from String.Trimmed() to ?.Trim()
Addressing PR feedback
Can't use ReadOnlySpan in an async method
Removed now-unused namespace
2023-05-15 00:38:27 -05:00
if ( string . IsNullOrEmpty ( genre ) )
2018-12-14 10:40:55 +01:00
{
2021-07-09 02:06:38 +02:00
continue ;
2018-12-14 10:40:55 +01:00
}
2021-07-09 02:06:38 +02:00
genres . Add ( genre ) ;
2018-12-14 10:40:55 +01:00
}
2021-07-09 02:06:38 +02:00
info . Genres = genres
. Distinct ( StringComparer . OrdinalIgnoreCase )
. ToArray ( ) ;
2018-12-14 10:40:55 +01:00
}
/// <summary>
2021-07-09 02:06:38 +02:00
/// Gets the track or disc number, which can be in the form of '1', or '1/3'.
2018-12-14 10:40:55 +01:00
/// </summary>
/// <param name="tags">The tags.</param>
/// <param name="tagName">Name of the tag.</param>
2021-07-09 02:06:38 +02:00
/// <returns>The track or disc number, or null, if missing or not parseable.</returns>
private static int? GetDictionaryTrackOrDiscNumber ( IReadOnlyDictionary < string , string > tags , string tagName )
2018-12-14 10:40:55 +01:00
{
2021-07-09 02:06:38 +02:00
var disc = tags . GetValueOrDefault ( tagName ) ;
2018-12-14 10:40:55 +01:00
2023-02-01 14:58:04 +01:00
if ( int . TryParse ( disc . AsSpan ( ) . LeftPart ( '/' ) , out var discNum ) )
2018-12-14 10:40:55 +01:00
{
2021-07-09 02:06:38 +02:00
return discNum ;
2018-12-14 10:40:55 +01:00
}
return null ;
}
2021-07-09 02:06:38 +02:00
private static ChapterInfo GetChapterInfo ( MediaChapter chapter )
2018-12-14 10:40:55 +01:00
{
var info = new ChapterInfo ( ) ;
2022-12-05 15:01:13 +01:00
if ( chapter . Tags is not null & & chapter . Tags . TryGetValue ( "title" , out string name ) )
2018-12-14 10:40:55 +01:00
{
2021-07-09 02:06:38 +02:00
info . Name = name ;
2018-12-14 10:40:55 +01:00
}
// Limit accuracy to milliseconds to match xml saving
Fix exceptions while scanning
Fixes these exceptions:
```
[2019-12-22 20:48:14.779 +01:00] [ERR] Error in WaitForExit
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.GetWaitState()
at System.Diagnostics.Process.WaitForExitCore(Int32 milliseconds)
at System.Diagnostics.Process.WaitForExit(Int32 milliseconds)
at Emby.Server.Implementations.Diagnostics.CommonProcess.WaitForExit(Int32 timeMs) in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 100
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 785
[2019-12-22 20:48:14.790 +01:00] [INF] Killing ffmpeg process
[2019-12-22 20:48:14.795 +01:00] [ERR] Error killing process
System.InvalidOperationException: No process is associated with this object.
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.EnsureState(State state)
at System.Diagnostics.Process.Kill()
at Emby.Server.Implementations.Diagnostics.CommonProcess.Kill() in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 95
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 799
[2019-12-22 20:48:14.808 +01:00] [ERR] Error in "ffprobe"
System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $.streams[0].start_pts | LineNumber: 32 | BytePositionInLine: 26.
---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string.
at System.Text.Json.Utf8JsonReader.GetString()
at System.Text.Json.Serialization.Converters.JsonConverterString.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
at System.Text.Json.JsonPropertyInfoNotNullable`4.OnRead(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonPropertyInfo.Read(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.JsonSerializer.HandleValue(JsonTokenType tokenType, JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& state)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
--- End of inner exception stack trace ---
at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& readStack, Utf8JsonReader& reader, Exception ex)
at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadCore(JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& readStack)
at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken)
at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.GetMediaInfoInternal(String inputPath, String primaryPath, MediaProtocol protocol, Boolean extractChapters, String probeSizeArgument, Boolean isAudio, Nullable`1 videoType, Boolean forceEnableLogging, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 399
at MediaBrowser.Providers.MediaInfo.FFProbeVideoInfo.ProbeVideo[T](T item, MetadataRefreshOptions options, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs:line 122
at MediaBrowser.Providers.Manager.MetadataService`2.RunCustomProvider(ICustomMetadataProvider`1 provider, TItemType item, String logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/Manager/MetadataService.cs:line 815
```
2019-12-22 21:39:26 +01:00
var secondsString = chapter . StartTime ;
2018-12-14 10:40:55 +01:00
2023-02-19 16:52:29 +01:00
if ( double . TryParse ( secondsString , CultureInfo . InvariantCulture , out var seconds ) )
2018-12-14 10:40:55 +01:00
{
var ms = Math . Round ( TimeSpan . FromSeconds ( seconds ) . TotalMilliseconds ) ;
info . StartPositionTicks = TimeSpan . FromMilliseconds ( ms ) . Ticks ;
}
return info ;
}
private void FetchWtvInfo ( MediaInfo video , InternalMediaInfoResult data )
{
2021-07-09 02:06:38 +02:00
var tags = data . Format ? . Tags ;
2022-12-05 15:00:20 +01:00
if ( tags is null )
2018-12-14 10:40:55 +01:00
{
return ;
}
2021-07-09 02:06:38 +02:00
if ( tags . TryGetValue ( "WM/Genre" , out var genres ) & & ! string . IsNullOrWhiteSpace ( genres ) )
2018-12-14 10:40:55 +01:00
{
2025-09-12 21:58:28 +02:00
var genreList = genres . Split ( _genreDelimiters , StringSplitOptions . RemoveEmptyEntries | StringSplitOptions . TrimEntries ) ;
2018-12-14 10:40:55 +01:00
// If this is empty then don't overwrite genres that might have been fetched earlier
2024-04-24 16:35:15 +02:00
if ( genreList . Length > 0 )
2018-12-14 10:40:55 +01:00
{
2024-04-24 16:35:15 +02:00
video . Genres = genreList ;
2018-12-14 10:40:55 +01:00
}
}
2021-07-09 02:06:38 +02:00
if ( tags . TryGetValue ( "WM/ParentalRating" , out var officialRating ) & & ! string . IsNullOrWhiteSpace ( officialRating ) )
2018-12-14 10:40:55 +01:00
{
video . OfficialRating = officialRating ;
}
2021-07-09 02:06:38 +02:00
if ( tags . TryGetValue ( "WM/MediaCredits" , out var people ) & & ! string . IsNullOrEmpty ( people ) )
2018-12-14 10:40:55 +01:00
{
2024-04-24 16:35:15 +02:00
video . People = Array . ConvertAll (
2025-09-12 21:58:28 +02:00
people . Split ( _basicDelimiters , StringSplitOptions . RemoveEmptyEntries | StringSplitOptions . TrimEntries ) ,
2024-04-24 16:35:15 +02:00
i = > new BaseItemPerson { Name = i , Type = PersonKind . Actor } ) ;
2018-12-14 10:40:55 +01:00
}
2021-09-26 08:14:36 -06:00
if ( tags . TryGetValue ( "WM/OriginalReleaseTime" , out var year ) & & int . TryParse ( year , NumberStyles . Integer , CultureInfo . InvariantCulture , out var parsedYear ) )
2018-12-14 10:40:55 +01:00
{
2021-07-09 02:06:38 +02:00
video . ProductionYear = parsedYear ;
2018-12-14 10:40:55 +01:00
}
2021-07-09 02:06:38 +02:00
// Credit to MCEBuddy: https://mcebuddy2x.codeplex.com/
// DateTime is reported along with timezone info (typically Z i.e. UTC hence assume None)
2021-09-21 01:21:45 +02:00
if ( tags . TryGetValue ( "WM/MediaOriginalBroadcastDateTime" , out var premiereDateString ) & & DateTime . TryParse ( year , null , DateTimeStyles . AdjustToUniversal , out var parsedDate ) )
2018-12-14 10:40:55 +01:00
{
2021-09-21 01:21:45 +02:00
video . PremiereDate = parsedDate ;
2018-12-14 10:40:55 +01:00
}
2021-07-09 02:06:38 +02:00
var description = tags . GetValueOrDefault ( "WM/SubTitleDescription" ) ;
2018-12-14 10:40:55 +01:00
2021-07-09 02:06:38 +02:00
var subTitle = tags . GetValueOrDefault ( "WM/SubTitle" ) ;
2018-12-14 10:40:55 +01:00
// For below code, credit to MCEBuddy: https://mcebuddy2x.codeplex.com/
// Sometimes for TV Shows the Subtitle field is empty and the subtitle description contains the subtitle, extract if possible. See ticket https://mcebuddy2x.codeplex.com/workitem/1910
// The format is -> EPISODE/TOTAL_EPISODES_IN_SEASON. SUBTITLE: DESCRIPTION
// OR -> COMMENT. SUBTITLE: DESCRIPTION
// e.g. -> 4/13. The Doctor's Wife: Science fiction drama. When he follows a Time Lord distress signal, the Doctor puts Amy, Rory and his beloved TARDIS in grave danger. Also in HD. [AD,S]
// e.g. -> CBeebies Bedtime Hour. The Mystery: Animated adventures of two friends who live on an island in the middle of the big city. Some of Abney and Teal's favourite objects are missing. [S]
2020-07-29 13:17:01 +02:00
if ( string . IsNullOrWhiteSpace ( subTitle )
& & ! string . IsNullOrWhiteSpace ( description )
2021-09-21 01:21:45 +02:00
& & description . AsSpan ( ) [ . . Math . Min ( description . Length , MaxSubtitleDescriptionExtractionLength ) ] . Contains ( ':' ) ) // Check within the Subtitle size limit, otherwise from description it can get too long creating an invalid filename
2018-12-14 10:40:55 +01:00
{
2021-07-09 02:06:38 +02:00
string [ ] descriptionParts = description . Split ( ':' ) ;
if ( descriptionParts . Length > 0 )
2018-12-14 10:40:55 +01:00
{
2021-07-09 02:06:38 +02:00
string subtitle = descriptionParts [ 0 ] ;
2018-12-14 10:40:55 +01:00
try
{
2021-07-09 02:06:38 +02:00
// Check if it contains a episode number and season number
if ( subtitle . Contains ( '/' , StringComparison . Ordinal ) )
2018-12-14 10:40:55 +01:00
{
2021-07-09 02:06:38 +02:00
string [ ] subtitleParts = subtitle . Split ( ' ' ) ;
string [ ] numbers = subtitleParts [ 0 ] . Replace ( "." , string . Empty , StringComparison . Ordinal ) . Split ( '/' ) ;
video . IndexNumber = int . Parse ( numbers [ 0 ] , CultureInfo . InvariantCulture ) ;
// int totalEpisodesInSeason = int.Parse(numbers[1], CultureInfo.InvariantCulture);
2018-12-14 10:40:55 +01:00
2021-07-09 02:06:38 +02:00
// Skip the numbers, concatenate the rest, trim and set as new description
description = string . Join ( ' ' , subtitleParts , 1 , subtitleParts . Length - 1 ) . Trim ( ) ;
}
else if ( subtitle . Contains ( '.' , StringComparison . Ordinal ) )
{
var subtitleParts = subtitle . Split ( '.' ) ;
description = string . Join ( '.' , subtitleParts , 1 , subtitleParts . Length - 1 ) . Trim ( ) ;
2018-12-14 10:40:55 +01:00
}
else
2020-06-20 21:19:16 +12:00
{
2021-07-09 02:06:38 +02:00
description = subtitle . Trim ( ) ;
2020-06-20 21:19:16 +12:00
}
2018-12-14 10:40:55 +01:00
}
2021-03-09 03:04:47 +01:00
catch ( Exception ex )
2018-12-14 10:40:55 +01:00
{
2021-03-09 03:04:47 +01:00
_logger . LogError ( ex , "Error while parsing subtitle field" ) ;
2021-07-09 02:06:38 +02:00
// Fallback to default parsing
2020-07-29 13:17:01 +02:00
if ( subtitle . Contains ( '.' , StringComparison . Ordinal ) )
{
2021-07-09 02:06:38 +02:00
var subtitleParts = subtitle . Split ( '.' ) ;
description = string . Join ( '.' , subtitleParts , 1 , subtitleParts . Length - 1 ) . Trim ( ) ;
2020-07-29 13:17:01 +02:00
}
2018-12-14 10:40:55 +01:00
else
2020-06-20 21:19:16 +12:00
{
2021-07-09 02:06:38 +02:00
description = subtitle . Trim ( ) ;
2020-06-20 21:19:16 +12:00
}
2018-12-14 10:40:55 +01:00
}
}
}
if ( ! string . IsNullOrWhiteSpace ( description ) )
{
video . Overview = description ;
}
}
private void ExtractTimestamp ( MediaInfo video )
{
2021-07-09 02:06:38 +02:00
if ( video . VideoType ! = VideoType . VideoFile )
2018-12-14 10:40:55 +01:00
{
2021-07-09 02:06:38 +02:00
return ;
}
2018-12-14 10:40:55 +01:00
2021-07-09 02:06:38 +02:00
if ( ! string . Equals ( video . Container , "mpeg2ts" , StringComparison . OrdinalIgnoreCase )
& & ! string . Equals ( video . Container , "m2ts" , StringComparison . OrdinalIgnoreCase )
& & ! string . Equals ( video . Container , "ts" , StringComparison . OrdinalIgnoreCase ) )
{
return ;
}
try
{
video . Timestamp = GetMpegTimestamp ( video . Path ) ;
_logger . LogDebug ( "Video has {Timestamp} timestamp" , video . Timestamp ) ;
}
catch ( Exception ex )
{
video . Timestamp = null ;
_logger . LogError ( ex , "Error extracting timestamp info from {Path}" , video . Path ) ;
2018-12-14 10:40:55 +01:00
}
}
2020-01-06 10:39:01 +01:00
// REVIEW: find out why the byte array needs to be 197 bytes long and comment the reason
2025-08-27 18:34:00 -05:00
private static TransportStreamTimestamp GetMpegTimestamp ( string path )
2018-12-14 10:40:55 +01:00
{
2020-01-02 20:19:01 +01:00
var packetBuffer = new byte [ 197 ] ;
2018-12-14 10:40:55 +01:00
2021-06-12 22:20:35 +02:00
using ( var fs = new FileStream ( path , FileMode . Open , FileAccess . Read , FileShare . Read , 1 ) )
2018-12-14 10:40:55 +01:00
{
2024-11-16 18:11:01 +01:00
fs . ReadExactly ( packetBuffer ) ;
2018-12-14 10:40:55 +01:00
}
if ( packetBuffer [ 0 ] = = 71 )
{
return TransportStreamTimestamp . None ;
}
2021-07-09 02:06:38 +02:00
if ( ( packetBuffer [ 4 ] ! = 71 ) | | ( packetBuffer [ 196 ] ! = 71 ) )
2018-12-14 10:40:55 +01:00
{
2021-07-09 02:06:38 +02:00
return TransportStreamTimestamp . None ;
}
2018-12-14 10:40:55 +01:00
2021-07-09 02:06:38 +02:00
if ( ( packetBuffer [ 0 ] = = 0 ) & & ( packetBuffer [ 1 ] = = 0 ) & & ( packetBuffer [ 2 ] = = 0 ) & & ( packetBuffer [ 3 ] = = 0 ) )
{
return TransportStreamTimestamp . Zero ;
2018-12-14 10:40:55 +01:00
}
2021-07-09 02:06:38 +02:00
return TransportStreamTimestamp . Valid ;
2018-12-14 10:40:55 +01:00
}
2023-10-08 01:16:00 +02:00
[GeneratedRegex("(?<name>.*) \\((?<instrument>.*)\\)")]
private static partial Regex PerformerRegex ( ) ;
2018-12-14 10:40:55 +01:00
}
}