Coverage for pyguymer3/media/return_media_format.py: 42%

50 statements  

« prev     ^ index     » next       coverage.py v7.9.2, created at 2025-07-08 18:47 +0000

1#!/usr/bin/env python3 

2 

3# Define function ... 

4def return_media_format( 

5 fname, 

6 /, 

7 *, 

8 cwd = None, 

9 debug = __debug__, 

10 ensureNFC = True, 

11 ffprobePath = None, 

12 playlist = -1, 

13 timeout = 60.0, 

14): 

15 """Return the format of a media file 

16 

17 This function will return a pretty string of the format of the container 

18 used by a media file. 

19 

20 Parameters 

21 ---------- 

22 fname : str 

23 the media file 

24 cwd : str, optional 

25 the directory to change to before running "ffprobe" 

26 debug : bool, optional 

27 print debug messages 

28 ffprobePath : str, optional 

29 the path to the "ffprobe" binary (if not provided then Python will 

30 attempt to find the binary itself) 

31 playlist : int, optional 

32 for media files containing playlists, specify which playlist wants to be 

33 surveyed 

34 timeout : float, optional 

35 the timeout for any requests/subprocess calls 

36 

37 Returns 

38 ------- 

39 fmt : str 

40 the format as a pretty string 

41 

42 Notes 

43 ----- 

44 Copyright 2017 Thomas Guymer [1]_ 

45 

46 References 

47 ---------- 

48 .. [1] PyGuymer3, https://github.com/Guymer/PyGuymer3 

49 """ 

50 

51 # Import standard modules ... 

52 import shutil 

53 

54 # Import sub-functions ... 

55 from .__ffprobe__ import __ffprobe__ 

56 from .ffprobe import ffprobe 

57 

58 # ************************************************************************** 

59 

60 # Try to find the paths if the user did not provide them ... 

61 if ffprobePath is None: 

62 ffprobePath = shutil.which("ffprobe") 

63 assert ffprobePath is not None, "\"ffprobe\" is not installed" 

64 

65 # ************************************************************************** 

66 

67 # Make sure that this fname/playlist combination is in the global dictionary ... 

68 if fname not in __ffprobe__: 

69 __ffprobe__[fname] = {} 

70 if playlist not in __ffprobe__[fname]: 

71 if debug: 

72 print(f"INFO: Running ffprobe(\"{fname}\", {playlist:d}) ...") 

73 __ffprobe__[fname][playlist] = ffprobe( 

74 fname, 

75 cwd = cwd, 

76 ensureNFC = ensureNFC, 

77 ffprobePath = ffprobePath, 

78 playlist = playlist, 

79 timeout = timeout, 

80 ) 

81 

82 # Determine the format of the file container ... 

83 # NOTE: Unhelpfully, "ffprobe" returns "mov,mp4,m4a,3gp,3g2,mj2" for both 

84 # proprietary Apple QuickTime MOV files and ISO standard MP4 files. To 

85 # find out what sort of file it is, the "major_brand" must be studied 

86 # too. See these references: 

87 # * "ISO Base Media File Format", https://www.loc.gov/preservation/digital/formats/fdd/fdd000079.shtml 

88 # * "MPEG-4 File Format, Version 1", https://www.loc.gov/preservation/digital/formats/fdd/fdd000037.shtml 

89 # * "MPEG-4 File Format, Version 2", https://www.loc.gov/preservation/digital/formats/fdd/fdd000155.shtml 

90 match __ffprobe__[fname][playlist]["format"]["format_name"]: 

91 case "asf": 

92 return "ASF" 

93 case "avi": 

94 return "AVI" 

95 case "flac": 

96 return "FLAC" 

97 case "flv": 

98 return "FLV" 

99 case "mov,mp4,m4a,3gp,3g2,mj2": 

100 match __ffprobe__[fname][playlist]["format"]["tags"].get("major_brand", "qt "): 

101 case "3gp4" | "3gp5" | "3gp6": 

102 return "3GPP" 

103 case "3g2a" | "3g2b": 

104 return "3GPP2" 

105 case "isom": 

106 return "MP4 (ISO/IEC 14496-12)" 

107 case "M4A ": 

108 # NOTE: By reading "libavformat/movenc.c" in the "ffmpeg" 

109 # Git repository on 19/July/2024, the "ipod" format is 

110 # the same as the "mp4" format but it contains a 

111 # "uuid" atom to enable it to play on certain devices. 

112 return "iPod-Compatible M4A (ISO/IEC 14496-12)" 

113 case "M4V ": 

114 # NOTE: By reading "libavformat/movenc.c" in the "ffmpeg" 

115 # Git repository on 19/July/2024, the "ipod" format is 

116 # the same as the "mp4" format but it contains a 

117 # "uuid" atom to enable it to play on certain devices. 

118 return "iPod-Compatible M4V (ISO/IEC 14496-12)" 

119 case "mp41": 

120 return "MP4 (ISO/IEC 14496-1:2001)" 

121 case "mp42": 

122 return "MP4 (ISO/IEC 14496-14:2003)" 

123 case "qt ": 

124 return "MOV" 

125 case _: 

126 raise ValueError(f'\"format::tags::major_brand\" is an unexpected value ({repr(__ffprobe__[fname][playlist]["format"]["tags"]["major_brand"])})') from None 

127 case "mp3": 

128 return "MP3" 

129 case "ogg": 

130 return "OGG" 

131 case "swf": 

132 return "SWF" 

133 case _: 

134 raise ValueError(f'\"format::format_name\" is an unexpected value ({repr(__ffprobe__[fname][playlist]["format"]["format_name"])})') from None