Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
8d0641f
Base frame value objects (refs #119)
WoZ Oct 28, 2025
d38bb17
Fix to BaseFrame, test (refs #119)
WoZ Oct 28, 2025
410d767
Audio and Video frames of different schemes with tests (refs #119)
WoZ Oct 28, 2025
2c1fcfc
processFrames logic was added to deal with value objects + tests (ref…
WoZ Oct 28, 2025
a602aa9
buildFftoolLibVersionsObject + tests (refs #119)
WoZ Oct 29, 2025
21318ee
FramesMonitor received support of fullFrameInfo param + tests (refs #…
WoZ Oct 29, 2025
258ce8c
RawFrameTransformer was added (refs #119)
WoZ Oct 29, 2025
0c9b1c9
new functions and classes were added to index.js (refs #119)
WoZ Oct 30, 2025
2fe848d
Info about changes in 4.0.0 was added to CHANGELOG.md (refs #119)
WoZ Oct 30, 2025
51258c4
Add .DS_Store to .gitignore
WoZ Oct 30, 2025
ba22574
Update calculateFps.test.js to use VideoFrameSchema1
WoZ Oct 30, 2025
9b253d5
Remove invalid frames types from encoderStats.test.js (refs #119)
WoZ Oct 30, 2025
019dac5
Update encoderStats.test.js to use VideoFrameSchema1 and AudioFrameSc…
WoZ Oct 30, 2025
4ef0b94
Update networkStats.test.js to use VideoFrameSchema1 and AudioFrameSc…
WoZ Oct 30, 2025
8a5b856
Add RawFrameTransformer.data.js and RawFrameTransformer.test.js (refs…
WoZ Oct 30, 2025
d11fe22
getCodedPictureNumber and getDisplayPictureNumber were removed from t…
WoZ Oct 31, 2025
aa9fd7a
Updates examples (refs #119)
WoZ Oct 31, 2025
0aedf7a
Update README.md and add FrameSchemaAPI.md (refs #119)
WoZ Oct 31, 2025
e37250f
Merge remote-tracking branch 'origin/gh-119-ffprobe-version-detection…
WoZ Oct 31, 2025
0c91c3f
Unit test fix (refs #119)
WoZ Oct 31, 2025
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ package-lock.json
# MUST be the last line of this file
!.gitkeep

.DS_Store
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
# Changelog

### 4.0.0

BREAKING CHANGES:

- Minimum Node.js version increased from 8.1 to 10
[[GH-119](https://github.com/LCMApps/video-quality-tools/issues/119)]
- `processFrames` functions now support both plain frame objects and value object frames (instances of `BaseFrame` subclasses)
[[GH-119](https://github.com/LCMApps/video-quality-tools/issues/119)]

IMPROVEMENTS:

- Added `FftoolsLibVersions` class to represent FFmpeg/FFprobe library versions with semantic version comparison support
[[GH-119](https://github.com/LCMApps/video-quality-tools/issues/119)]
- Added `buildFftoolLibVersionsObject()` function to detect FFmpeg/FFprobe library versions from the tool's output
[[GH-119](https://github.com/LCMApps/video-quality-tools/issues/119)]
- Added `RawFrameTransformer` class to transform raw frame data into appropriate value objects based on FFmpeg library versions (libavutil 57-60)
[[GH-119](https://github.com/LCMApps/video-quality-tools/issues/119)]
- Added frame value object classes (`BaseFrame`, `BaseVideoFrame`, `BaseAudioFrame`) with schema variations (Schema1-4) to support different FFmpeg versions
[[GH-119](https://github.com/LCMApps/video-quality-tools/issues/119)]
- Added `fullFrameInfo` option to `FramesMonitor` constructor to retrieve all frame fields instead of the default subset
[[GH-119](https://github.com/LCMApps/video-quality-tools/issues/119)]


### 3.0.3

- Fix url in FFmpeg commands.
Expand Down
144 changes: 139 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,120 @@ structure as the `ffprobe -show_streams` output has. You may find a typical outp
disposition: [Object] } ] }
```

# <a name="ffmpeg-compatibility"></a>FFmpeg Version Compatibility

## Raw Frames (Default Behavior)

By default, `FramesMonitor` emits raw frame objects directly from ffprobe output. This approach works seamlessly with **FFmpeg <= 4.x** (`libavutil` <= 56).

Starting from **FFmpeg 5.x** (`libavutil` 57+), ffprobe changed some field names in frame output. If you're using FFmpeg 5.x or newer, you should use the `RawFrameTransformer` approach described below to ensure compatibility.

## Using `RawFrameTransformer` for FFmpeg 5.x+

For FFmpeg 5.x and newer versions, use `RawFrameTransformer` to automatically handle field name differences across FFmpeg versions.

### Basic Usage

```javascript
const {
FramesMonitor,
buildFftoolLibVersionsObject,
RawFrameTransformer
} = require('video-quality-tools');

// Detect FFprobe version
const fftoolLibVersions = await buildFftoolLibVersionsObject('/usr/local/bin/ffprobe');

// Create transformer with detected version
const transformer = new RawFrameTransformer(fftoolLibVersions);

const framesMonitor = new FramesMonitor(options, 'rtmp://host:port/appInstance/name', {
// other options, plus...
fullFrameInfo: true // Required for RawFrameTransformer
});

framesMonitor.on('frame', rawFrame => {
// Transform raw frame to value object
const frame = transformer.transform(rawFrame);

// Use consistent API regardless of FFmpeg version
console.log(frame.getMediaType()); // 'video' or 'audio'
console.log(frame.getKeyFrame()); // 1 or 0
console.log(frame.getPtsTime()); // presentation timestamp
console.log(frame.getPktSize()); // packet size

if (frame.getMediaType() === 'video') {
console.log(frame.getWidth()); // frame width
console.log(frame.getHeight()); // frame height
console.log(frame.getPictType()); // 'I', 'P', or 'B'
}
});

framesMonitor.listen();
```

### Detecting FFmpeg Version

The `buildFftoolLibVersionsObject` function automatically detects your FFmpeg/ffprobe version:

```javascript
const {buildFftoolLibVersionsObject, FftoolsLibVersions} = require('video-quality-tools');

// Detect version
const fftoolLibVersions = await buildFftoolLibVersionsObject('/usr/local/bin/ffprobe');

// Check specific library versions
const libavutilVersion = fftoolLibVersions.getVersion(FftoolsLibVersions.LIBAVUTIL);
console.log(`libavutil version: ${libavutilVersion}`);

// Compare versions
if (fftoolLibVersions.gte(FftoolsLibVersions.LIBAVUTIL, '58.0.0')) {
console.log('FFmpeg 5.x or newer detected');
}
```

### Supported Versions

| FFmpeg Version | libavutil Version | Schema | Status |
|----------------|-------------------|--------|---------|
| FFmpeg 4.x | < 57 | Schema1 | ✅ Supported |
| FFmpeg 5.x | 57.x | Schema2 | ✅ Supported |
| FFmpeg 6.x | 58.x | Schema3 | ✅ Supported |
| FFmpeg 7.x-8.x | 59.x-60.x | Schema4 | ✅ Supported |

For detailed information about frame schema methods and API, see [Frame Schema API Reference](doc/FrameSchemaAPI.md).

### Working with processFrames Functions

The `processFrames` functions (like `encoderStats` and `networkStats`) support both raw frames and frame value objects.

> But raw frames are supported for `libavutil` <= 56, so value objects and RawFrameTransformer is only one recommended
option starting `video-quality-tools` version 4.0.0.

```javascript
const {processFrames, RawFrameTransformer, buildFftoolLibVersionsObject} = require('video-quality-tools');

const fftoolLibVersions = await buildFftoolLibVersionsObject('/usr/local/bin/ffprobe');
const transformer = new RawFrameTransformer(fftoolLibVersions);

let frames = [];

framesMonitor.on('frame', rawFrame => {
// Transform to value object
const frame = transformer.transform(rawFrame);
frames.push(frame);
});

setInterval(() => {
// processFrames works with both raw frames and value objects
const stats = processFrames.networkStats(frames, 5000);
console.log(stats);
frames = [];
}, 5000);
```

For a complete working example, see [examples/rawFrameTransformer.js](examples/rawFrameTransformer.js).

# <a name="one-time-info"></a>Live Frames Monitor

To measure live stream info you need to create instance of `FramesMonitor` class
Expand All @@ -196,7 +310,7 @@ Constructor throws:

## Frames Monitor Config

The first argument of `FramesMonitor` must be an `options` object. All `options` object's fields are mandatory:
The first argument of `FramesMonitor` must be an `options` object. All `options` object's fields are mandatory except `fullFrameInfo`:

* `ffprobePath` - string, path to ffprobe executable;
* `timeoutInMs` - integer, greater than 0, specifies the maximum time to wait for (network) read/write operations
Expand All @@ -212,7 +326,10 @@ process will be hard killed if the attempt of soft stop fails. When you try to s
method the `FramesMonitor` sends `SIGTERM` signal to ffprobe process. ffprobe may ignore this signal (some versions
do it pretty often). If ffprobe doesn't exit after `exitProcessGuardTimeoutInMs` milliseconds, `FramesMonitor` sends
`SIGKILL` signal and forces underlying ffprobe process to exit.
* analyzeDurationInMs - integer, greater than 0, specifies the maximum analyzing time of the input.
* `analyzeDurationInMs` - integer, greater than 0, specifies the maximum analyzing time of the input.
* `fullFrameInfo` - (added in 4.0.0, **optional**) boolean, default: `false`. When set to `true`, retrieves all available frame fields
from ffprobe. This is **required when using `RawFrameTransformer`** for FFmpeg 5.x+ compatibility. When `false`, only
retrieves a subset of fields (`pkt_size`, `pkt_pts_time`, `media_type`, `pict_type`, `key_frame`, `width`, `height`).

## Listening of Frames

Expand Down Expand Up @@ -254,8 +371,10 @@ try {

## `frame` event

This event is generated on each video and audio frame decoded by ffprobe.
The structure of the frame object is the following:
This event is generated on each video and audio frame decoded by ffprobe.

When the option `fullFrameInfo` is not specified or set to `false`, data with a `frame`event will have the following
structure:

```
{ media_type: 'video',
Expand All @@ -274,6 +393,16 @@ or
pkt_size: 20 }
```

With `fullFrameInfo` set to `true` all the fields provided by the `ffprobe` will be present.

Prior version 4.0.0 there wasn't `fullFrameInfo` option, and subset of fields was enough to calculate stats, but
starting from ffmpeg 5.0 (actually, from `libavutil 57`) `ffprobe` and `ffmpeg` started to rename fields, remove
deprecated. `video-quality-tools` stats calculation relies on frame field names, and package stopped working.

It's recommended to switch to version 4.0.0 and use `RawFrameTransfermer` with `fullFrameInfo` set to `true` to
make sure package works as expected. You may read details below.


## `exit` event

Underlying process may not start at all, it may fail after some time or it may be killed with signal. In such situations
Expand Down Expand Up @@ -348,13 +477,18 @@ between receiver and module affects delivery of RTMP packages this module indica
to run this module near the receiver.

```javascript
const {processFrames} = require('video-quality-tools');
const {processFrames, RawFrameTransformer, buildFftoolLibVersionsObject} = require('video-quality-tools');

const INTERVAL_TO_ANALYZE_FRAMES = 5000; // in milliseconds

const fftoolLibVersions = await buildFftoolLibVersionsObject('/usr/local/bin/ffprobe');
const transformer = new RawFrameTransformer(fftoolLibVersions);

let frames = [];

framesMonitor.on('frame', frame => {
// Transform to value object
const frame = transformer.transform(rawFrame);
frames.push(frame);
});

Expand Down
Loading