aboutsummaryrefslogtreecommitdiffhomepage
path: root/shared/extra-utils/ffprobe.ts
diff options
context:
space:
mode:
Diffstat (limited to 'shared/extra-utils/ffprobe.ts')
-rw-r--r--shared/extra-utils/ffprobe.ts96
1 files changed, 41 insertions, 55 deletions
diff --git a/shared/extra-utils/ffprobe.ts b/shared/extra-utils/ffprobe.ts
index 53a3aa001..dfacd251c 100644
--- a/shared/extra-utils/ffprobe.ts
+++ b/shared/extra-utils/ffprobe.ts
@@ -17,12 +17,22 @@ function ffprobePromise (path: string) {
17 }) 17 })
18} 18}
19 19
20// ---------------------------------------------------------------------------
21// Audio
22// ---------------------------------------------------------------------------
23
20async function isAudioFile (path: string, existingProbe?: FfprobeData) { 24async function isAudioFile (path: string, existingProbe?: FfprobeData) {
21 const videoStream = await getVideoStreamFromFile(path, existingProbe) 25 const videoStream = await getVideoStream(path, existingProbe)
22 26
23 return !videoStream 27 return !videoStream
24} 28}
25 29
30async function hasAudioStream (path: string, existingProbe?: FfprobeData) {
31 const { audioStream } = await getAudioStream(path, existingProbe)
32
33 return !!audioStream
34}
35
26async function getAudioStream (videoPath: string, existingProbe?: FfprobeData) { 36async function getAudioStream (videoPath: string, existingProbe?: FfprobeData) {
27 // without position, ffprobe considers the last input only 37 // without position, ffprobe considers the last input only
28 // we make it consider the first input only 38 // we make it consider the first input only
@@ -78,29 +88,26 @@ function getMaxAudioBitrate (type: 'aac' | 'mp3' | string, bitrate: number) {
78 } 88 }
79} 89}
80 90
81async function getVideoStreamSize (path: string, existingProbe?: FfprobeData): Promise<{ width: number, height: number }> { 91// ---------------------------------------------------------------------------
82 const videoStream = await getVideoStreamFromFile(path, existingProbe) 92// Video
83 93// ---------------------------------------------------------------------------
84 return videoStream === null
85 ? { width: 0, height: 0 }
86 : { width: videoStream.width, height: videoStream.height }
87}
88 94
89async function getVideoFileResolution (path: string, existingProbe?: FfprobeData) { 95async function getVideoStreamDimensionsInfo (path: string, existingProbe?: FfprobeData) {
90 const size = await getVideoStreamSize(path, existingProbe) 96 const videoStream = await getVideoStream(path, existingProbe)
97 if (!videoStream) return undefined
91 98
92 return { 99 return {
93 width: size.width, 100 width: videoStream.width,
94 height: size.height, 101 height: videoStream.height,
95 ratio: Math.max(size.height, size.width) / Math.min(size.height, size.width), 102 ratio: Math.max(videoStream.height, videoStream.width) / Math.min(videoStream.height, videoStream.width),
96 resolution: Math.min(size.height, size.width), 103 resolution: Math.min(videoStream.height, videoStream.width),
97 isPortraitMode: size.height > size.width 104 isPortraitMode: videoStream.height > videoStream.width
98 } 105 }
99} 106}
100 107
101async function getVideoFileFPS (path: string, existingProbe?: FfprobeData) { 108async function getVideoStreamFPS (path: string, existingProbe?: FfprobeData) {
102 const videoStream = await getVideoStreamFromFile(path, existingProbe) 109 const videoStream = await getVideoStream(path, existingProbe)
103 if (videoStream === null) return 0 110 if (!videoStream) return 0
104 111
105 for (const key of [ 'avg_frame_rate', 'r_frame_rate' ]) { 112 for (const key of [ 'avg_frame_rate', 'r_frame_rate' ]) {
106 const valuesText: string = videoStream[key] 113 const valuesText: string = videoStream[key]
@@ -116,19 +123,19 @@ async function getVideoFileFPS (path: string, existingProbe?: FfprobeData) {
116 return 0 123 return 0
117} 124}
118 125
119async function getMetadataFromFile (path: string, existingProbe?: FfprobeData) { 126async function buildFileMetadata (path: string, existingProbe?: FfprobeData) {
120 const metadata = existingProbe || await ffprobePromise(path) 127 const metadata = existingProbe || await ffprobePromise(path)
121 128
122 return new VideoFileMetadata(metadata) 129 return new VideoFileMetadata(metadata)
123} 130}
124 131
125async function getVideoFileBitrate (path: string, existingProbe?: FfprobeData): Promise<number> { 132async function getVideoStreamBitrate (path: string, existingProbe?: FfprobeData): Promise<number> {
126 const metadata = await getMetadataFromFile(path, existingProbe) 133 const metadata = await buildFileMetadata(path, existingProbe)
127 134
128 let bitrate = metadata.format.bit_rate as number 135 let bitrate = metadata.format.bit_rate as number
129 if (bitrate && !isNaN(bitrate)) return bitrate 136 if (bitrate && !isNaN(bitrate)) return bitrate
130 137
131 const videoStream = await getVideoStreamFromFile(path, existingProbe) 138 const videoStream = await getVideoStream(path, existingProbe)
132 if (!videoStream) return undefined 139 if (!videoStream) return undefined
133 140
134 bitrate = videoStream?.bit_rate 141 bitrate = videoStream?.bit_rate
@@ -137,51 +144,30 @@ async function getVideoFileBitrate (path: string, existingProbe?: FfprobeData):
137 return undefined 144 return undefined
138} 145}
139 146
140async function getDurationFromVideoFile (path: string, existingProbe?: FfprobeData) { 147async function getVideoStreamDuration (path: string, existingProbe?: FfprobeData) {
141 const metadata = await getMetadataFromFile(path, existingProbe) 148 const metadata = await buildFileMetadata(path, existingProbe)
142 149
143 return Math.round(metadata.format.duration) 150 return Math.round(metadata.format.duration)
144} 151}
145 152
146async function getVideoStreamFromFile (path: string, existingProbe?: FfprobeData) { 153async function getVideoStream (path: string, existingProbe?: FfprobeData) {
147 const metadata = await getMetadataFromFile(path, existingProbe) 154 const metadata = await buildFileMetadata(path, existingProbe)
148
149 return metadata.streams.find(s => s.codec_type === 'video') || null
150}
151
152async function canDoQuickAudioTranscode (path: string, probe?: FfprobeData): Promise<boolean> {
153 const parsedAudio = await getAudioStream(path, probe)
154
155 if (!parsedAudio.audioStream) return true
156
157 if (parsedAudio.audioStream['codec_name'] !== 'aac') return false
158
159 const audioBitrate = parsedAudio.bitrate
160 if (!audioBitrate) return false
161
162 const maxAudioBitrate = getMaxAudioBitrate('aac', audioBitrate)
163 if (maxAudioBitrate !== -1 && audioBitrate > maxAudioBitrate) return false
164
165 const channelLayout = parsedAudio.audioStream['channel_layout']
166 // Causes playback issues with Chrome
167 if (!channelLayout || channelLayout === 'unknown') return false
168 155
169 return true 156 return metadata.streams.find(s => s.codec_type === 'video')
170} 157}
171 158
172// --------------------------------------------------------------------------- 159// ---------------------------------------------------------------------------
173 160
174export { 161export {
175 getVideoStreamSize, 162 getVideoStreamDimensionsInfo,
176 getVideoFileResolution, 163 buildFileMetadata,
177 getMetadataFromFile,
178 getMaxAudioBitrate, 164 getMaxAudioBitrate,
179 getVideoStreamFromFile, 165 getVideoStream,
180 getDurationFromVideoFile, 166 getVideoStreamDuration,
181 getAudioStream, 167 getAudioStream,
182 getVideoFileFPS, 168 getVideoStreamFPS,
183 isAudioFile, 169 isAudioFile,
184 ffprobePromise, 170 ffprobePromise,
185 getVideoFileBitrate, 171 getVideoStreamBitrate,
186 canDoQuickAudioTranscode 172 hasAudioStream
187} 173}