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
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-08 18:47 +0000
1#!/usr/bin/env python3
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
17 This function will return a pretty string of the format of the container
18 used by a media file.
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
37 Returns
38 -------
39 fmt : str
40 the format as a pretty string
42 Notes
43 -----
44 Copyright 2017 Thomas Guymer [1]_
46 References
47 ----------
48 .. [1] PyGuymer3, https://github.com/Guymer/PyGuymer3
49 """
51 # Import standard modules ...
52 import shutil
54 # Import sub-functions ...
55 from .__ffprobe__ import __ffprobe__
56 from .ffprobe import ffprobe
58 # **************************************************************************
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"
65 # **************************************************************************
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 )
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