1+ import json
2+ import re
3+ import subprocess
4+
5+ from pydub .utils import (
6+ get_prober_name ,
7+ fsdecode ,
8+ _fd_or_path_or_tempfile ,
9+ get_extra_info ,
10+ )
11+
12+ from src .qt .helpers .silent_popen import promptless_Popen
13+
14+ def _mediainfo_json (filepath , read_ahead_limit = - 1 ):
15+ """Return json dictionary with media info(codec, duration, size, bitrate...) from filepath
16+ """
17+ prober = get_prober_name ()
18+ command_args = [
19+ "-v" , "info" ,
20+ "-show_format" ,
21+ "-show_streams" ,
22+ ]
23+ try :
24+ command_args += [fsdecode (filepath )]
25+ stdin_parameter = None
26+ stdin_data = None
27+ except TypeError :
28+ if prober == 'ffprobe' :
29+ command_args += ["-read_ahead_limit" , str (read_ahead_limit ),
30+ "cache:pipe:0" ]
31+ else :
32+ command_args += ["-" ]
33+ stdin_parameter = subprocess .PIPE
34+ file , close_file = _fd_or_path_or_tempfile (filepath , 'rb' , tempfile = False )
35+ file .seek (0 )
36+ stdin_data = file .read ()
37+ if close_file :
38+ file .close ()
39+
40+ command = [prober , '-of' , 'json' ] + command_args
41+ # PATCHED
42+ res = promptless_Popen (command , stdin = stdin_parameter , stdout = subprocess .PIPE , stderr = subprocess .PIPE )
43+ output , stderr = res .communicate (input = stdin_data )
44+ output = output .decode ("utf-8" , 'ignore' )
45+ stderr = stderr .decode ("utf-8" , 'ignore' )
46+
47+ try :
48+ info = json .loads (output )
49+ except json .decoder .JSONDecodeError :
50+ # If ffprobe didn't give any information, just return it
51+ # (for example, because the file doesn't exist)
52+ return None
53+ if not info :
54+ return info
55+
56+ extra_info = get_extra_info (stderr )
57+
58+ audio_streams = [x for x in info ['streams' ] if x ['codec_type' ] == 'audio' ]
59+ if len (audio_streams ) == 0 :
60+ return info
61+
62+ # We just operate on the first audio stream in case there are more
63+ stream = audio_streams [0 ]
64+
65+ def set_property (stream , prop , value ):
66+ if prop not in stream or stream [prop ] == 0 :
67+ stream [prop ] = value
68+
69+ for token in extra_info [stream ['index' ]]:
70+ m = re .match (r'([su]([0-9]{1,2})p?) \(([0-9]{1,2}) bit\)$' , token )
71+ m2 = re .match (r'([su]([0-9]{1,2})p?)( \(default\))?$' , token )
72+ if m :
73+ set_property (stream , 'sample_fmt' , m .group (1 ))
74+ set_property (stream , 'bits_per_sample' , int (m .group (2 )))
75+ set_property (stream , 'bits_per_raw_sample' , int (m .group (3 )))
76+ elif m2 :
77+ set_property (stream , 'sample_fmt' , m2 .group (1 ))
78+ set_property (stream , 'bits_per_sample' , int (m2 .group (2 )))
79+ set_property (stream , 'bits_per_raw_sample' , int (m2 .group (2 )))
80+ elif re .match (r'(flt)p?( \(default\))?$' , token ):
81+ set_property (stream , 'sample_fmt' , token )
82+ set_property (stream , 'bits_per_sample' , 32 )
83+ set_property (stream , 'bits_per_raw_sample' , 32 )
84+ elif re .match (r'(dbl)p?( \(default\))?$' , token ):
85+ set_property (stream , 'sample_fmt' , token )
86+ set_property (stream , 'bits_per_sample' , 64 )
87+ set_property (stream , 'bits_per_raw_sample' , 64 )
88+ return info
0 commit comments