ffmpeg-progress 1.3.0 → 1.5.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 +31 -0
  2. package/core.d.ts +16 -1
  3. package/core.js +90 -0
  4. package/package.json +1 -1
package/README.md CHANGED
@@ -42,6 +42,24 @@ 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
+
54
+ **Get video duration in seconds**:
55
+
56
+ ```typescript
57
+ import { getVideoDuration } from 'ffmpeg-progress'
58
+
59
+ console.log(await getVideoDuration('test/in.mp4'))
60
+ // 15.04 (duration in seconds)
61
+ ```
62
+
45
63
  ## Typescript Types
46
64
 
47
65
  ```typescript
@@ -88,6 +106,19 @@ export function attachChildProcess(
88
106
  childProcess: ChildProcessWithoutNullStreams
89
107
  } & ProgressArgs,
90
108
  ): Promise<void>
109
+
110
+ /**
111
+ * take a image frame from the video,
112
+ * this is more accurate than parsing the resolution string in ffmpeg,
113
+ * because the video has rotation metadata.
114
+ */
115
+ export function getVideoResolution(video_file: string): Promise<{
116
+ width: number
117
+ height: number
118
+ }>
119
+
120
+ /** @description get video duration in seconds, e.g. `15.04` */
121
+ export async function getVideoDuration(video_file: string): Promise<number>
91
122
  ```
92
123
 
93
124
  ## 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,14 @@ 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
+ }>;
65
+ /** @description get video duration in seconds, e.g. `15.04` */
66
+ export declare function getVideoDuration(video_file: string): Promise<number>;
package/core.js CHANGED
@@ -7,7 +7,11 @@ exports.scanVideo = scanVideo;
7
7
  exports.convertFile = convertFile;
8
8
  exports.attachChildProcess = attachChildProcess;
9
9
  exports.estimateOutSize = estimateOutSize;
10
+ exports.getVideoResolution = getVideoResolution;
11
+ exports.getVideoDuration = getVideoDuration;
10
12
  const child_process_1 = require("child_process");
13
+ const promises_1 = require("fs/promises");
14
+ const path_1 = require("path");
11
15
  /** @description
12
16
  * from "00:01:00.03" to 60.03;
13
17
  * from "N/A" to NaN;
@@ -194,3 +198,89 @@ function estimateOutSize(args) {
194
198
  let estimatedOutSize = args.currentOutSize + estimatedRate * remindSeconds;
195
199
  return estimatedOutSize;
196
200
  }
201
+ /**
202
+ * take a image frame from the video,
203
+ * this is more accurate than parsing the resolution string in ffmpeg,
204
+ * because the video has rotation metadata.
205
+ */
206
+ async function getVideoResolution(video_file) {
207
+ let image_file = (0, path_1.join)('/tmp/', (0, path_1.basename)(video_file) + '.jpg');
208
+ // ffmpeg -ss 0 -i video.mp4 -frames:v 1 -f image2 -update 1 -y image.jpg
209
+ let childProcess = (0, child_process_1.spawn)('ffmpeg', [
210
+ '-ss',
211
+ '0',
212
+ '-i',
213
+ video_file,
214
+ '-frames:v',
215
+ '1',
216
+ '-f',
217
+ 'image2',
218
+ '-update',
219
+ '1',
220
+ '-y',
221
+ image_file,
222
+ ]);
223
+ var { stdout, stderr, code, signal } = await waitChildProcess(childProcess);
224
+ if (code != 0) {
225
+ throw new Error(`ffmpeg exit abnormally, exit code: ${code}, signal: ${signal}, stdout: ${stdout}, stderr: ${stderr}`);
226
+ }
227
+ childProcess = (0, child_process_1.spawn)('file', [image_file]);
228
+ var { stdout, stderr, code, signal } = await waitChildProcess(childProcess);
229
+ if (code != 0) {
230
+ throw new Error(`file exit abnormally, exit code: ${code}, signal: ${signal}, stdout: ${stdout}, stderr: ${stderr}`);
231
+ }
232
+ let resolution = parseImageResolution(stdout);
233
+ await (0, promises_1.unlink)(image_file);
234
+ return resolution;
235
+ }
236
+ /** @description get video duration in seconds, e.g. `15.04` */
237
+ async function getVideoDuration(video_file) {
238
+ let childProcess = (0, child_process_1.spawn)('ffprobe', [
239
+ '-v',
240
+ 'error',
241
+ '-show_entries',
242
+ 'format=duration',
243
+ '-of',
244
+ 'default=noprint_wrappers=1:nokey=1',
245
+ video_file,
246
+ ]);
247
+ var { stdout, stderr, code, signal } = await waitChildProcess(childProcess);
248
+ if (code != 0) {
249
+ throw new Error(`ffprobe exit abnormally, exit code: ${code}, signal: ${signal}, stdout: ${stdout}, stderr: ${stderr}`);
250
+ }
251
+ let duration = +stdout;
252
+ if (!duration) {
253
+ throw new Error('failed to parse video duration: ' + JSON.stringify(stdout));
254
+ }
255
+ return duration;
256
+ }
257
+ function waitChildProcess(childProcess) {
258
+ return new Promise((resolve, reject) => {
259
+ let stdout = '';
260
+ let stderr = '';
261
+ childProcess.stdout.on('data', (data) => {
262
+ stdout += data.toString();
263
+ });
264
+ childProcess.stderr.on('data', (data) => {
265
+ stderr += data.toString();
266
+ });
267
+ childProcess.on('exit', (code, signal) => {
268
+ resolve({ stdout, stderr, code, signal });
269
+ });
270
+ });
271
+ }
272
+ // e.g. sample.jpg: JPEG image data, baseline, precision 8, 3024x4032, components 3
273
+ function parseImageResolution(text) {
274
+ let parts = text.split(', ').reverse();
275
+ for (let part of parts) {
276
+ let parts = part.split('x');
277
+ if (parts.length == 2) {
278
+ let width = +parts[0];
279
+ let height = +parts[1];
280
+ if (width && height) {
281
+ return { width, height };
282
+ }
283
+ }
284
+ }
285
+ throw new Error('failed to parse image resolution: ' + JSON.stringify(text));
286
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ffmpeg-progress",
3
- "version": "1.3.0",
3
+ "version": "1.5.0",
4
4
  "description": "Extract progress from ffmpeg child_process",
5
5
  "keywords": [
6
6
  "ffmpeg",