ffmpeg-progress 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +19 -0
  2. package/core.d.ts +14 -1
  3. package/core.js +68 -0
  4. package/package.json +1 -1
package/README.md CHANGED
@@ -42,6 +42,15 @@ await convertFile({
42
42
  timer.end()
43
43
  ```
44
44
 
45
+ **Get video resolution**:
46
+
47
+ ```typescript
48
+ import { getVideoResolution } from 'ffmpeg-progress'
49
+
50
+ console.log(await getVideoResolution('test/rotate.mp4'))
51
+ // { width: 3024, height: 4032 }
52
+ ```
53
+
45
54
  ## Typescript Types
46
55
 
47
56
  ```typescript
@@ -88,6 +97,16 @@ export function attachChildProcess(
88
97
  childProcess: ChildProcessWithoutNullStreams
89
98
  } & ProgressArgs,
90
99
  ): Promise<void>
100
+
101
+ /**
102
+ * take a image frame from the video,
103
+ * this is more accurate than parsing the resolution string in ffmpeg,
104
+ * because the video has rotation metadata.
105
+ */
106
+ export function getVideoResolution(video_file: string): Promise<{
107
+ width: number
108
+ height: number
109
+ }>
91
110
  ```
92
111
 
93
112
  ## License
package/core.d.ts CHANGED
@@ -15,7 +15,11 @@ export type ScanVideoResult = {
15
15
  duration: string;
16
16
  /** @description e.g. 180.03 or 0 */
17
17
  seconds: number;
18
- /** @description e.g. "4032x3024" */
18
+ /**
19
+ * @description e.g. "4032x3024"
20
+ * This is the stored resolution of the video, not the resolution of the video when it is played.
21
+ * The display image may be rotated if there are rotation metadata in the video.
22
+ */
19
23
  resolution: string | null;
20
24
  /** @description e.g. 44100 for 44.1kHz */
21
25
  audioSampleRate: number | null;
@@ -49,3 +53,12 @@ export declare function estimateOutSize(args: {
49
53
  currentSeconds: number;
50
54
  totalSeconds: number;
51
55
  }): number;
56
+ /**
57
+ * take a image frame from the video,
58
+ * this is more accurate than parsing the resolution string in ffmpeg,
59
+ * because the video has rotation metadata.
60
+ */
61
+ export declare function getVideoResolution(video_file: string): Promise<{
62
+ width: number;
63
+ height: number;
64
+ }>;
package/core.js CHANGED
@@ -7,7 +7,10 @@ exports.scanVideo = scanVideo;
7
7
  exports.convertFile = convertFile;
8
8
  exports.attachChildProcess = attachChildProcess;
9
9
  exports.estimateOutSize = estimateOutSize;
10
+ exports.getVideoResolution = getVideoResolution;
10
11
  const child_process_1 = require("child_process");
12
+ const promises_1 = require("fs/promises");
13
+ const path_1 = require("path");
11
14
  /** @description
12
15
  * from "00:01:00.03" to 60.03;
13
16
  * from "N/A" to NaN;
@@ -194,3 +197,68 @@ function estimateOutSize(args) {
194
197
  let estimatedOutSize = args.currentOutSize + estimatedRate * remindSeconds;
195
198
  return estimatedOutSize;
196
199
  }
200
+ /**
201
+ * take a image frame from the video,
202
+ * this is more accurate than parsing the resolution string in ffmpeg,
203
+ * because the video has rotation metadata.
204
+ */
205
+ async function getVideoResolution(video_file) {
206
+ let image_file = (0, path_1.join)('/tmp/', (0, path_1.basename)(video_file) + '.jpg');
207
+ // ffmpeg -ss 0 -i video.mp4 -frames:v 1 -f image2 -update 1 -y image.jpg
208
+ let childProcess = (0, child_process_1.spawn)('ffmpeg', [
209
+ '-ss',
210
+ '0',
211
+ '-i',
212
+ video_file,
213
+ '-frames:v',
214
+ '1',
215
+ '-f',
216
+ 'image2',
217
+ '-update',
218
+ '1',
219
+ '-y',
220
+ image_file,
221
+ ]);
222
+ var { stdout, stderr, code, signal } = await waitChildProcess(childProcess);
223
+ if (code != 0) {
224
+ throw new Error(`ffmpeg exit abnormally, exit code: ${code}, signal: ${signal}, stdout: ${stdout}, stderr: ${stderr}`);
225
+ }
226
+ childProcess = (0, child_process_1.spawn)('file', [image_file]);
227
+ var { stdout, stderr, code, signal } = await waitChildProcess(childProcess);
228
+ if (code != 0) {
229
+ throw new Error(`file exit abnormally, exit code: ${code}, signal: ${signal}, stdout: ${stdout}, stderr: ${stderr}`);
230
+ }
231
+ let resolution = parseImageResolution(stdout);
232
+ await (0, promises_1.unlink)(image_file);
233
+ return resolution;
234
+ }
235
+ function waitChildProcess(childProcess) {
236
+ return new Promise((resolve, reject) => {
237
+ let stdout = '';
238
+ let stderr = '';
239
+ childProcess.stdout.on('data', (data) => {
240
+ stdout += data.toString();
241
+ });
242
+ childProcess.stderr.on('data', (data) => {
243
+ stderr += data.toString();
244
+ });
245
+ childProcess.on('exit', (code, signal) => {
246
+ resolve({ stdout, stderr, code, signal });
247
+ });
248
+ });
249
+ }
250
+ // e.g. sample.jpg: JPEG image data, baseline, precision 8, 3024x4032, components 3
251
+ function parseImageResolution(text) {
252
+ let parts = text.split(', ').reverse();
253
+ for (let part of parts) {
254
+ let parts = part.split('x');
255
+ if (parts.length == 2) {
256
+ let width = +parts[0];
257
+ let height = +parts[1];
258
+ if (width && height) {
259
+ return { width, height };
260
+ }
261
+ }
262
+ }
263
+ throw new Error('failed to parse image resolution: ' + JSON.stringify(text));
264
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ffmpeg-progress",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Extract progress from ffmpeg child_process",
5
5
  "keywords": [
6
6
  "ffmpeg",