@vidtreo/recorder 1.7.11 → 1.7.12
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.
- package/dist/index.d.ts +2773 -2745
- package/dist/index.js +381 -99
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6451,7 +6451,7 @@ function resolveDeviceError(input) {
|
|
|
6451
6451
|
// package.json
|
|
6452
6452
|
var package_default = {
|
|
6453
6453
|
name: "@vidtreo/recorder",
|
|
6454
|
-
version: "1.7.
|
|
6454
|
+
version: "1.7.12",
|
|
6455
6455
|
type: "module",
|
|
6456
6456
|
description: "Vidtreo SDK for browser-based video recording and transcoding. Features include camera/screen recording, real-time MP4 transcoding, audio level analysis, mute/pause controls, source switching, device selection, and automatic backend uploads. Similar to Ziggeo and Addpipe, Vidtreo provides enterprise-grade video processing capabilities for web applications.",
|
|
6457
6457
|
main: "./dist/index.js",
|
|
@@ -8881,12 +8881,14 @@ var workerCode = `(() => {
|
|
|
8881
8881
|
}
|
|
8882
8882
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
8883
8883
|
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
8884
|
-
|
|
8885
|
-
|
|
8886
|
-
|
|
8887
|
-
|
|
8888
|
-
|
|
8889
|
-
|
|
8884
|
+
if (mod && typeof mod === "object" || typeof mod === "function") {
|
|
8885
|
+
for (let key of __getOwnPropNames(mod))
|
|
8886
|
+
if (!__hasOwnProp.call(to, key))
|
|
8887
|
+
__defProp(to, key, {
|
|
8888
|
+
get: __accessProp.bind(mod, key),
|
|
8889
|
+
enumerable: true
|
|
8890
|
+
});
|
|
8891
|
+
}
|
|
8890
8892
|
if (canCache)
|
|
8891
8893
|
cache.set(mod, to);
|
|
8892
8894
|
return to;
|
|
@@ -8932,8 +8934,8 @@ var workerCode = `(() => {
|
|
|
8932
8934
|
// src/core/processor/worker/recorder-worker.ts
|
|
8933
8935
|
var exports_recorder_worker = {};
|
|
8934
8936
|
__export(exports_recorder_worker, {
|
|
8935
|
-
|
|
8936
|
-
|
|
8937
|
+
RecorderWorker: () => RecorderWorker,
|
|
8938
|
+
initializeRecorderWorker: () => initializeRecorderWorker
|
|
8937
8939
|
});
|
|
8938
8940
|
|
|
8939
8941
|
// ../../node_modules/.bun/mediabunny@1.45.2/node_modules/mediabunny/dist/modules/src/misc.js
|
|
@@ -22899,7 +22901,272 @@ class StreamProcessor {
|
|
|
22899
22901
|
}
|
|
22900
22902
|
|
|
22901
22903
|
// src/core/transcode/deferred-video-transcoder.ts
|
|
22902
|
-
import { ALL_FORMATS as
|
|
22904
|
+
import { ALL_FORMATS as ALL_FORMATS3, BlobSource as BlobSource4, EncodedPacketSink as EncodedPacketSink2, Input as Input4 } from "mediabunny";
|
|
22905
|
+
|
|
22906
|
+
// src/core/transcode/deferred-video-timing-repair.ts
|
|
22907
|
+
import {
|
|
22908
|
+
ALL_FORMATS as ALL_FORMATS2,
|
|
22909
|
+
BlobSource as BlobSource3,
|
|
22910
|
+
BufferTarget as BufferTarget2,
|
|
22911
|
+
EncodedAudioPacketSource,
|
|
22912
|
+
EncodedPacketSink,
|
|
22913
|
+
EncodedVideoPacketSource,
|
|
22914
|
+
Input as Input3,
|
|
22915
|
+
Mp4OutputFormat as Mp4OutputFormat2,
|
|
22916
|
+
Output as Output2
|
|
22917
|
+
} from "mediabunny";
|
|
22918
|
+
var MINIMUM_IMPLAUSIBLE_DURATION_SECONDS = 60;
|
|
22919
|
+
var EXPECTED_DURATION_MULTIPLIER = 2;
|
|
22920
|
+
var MAXIMUM_REPAIR_RATIO = 0.05;
|
|
22921
|
+
var MINIMUM_REPAIR_LIMIT = 2;
|
|
22922
|
+
var MAXIMUM_BOUNDARY_REGRESSION_MULTIPLIER = 2;
|
|
22923
|
+
var MINIMUM_BOUNDARY_REGRESSION_TOLERANCE_SECONDS = 0.25;
|
|
22924
|
+
function resolveImplausibleDurationThreshold(expectedDurationSeconds) {
|
|
22925
|
+
return Math.max(MINIMUM_IMPLAUSIBLE_DURATION_SECONDS, expectedDurationSeconds * EXPECTED_DURATION_MULTIPLIER);
|
|
22926
|
+
}
|
|
22927
|
+
function resolveMedian(values) {
|
|
22928
|
+
values.sort((left, right) => left - right);
|
|
22929
|
+
return values[Math.floor(values.length / 2)];
|
|
22930
|
+
}
|
|
22931
|
+
function validatePacketTimings(packets, expectedDurationSeconds) {
|
|
22932
|
+
if (!Number.isFinite(expectedDurationSeconds) || expectedDurationSeconds < 0) {
|
|
22933
|
+
throw new Error("Timing repair requires a valid recording duration");
|
|
22934
|
+
}
|
|
22935
|
+
if (packets.length === 0) {
|
|
22936
|
+
throw new Error("Timing repair requires video packets");
|
|
22937
|
+
}
|
|
22938
|
+
for (const packet of packets) {
|
|
22939
|
+
if (!Number.isFinite(packet.timestamp)) {
|
|
22940
|
+
throw new Error("Timing repair requires finite packet timestamps");
|
|
22941
|
+
}
|
|
22942
|
+
if (!Number.isFinite(packet.duration) || packet.duration < 0) {
|
|
22943
|
+
throw new Error("Timing repair requires valid packet durations");
|
|
22944
|
+
}
|
|
22945
|
+
}
|
|
22946
|
+
}
|
|
22947
|
+
function createDeferredVideoTimingRepairPlan(packets, expectedDurationSeconds) {
|
|
22948
|
+
validatePacketTimings(packets, expectedDurationSeconds);
|
|
22949
|
+
const threshold = resolveImplausibleDurationThreshold(expectedDurationSeconds);
|
|
22950
|
+
const packetTimings = packets.map((packet) => ({
|
|
22951
|
+
duration: packet.duration,
|
|
22952
|
+
isDurationRepaired: false,
|
|
22953
|
+
isTimestampRepaired: false,
|
|
22954
|
+
timestamp: packet.timestamp
|
|
22955
|
+
}));
|
|
22956
|
+
const repairIndexes = [];
|
|
22957
|
+
const validDurations = [];
|
|
22958
|
+
for (let index = 0;index < packets.length; index += 1) {
|
|
22959
|
+
const duration = packets[index].duration;
|
|
22960
|
+
if (duration > threshold) {
|
|
22961
|
+
repairIndexes.push(index);
|
|
22962
|
+
continue;
|
|
22963
|
+
}
|
|
22964
|
+
if (duration > 0) {
|
|
22965
|
+
validDurations.push(duration);
|
|
22966
|
+
}
|
|
22967
|
+
}
|
|
22968
|
+
if (repairIndexes.length === 0) {
|
|
22969
|
+
return {
|
|
22970
|
+
nominalDurationSeconds: null,
|
|
22971
|
+
packetTimings,
|
|
22972
|
+
repairedDurationCount: 0,
|
|
22973
|
+
repairedTimestampCount: 0
|
|
22974
|
+
};
|
|
22975
|
+
}
|
|
22976
|
+
const maximumRepairCount = Math.max(MINIMUM_REPAIR_LIMIT, Math.floor(packets.length * MAXIMUM_REPAIR_RATIO));
|
|
22977
|
+
if (repairIndexes.length > maximumRepairCount) {
|
|
22978
|
+
throw new Error("Video timing corruption is not isolated");
|
|
22979
|
+
}
|
|
22980
|
+
if (validDurations.length === 0) {
|
|
22981
|
+
throw new Error("Video timing recovery requires a valid source cadence");
|
|
22982
|
+
}
|
|
22983
|
+
for (let index = 1;index < repairIndexes.length; index += 1) {
|
|
22984
|
+
if (repairIndexes[index] - repairIndexes[index - 1] === 1) {
|
|
22985
|
+
throw new Error("Video timing corruption is not isolated");
|
|
22986
|
+
}
|
|
22987
|
+
}
|
|
22988
|
+
const nominalDurationSeconds = resolveMedian(validDurations);
|
|
22989
|
+
for (const index of repairIndexes) {
|
|
22990
|
+
packetTimings[index].duration = nominalDurationSeconds;
|
|
22991
|
+
packetTimings[index].isDurationRepaired = true;
|
|
22992
|
+
}
|
|
22993
|
+
let repairedTimestampCount = 0;
|
|
22994
|
+
const maximumBoundaryRegression = Math.max(MINIMUM_BOUNDARY_REGRESSION_TOLERANCE_SECONDS, nominalDurationSeconds * MAXIMUM_BOUNDARY_REGRESSION_MULTIPLIER);
|
|
22995
|
+
for (const index of repairIndexes) {
|
|
22996
|
+
const boundaryIndex = index + 1;
|
|
22997
|
+
if (boundaryIndex >= packetTimings.length) {
|
|
22998
|
+
continue;
|
|
22999
|
+
}
|
|
23000
|
+
const repairedPacket = packetTimings[index];
|
|
23001
|
+
const boundaryPacket = packetTimings[boundaryIndex];
|
|
23002
|
+
if (boundaryPacket.timestamp >= repairedPacket.timestamp) {
|
|
23003
|
+
continue;
|
|
23004
|
+
}
|
|
23005
|
+
const regression = repairedPacket.timestamp - boundaryPacket.timestamp;
|
|
23006
|
+
if (regression > maximumBoundaryRegression) {
|
|
23007
|
+
throw new Error("Video timing boundary regression is not recoverable");
|
|
23008
|
+
}
|
|
23009
|
+
boundaryPacket.timestamp = repairedPacket.timestamp + repairedPacket.duration;
|
|
23010
|
+
boundaryPacket.isTimestampRepaired = true;
|
|
23011
|
+
repairedTimestampCount += 1;
|
|
23012
|
+
}
|
|
23013
|
+
return {
|
|
23014
|
+
nominalDurationSeconds,
|
|
23015
|
+
packetTimings,
|
|
23016
|
+
repairedDurationCount: repairIndexes.length,
|
|
23017
|
+
repairedTimestampCount
|
|
23018
|
+
};
|
|
23019
|
+
}
|
|
23020
|
+
async function readVideoPacketTimings(videoTrack) {
|
|
23021
|
+
const packets = [];
|
|
23022
|
+
const sink = new EncodedPacketSink(videoTrack);
|
|
23023
|
+
for await (const packet of sink.packets(undefined, undefined, {
|
|
23024
|
+
metadataOnly: true
|
|
23025
|
+
})) {
|
|
23026
|
+
packets.push({
|
|
23027
|
+
duration: packet.duration,
|
|
23028
|
+
timestamp: packet.timestamp
|
|
23029
|
+
});
|
|
23030
|
+
}
|
|
23031
|
+
return packets;
|
|
23032
|
+
}
|
|
23033
|
+
async function addVideoTrack(output, videoTrack, videoSource) {
|
|
23034
|
+
const name = await videoTrack.getName();
|
|
23035
|
+
const metadata = {
|
|
23036
|
+
languageCode: await videoTrack.getLanguageCode(),
|
|
23037
|
+
rotation: await videoTrack.getRotation()
|
|
23038
|
+
};
|
|
23039
|
+
if (name !== null) {
|
|
23040
|
+
metadata.name = name;
|
|
23041
|
+
}
|
|
23042
|
+
output.addVideoTrack(videoSource, metadata);
|
|
23043
|
+
}
|
|
23044
|
+
async function addAudioTrack(output, audioTrack, audioSource) {
|
|
23045
|
+
const name = await audioTrack.getName();
|
|
23046
|
+
const metadata = {
|
|
23047
|
+
languageCode: await audioTrack.getLanguageCode()
|
|
23048
|
+
};
|
|
23049
|
+
if (name !== null) {
|
|
23050
|
+
metadata.name = name;
|
|
23051
|
+
}
|
|
23052
|
+
output.addAudioTrack(audioSource, metadata);
|
|
23053
|
+
}
|
|
23054
|
+
async function writeRepairedVideoPackets(videoTrack, videoSource, plan) {
|
|
23055
|
+
const decoderConfig = await videoTrack.getDecoderConfig();
|
|
23056
|
+
const metadata = {};
|
|
23057
|
+
if (decoderConfig !== null) {
|
|
23058
|
+
metadata.decoderConfig = decoderConfig;
|
|
23059
|
+
}
|
|
23060
|
+
let packetIndex = 0;
|
|
23061
|
+
const sink = new EncodedPacketSink(videoTrack);
|
|
23062
|
+
for await (const packet of sink.packets(undefined, undefined, {
|
|
23063
|
+
verifyKeyPackets: true
|
|
23064
|
+
})) {
|
|
23065
|
+
const timing = plan.packetTimings[packetIndex];
|
|
23066
|
+
if (timing === undefined) {
|
|
23067
|
+
throw new Error("Video packet count changed during timing repair");
|
|
23068
|
+
}
|
|
23069
|
+
const outputPacket = timing.isDurationRepaired || timing.isTimestampRepaired ? packet.clone({
|
|
23070
|
+
duration: timing.duration,
|
|
23071
|
+
timestamp: timing.timestamp
|
|
23072
|
+
}) : packet;
|
|
23073
|
+
await videoSource.add(outputPacket, metadata);
|
|
23074
|
+
packetIndex += 1;
|
|
23075
|
+
}
|
|
23076
|
+
if (packetIndex !== plan.packetTimings.length) {
|
|
23077
|
+
throw new Error("Video packet count changed during timing repair");
|
|
23078
|
+
}
|
|
23079
|
+
videoSource.close();
|
|
23080
|
+
}
|
|
23081
|
+
async function writeAudioPackets(audioTrack, audioSource) {
|
|
23082
|
+
const decoderConfig = await audioTrack.getDecoderConfig();
|
|
23083
|
+
const metadata = {};
|
|
23084
|
+
if (decoderConfig !== null) {
|
|
23085
|
+
metadata.decoderConfig = decoderConfig;
|
|
23086
|
+
}
|
|
23087
|
+
const sink = new EncodedPacketSink(audioTrack);
|
|
23088
|
+
for await (const packet of sink.packets()) {
|
|
23089
|
+
await audioSource.add(packet, metadata);
|
|
23090
|
+
}
|
|
23091
|
+
audioSource.close();
|
|
23092
|
+
}
|
|
23093
|
+
async function remuxRepairedVideo(input, videoTrack, plan) {
|
|
23094
|
+
const videoCodec = await videoTrack.getCodec();
|
|
23095
|
+
if (videoCodec === null) {
|
|
23096
|
+
throw new Error("Timing repair requires a supported video codec");
|
|
23097
|
+
}
|
|
23098
|
+
const audioTrack = await input.getPrimaryAudioTrack();
|
|
23099
|
+
let audioCodec = null;
|
|
23100
|
+
if (audioTrack !== null) {
|
|
23101
|
+
audioCodec = await audioTrack.getCodec();
|
|
23102
|
+
if (audioCodec === null) {
|
|
23103
|
+
throw new Error("Timing repair requires a supported audio codec");
|
|
23104
|
+
}
|
|
23105
|
+
}
|
|
23106
|
+
const target = new BufferTarget2;
|
|
23107
|
+
const output = new Output2({
|
|
23108
|
+
format: new Mp4OutputFormat2({ fastStart: "in-memory" }),
|
|
23109
|
+
target
|
|
23110
|
+
});
|
|
23111
|
+
const videoSource = new EncodedVideoPacketSource(videoCodec);
|
|
23112
|
+
await addVideoTrack(output, videoTrack, videoSource);
|
|
23113
|
+
let audioSource = null;
|
|
23114
|
+
if (audioTrack !== null && audioCodec !== null) {
|
|
23115
|
+
audioSource = new EncodedAudioPacketSource(audioCodec);
|
|
23116
|
+
await addAudioTrack(output, audioTrack, audioSource);
|
|
23117
|
+
}
|
|
23118
|
+
await output.start();
|
|
23119
|
+
const writers = [
|
|
23120
|
+
writeRepairedVideoPackets(videoTrack, videoSource, plan)
|
|
23121
|
+
];
|
|
23122
|
+
if (audioTrack !== null && audioSource !== null) {
|
|
23123
|
+
writers.push(writeAudioPackets(audioTrack, audioSource));
|
|
23124
|
+
}
|
|
23125
|
+
await Promise.all(writers);
|
|
23126
|
+
await output.finalize();
|
|
23127
|
+
if (target.buffer === null) {
|
|
23128
|
+
throw new Error("Timing repair did not produce an output buffer");
|
|
23129
|
+
}
|
|
23130
|
+
return new Blob([target.buffer], { type: "video/mp4" });
|
|
23131
|
+
}
|
|
23132
|
+
async function repairDeferredVideoTiming(blob, expectedDurationSeconds) {
|
|
23133
|
+
const input = new Input3({
|
|
23134
|
+
formats: ALL_FORMATS2,
|
|
23135
|
+
source: new BlobSource3(blob)
|
|
23136
|
+
});
|
|
23137
|
+
try {
|
|
23138
|
+
const videoTrack = await input.getPrimaryVideoTrack();
|
|
23139
|
+
if (videoTrack === null) {
|
|
23140
|
+
return {
|
|
23141
|
+
blob,
|
|
23142
|
+
diagnostics: {
|
|
23143
|
+
deferredTimingRepairedDurationCount: 0,
|
|
23144
|
+
deferredTimingRepairedTimestampCount: 0
|
|
23145
|
+
}
|
|
23146
|
+
};
|
|
23147
|
+
}
|
|
23148
|
+
const packetTimings = await readVideoPacketTimings(videoTrack);
|
|
23149
|
+
const plan = createDeferredVideoTimingRepairPlan(packetTimings, expectedDurationSeconds);
|
|
23150
|
+
const diagnostics = {
|
|
23151
|
+
deferredTimingRepairedDurationCount: plan.repairedDurationCount,
|
|
23152
|
+
deferredTimingRepairedTimestampCount: plan.repairedTimestampCount
|
|
23153
|
+
};
|
|
23154
|
+
if (plan.nominalDurationSeconds !== null) {
|
|
23155
|
+
diagnostics.deferredTimingNominalDurationSeconds = plan.nominalDurationSeconds;
|
|
23156
|
+
}
|
|
23157
|
+
if (plan.repairedDurationCount === 0) {
|
|
23158
|
+
return { blob, diagnostics };
|
|
23159
|
+
}
|
|
23160
|
+
return {
|
|
23161
|
+
blob: await remuxRepairedVideo(input, videoTrack, plan),
|
|
23162
|
+
diagnostics
|
|
23163
|
+
};
|
|
23164
|
+
} finally {
|
|
23165
|
+
input.dispose();
|
|
23166
|
+
}
|
|
23167
|
+
}
|
|
23168
|
+
|
|
23169
|
+
// src/core/transcode/deferred-video-transcoder.ts
|
|
22903
23170
|
var MINIMUM_FRAME_DENSITY_RATIO = 0.9;
|
|
22904
23171
|
var MAXIMUM_DURATION_DIFFERENCE_RATIO = 0.05;
|
|
22905
23172
|
var MINIMUM_DURATION_TOLERANCE_SECONDS = 0.25;
|
|
@@ -22951,12 +23218,13 @@ function validateOutputFrameDensity(summary, targetFrameRate, diagnostics) {
|
|
|
22951
23218
|
throw createIntegrityError("Output video frame density is below the capture target", diagnostics);
|
|
22952
23219
|
}
|
|
22953
23220
|
}
|
|
22954
|
-
function buildIntegrityDiagnostics(validation) {
|
|
23221
|
+
function buildIntegrityDiagnostics(validation, additionalDiagnostics = {}) {
|
|
22955
23222
|
let stage = "output";
|
|
22956
23223
|
if (validation.stage !== undefined) {
|
|
22957
23224
|
stage = validation.stage;
|
|
22958
23225
|
}
|
|
22959
23226
|
const diagnostics = {
|
|
23227
|
+
...additionalDiagnostics,
|
|
22960
23228
|
deferredIntegrityStage: stage
|
|
22961
23229
|
};
|
|
22962
23230
|
assignFiniteDiagnostic(diagnostics, "mediaRecorderExpectedDurationSeconds", validation.expectedDurationSeconds);
|
|
@@ -22992,8 +23260,8 @@ function validateLifecycleCoverage(summary, label, expectedDurationSeconds, diag
|
|
|
22992
23260
|
throw createIntegrityError(`${label} video duration does not cover the active recording`, diagnostics);
|
|
22993
23261
|
}
|
|
22994
23262
|
}
|
|
22995
|
-
function
|
|
22996
|
-
const diagnostics = buildIntegrityDiagnostics(validation);
|
|
23263
|
+
function validateDeferredVideoStatsWithDiagnostics(validation, additionalDiagnostics) {
|
|
23264
|
+
const diagnostics = buildIntegrityDiagnostics(validation, additionalDiagnostics);
|
|
22997
23265
|
if (!Number.isFinite(validation.expectedDurationSeconds) || validation.expectedDurationSeconds < 0) {
|
|
22998
23266
|
throw createIntegrityError("Deferred transcode requires a valid active recording duration", diagnostics);
|
|
22999
23267
|
}
|
|
@@ -23028,9 +23296,9 @@ function validateDeferredVideoStats(validation) {
|
|
|
23028
23296
|
}
|
|
23029
23297
|
}
|
|
23030
23298
|
async function inspectVideoPackets(blob) {
|
|
23031
|
-
const input = new
|
|
23032
|
-
formats:
|
|
23033
|
-
source: new
|
|
23299
|
+
const input = new Input4({
|
|
23300
|
+
formats: ALL_FORMATS3,
|
|
23301
|
+
source: new BlobSource4(blob)
|
|
23034
23302
|
});
|
|
23035
23303
|
const videoTrack = await input.getPrimaryVideoTrack();
|
|
23036
23304
|
if (videoTrack === null) {
|
|
@@ -23038,7 +23306,7 @@ async function inspectVideoPackets(blob) {
|
|
|
23038
23306
|
return null;
|
|
23039
23307
|
}
|
|
23040
23308
|
try {
|
|
23041
|
-
const packetSink = new
|
|
23309
|
+
const packetSink = new EncodedPacketSink2(videoTrack);
|
|
23042
23310
|
const timestamps = [];
|
|
23043
23311
|
let firstTimestamp = Number.POSITIVE_INFINITY;
|
|
23044
23312
|
let lastEndTimestamp = Number.NEGATIVE_INFINITY;
|
|
@@ -23073,6 +23341,15 @@ async function inspectDeferredVideo(blob, label, diagnostics) {
|
|
|
23073
23341
|
throw createIntegrityError(`Could not inspect ${label} deferred video: ${message}`, diagnostics);
|
|
23074
23342
|
});
|
|
23075
23343
|
}
|
|
23344
|
+
async function repairDeferredVideoSource(input, expectedDurationSeconds) {
|
|
23345
|
+
return await repairDeferredVideoTiming(input, expectedDurationSeconds).catch((error) => {
|
|
23346
|
+
const message = extractErrorMessage(error);
|
|
23347
|
+
throw createIntegrityError(`Could not repair deferred video timing: ${message}`, {
|
|
23348
|
+
deferredIntegrityStage: "source-repair",
|
|
23349
|
+
mediaRecorderExpectedDurationSeconds: expectedDurationSeconds
|
|
23350
|
+
});
|
|
23351
|
+
});
|
|
23352
|
+
}
|
|
23076
23353
|
async function transcodeDeferredVideo(input, config, onProgress, context) {
|
|
23077
23354
|
const targetFrameRate = config.fps;
|
|
23078
23355
|
if (typeof targetFrameRate !== "number" || !Number.isFinite(targetFrameRate) || targetFrameRate <= 0) {
|
|
@@ -23081,17 +23358,19 @@ async function transcodeDeferredVideo(input, config, onProgress, context) {
|
|
|
23081
23358
|
mediaRecorderExpectedDurationSeconds: context.expectedDurationSeconds
|
|
23082
23359
|
});
|
|
23083
23360
|
}
|
|
23084
|
-
const
|
|
23361
|
+
const timingRepair = await repairDeferredVideoSource(input, context.expectedDurationSeconds);
|
|
23362
|
+
const source = await inspectDeferredVideo(timingRepair.blob, "source", {
|
|
23085
23363
|
deferredIntegrityStage: "source",
|
|
23086
|
-
mediaRecorderExpectedDurationSeconds: context.expectedDurationSeconds
|
|
23364
|
+
mediaRecorderExpectedDurationSeconds: context.expectedDurationSeconds,
|
|
23365
|
+
...timingRepair.diagnostics
|
|
23087
23366
|
});
|
|
23088
|
-
|
|
23367
|
+
validateDeferredVideoStatsWithDiagnostics({
|
|
23089
23368
|
expectedDurationSeconds: context.expectedDurationSeconds,
|
|
23090
23369
|
output: null,
|
|
23091
23370
|
source,
|
|
23092
23371
|
stage: "source",
|
|
23093
23372
|
targetFrameRate
|
|
23094
|
-
});
|
|
23373
|
+
}, timingRepair.diagnostics);
|
|
23095
23374
|
const transcodeDiagnostics = buildIntegrityDiagnostics({
|
|
23096
23375
|
expectedDurationSeconds: context.expectedDurationSeconds,
|
|
23097
23376
|
output: null,
|
|
@@ -23100,7 +23379,8 @@ async function transcodeDeferredVideo(input, config, onProgress, context) {
|
|
|
23100
23379
|
targetFrameRate
|
|
23101
23380
|
});
|
|
23102
23381
|
transcodeDiagnostics.deferredIntegrityStage = "transcode";
|
|
23103
|
-
|
|
23382
|
+
Object.assign(transcodeDiagnostics, timingRepair.diagnostics);
|
|
23383
|
+
const result = await transcodeVideo(timingRepair.blob, config, onProgress).catch((error) => {
|
|
23104
23384
|
let transcodeError;
|
|
23105
23385
|
if (error instanceof Error) {
|
|
23106
23386
|
transcodeError = error;
|
|
@@ -23112,7 +23392,8 @@ async function transcodeDeferredVideo(input, config, onProgress, context) {
|
|
|
23112
23392
|
});
|
|
23113
23393
|
const outputDiagnostics = {
|
|
23114
23394
|
deferredIntegrityStage: "output",
|
|
23115
|
-
mediaRecorderExpectedDurationSeconds: context.expectedDurationSeconds
|
|
23395
|
+
mediaRecorderExpectedDurationSeconds: context.expectedDurationSeconds,
|
|
23396
|
+
...timingRepair.diagnostics
|
|
23116
23397
|
};
|
|
23117
23398
|
if (source !== null) {
|
|
23118
23399
|
outputDiagnostics.deferredSourceDurationSeconds = source.duration;
|
|
@@ -23128,10 +23409,11 @@ async function transcodeDeferredVideo(input, config, onProgress, context) {
|
|
|
23128
23409
|
stage: "output",
|
|
23129
23410
|
targetFrameRate
|
|
23130
23411
|
};
|
|
23131
|
-
|
|
23412
|
+
validateDeferredVideoStatsWithDiagnostics(validation, timingRepair.diagnostics);
|
|
23413
|
+
const diagnostics = buildIntegrityDiagnostics(validation, timingRepair.diagnostics);
|
|
23132
23414
|
return {
|
|
23133
23415
|
...result,
|
|
23134
|
-
diagnostics
|
|
23416
|
+
diagnostics
|
|
23135
23417
|
};
|
|
23136
23418
|
}
|
|
23137
23419
|
|
|
@@ -24968,79 +25250,79 @@ class VidtreoRecorder {
|
|
|
24968
25250
|
}
|
|
24969
25251
|
}
|
|
24970
25252
|
export {
|
|
24971
|
-
|
|
24972
|
-
validateBrowserSupport,
|
|
24973
|
-
transcodeVideoForNativeCamera,
|
|
24974
|
-
transcodeVideo,
|
|
24975
|
-
resolveDeviceError,
|
|
24976
|
-
requireStream,
|
|
24977
|
-
requireProcessor,
|
|
24978
|
-
requireNonNull,
|
|
24979
|
-
requireMediaDevices,
|
|
24980
|
-
requireInitialized,
|
|
24981
|
-
requireDefined,
|
|
24982
|
-
requireActive,
|
|
24983
|
-
recoverPendingUpload,
|
|
24984
|
-
parseBrowserErrorLinkContent,
|
|
24985
|
-
mapPresetToConfig,
|
|
24986
|
-
logger,
|
|
24987
|
-
isMobileDevice2 as isMobileDevice,
|
|
24988
|
-
isAudioRuntimeMissingCode,
|
|
24989
|
-
isAudioMissingError,
|
|
24990
|
-
getPresetVideoBitrateForFormat,
|
|
24991
|
-
getPresetTotalBitrate,
|
|
24992
|
-
getPresetAudioBitrateForFormat,
|
|
24993
|
-
getFormatCompatibilityPolicy,
|
|
24994
|
-
getDefaultConfigForFormat,
|
|
24995
|
-
getDefaultAudioCodecForFormat,
|
|
24996
|
-
getCameraErrorText,
|
|
24997
|
-
getBrowserName,
|
|
24998
|
-
getBrowserInfo,
|
|
24999
|
-
getBrowserErrorText,
|
|
25000
|
-
getAudioErrorText,
|
|
25001
|
-
getAudioCodecForFormat,
|
|
25002
|
-
formatTime,
|
|
25003
|
-
formatFileSize,
|
|
25004
|
-
extractVideoDuration,
|
|
25005
|
-
extractLastFrame,
|
|
25006
|
-
extractErrorMessage,
|
|
25007
|
-
evaluateAudioHealth,
|
|
25008
|
-
createPermissionFlowOrchestratorDependencies,
|
|
25009
|
-
createAudioNoTrackAtStartError,
|
|
25010
|
-
createAudioMissingError,
|
|
25011
|
-
checkRecorderSupport,
|
|
25012
|
-
calculateVideoBitrate,
|
|
25013
|
-
calculateTotalBitrateFromMbPerMinute,
|
|
25014
|
-
calculateBarColor,
|
|
25015
|
-
VidtreoRecorder,
|
|
25016
|
-
VideoUploadService,
|
|
25017
|
-
VideoStorageService,
|
|
25018
|
-
UploadQueueManager,
|
|
25019
|
-
StreamProcessor,
|
|
25020
|
-
StorageManager,
|
|
25021
|
-
RecordingManager,
|
|
25022
|
-
RecorderController,
|
|
25023
|
-
QuotaManager,
|
|
25024
|
-
PermissionFlowOrchestrator,
|
|
25025
|
-
PRESET_SIZE_LIMIT_MB_PER_MINUTE,
|
|
25026
|
-
NativeCameraHandler,
|
|
25027
|
-
FORMAT_DEFAULT_CODECS,
|
|
25028
|
-
FORMAT_COMPATIBILITY_POLICY,
|
|
25029
|
-
ERROR_RECORDING_NO_AUDIO_TRACK,
|
|
25030
|
-
ERROR_RECORDING_NO_AUDIO_FRAMES,
|
|
25031
|
-
ERROR_RECORDING_AUDIO_ZERO_CHANNELS,
|
|
25032
|
-
ERROR_RECORDING_AUDIO_TRACK_ENDED,
|
|
25033
|
-
ERROR_RECORDING_AUDIO_SILENT,
|
|
25034
|
-
ERROR_RECORDING_AUDIO_NO_CHUNKS,
|
|
25035
|
-
ERROR_RECORDING_AUDIO_INVALID_SAMPLE_RATE,
|
|
25036
|
-
ERROR_AUDIO_NO_TRACK_AT_START,
|
|
25037
|
-
DeviceManager,
|
|
25038
|
-
DEFAULT_TRANSCODE_CONFIG,
|
|
25039
|
-
DEFAULT_STREAM_CONFIG,
|
|
25040
|
-
DEFAULT_RECORDING_OPTIONS,
|
|
25041
|
-
DEFAULT_CAMERA_CONSTRAINTS,
|
|
25042
|
-
ConfigService,
|
|
25043
|
-
ConfigManager,
|
|
25253
|
+
AudioLevelAnalyzer,
|
|
25044
25254
|
CameraStreamManager,
|
|
25045
|
-
|
|
25255
|
+
ConfigManager,
|
|
25256
|
+
ConfigService,
|
|
25257
|
+
DEFAULT_CAMERA_CONSTRAINTS,
|
|
25258
|
+
DEFAULT_RECORDING_OPTIONS,
|
|
25259
|
+
DEFAULT_STREAM_CONFIG,
|
|
25260
|
+
DEFAULT_TRANSCODE_CONFIG,
|
|
25261
|
+
DeviceManager,
|
|
25262
|
+
ERROR_AUDIO_NO_TRACK_AT_START,
|
|
25263
|
+
ERROR_RECORDING_AUDIO_INVALID_SAMPLE_RATE,
|
|
25264
|
+
ERROR_RECORDING_AUDIO_NO_CHUNKS,
|
|
25265
|
+
ERROR_RECORDING_AUDIO_SILENT,
|
|
25266
|
+
ERROR_RECORDING_AUDIO_TRACK_ENDED,
|
|
25267
|
+
ERROR_RECORDING_AUDIO_ZERO_CHANNELS,
|
|
25268
|
+
ERROR_RECORDING_NO_AUDIO_FRAMES,
|
|
25269
|
+
ERROR_RECORDING_NO_AUDIO_TRACK,
|
|
25270
|
+
FORMAT_COMPATIBILITY_POLICY,
|
|
25271
|
+
FORMAT_DEFAULT_CODECS,
|
|
25272
|
+
NativeCameraHandler,
|
|
25273
|
+
PRESET_SIZE_LIMIT_MB_PER_MINUTE,
|
|
25274
|
+
PermissionFlowOrchestrator,
|
|
25275
|
+
QuotaManager,
|
|
25276
|
+
RecorderController,
|
|
25277
|
+
RecordingManager,
|
|
25278
|
+
StorageManager,
|
|
25279
|
+
StreamProcessor,
|
|
25280
|
+
UploadQueueManager,
|
|
25281
|
+
VideoStorageService,
|
|
25282
|
+
VideoUploadService,
|
|
25283
|
+
VidtreoRecorder,
|
|
25284
|
+
calculateBarColor,
|
|
25285
|
+
calculateTotalBitrateFromMbPerMinute,
|
|
25286
|
+
calculateVideoBitrate,
|
|
25287
|
+
checkRecorderSupport,
|
|
25288
|
+
createAudioMissingError,
|
|
25289
|
+
createAudioNoTrackAtStartError,
|
|
25290
|
+
createPermissionFlowOrchestratorDependencies,
|
|
25291
|
+
evaluateAudioHealth,
|
|
25292
|
+
extractErrorMessage,
|
|
25293
|
+
extractLastFrame,
|
|
25294
|
+
extractVideoDuration,
|
|
25295
|
+
formatFileSize,
|
|
25296
|
+
formatTime,
|
|
25297
|
+
getAudioCodecForFormat,
|
|
25298
|
+
getAudioErrorText,
|
|
25299
|
+
getBrowserErrorText,
|
|
25300
|
+
getBrowserInfo,
|
|
25301
|
+
getBrowserName,
|
|
25302
|
+
getCameraErrorText,
|
|
25303
|
+
getDefaultAudioCodecForFormat,
|
|
25304
|
+
getDefaultConfigForFormat,
|
|
25305
|
+
getFormatCompatibilityPolicy,
|
|
25306
|
+
getPresetAudioBitrateForFormat,
|
|
25307
|
+
getPresetTotalBitrate,
|
|
25308
|
+
getPresetVideoBitrateForFormat,
|
|
25309
|
+
isAudioMissingError,
|
|
25310
|
+
isAudioRuntimeMissingCode,
|
|
25311
|
+
isMobileDevice2 as isMobileDevice,
|
|
25312
|
+
logger,
|
|
25313
|
+
mapPresetToConfig,
|
|
25314
|
+
parseBrowserErrorLinkContent,
|
|
25315
|
+
recoverPendingUpload,
|
|
25316
|
+
requireActive,
|
|
25317
|
+
requireDefined,
|
|
25318
|
+
requireInitialized,
|
|
25319
|
+
requireMediaDevices,
|
|
25320
|
+
requireNonNull,
|
|
25321
|
+
requireProcessor,
|
|
25322
|
+
requireStream,
|
|
25323
|
+
resolveDeviceError,
|
|
25324
|
+
transcodeVideo,
|
|
25325
|
+
transcodeVideoForNativeCamera,
|
|
25326
|
+
validateBrowserSupport,
|
|
25327
|
+
validateFile
|
|
25046
25328
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vidtreo/recorder",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.12",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Vidtreo SDK for browser-based video recording and transcoding. Features include camera/screen recording, real-time MP4 transcoding, audio level analysis, mute/pause controls, source switching, device selection, and automatic backend uploads. Similar to Ziggeo and Addpipe, Vidtreo provides enterprise-grade video processing capabilities for web applications.",
|
|
6
6
|
"main": "./dist/index.js",
|