@pictx/gemini-veo-watermark-remover 0.2.3 → 0.2.4

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/browser.js CHANGED
@@ -272,6 +272,79 @@ var init_frameProcessor = __esm({
272
272
  }
273
273
  });
274
274
 
275
+ // src/video/codecDescription.js
276
+ function buildAvcDecoderConfigurationRecord(avcC) {
277
+ const spsList = avcC.SPS ?? [];
278
+ const ppsList = avcC.PPS ?? [];
279
+ let size = 7;
280
+ for (const sps of spsList) {
281
+ size += 2 + getNaluByteLength(sps);
282
+ }
283
+ size += 1;
284
+ for (const pps of ppsList) {
285
+ size += 2 + getNaluByteLength(pps);
286
+ }
287
+ if (avcC.ext?.length) {
288
+ size += avcC.ext.length;
289
+ }
290
+ const buffer = new Uint8Array(size);
291
+ const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
292
+ let offset = 0;
293
+ buffer[offset++] = avcC.configurationVersion;
294
+ buffer[offset++] = avcC.AVCProfileIndication;
295
+ buffer[offset++] = avcC.profile_compatibility;
296
+ buffer[offset++] = avcC.AVCLevelIndication;
297
+ buffer[offset++] = (avcC.lengthSizeMinusOne & 3) + (63 << 2);
298
+ buffer[offset++] = spsList.length + (7 << 5);
299
+ for (const sps of spsList) {
300
+ const nalu = getNaluBytes(sps);
301
+ view.setUint16(offset, nalu.length);
302
+ offset += 2;
303
+ buffer.set(nalu, offset);
304
+ offset += nalu.length;
305
+ }
306
+ buffer[offset++] = ppsList.length;
307
+ for (const pps of ppsList) {
308
+ const nalu = getNaluBytes(pps);
309
+ view.setUint16(offset, nalu.length);
310
+ offset += 2;
311
+ buffer.set(nalu, offset);
312
+ offset += nalu.length;
313
+ }
314
+ if (avcC.ext?.length) {
315
+ buffer.set(avcC.ext, offset);
316
+ }
317
+ return buffer;
318
+ }
319
+ function extractCodecDescription(mp4, trackId) {
320
+ const trak = mp4.getTrackById(trackId);
321
+ const entries = trak?.mdia?.minf?.stbl?.stsd?.entries ?? [];
322
+ for (const entry of entries) {
323
+ if (entry.avcC) {
324
+ return buildAvcDecoderConfigurationRecord(entry.avcC);
325
+ }
326
+ if (entry.hvcC) {
327
+ throw new Error("HEVC (hvcC) WebCodecs decoding is not implemented yet.");
328
+ }
329
+ }
330
+ throw new Error("Codec description box (avcC or hvcC) not found for video track.");
331
+ }
332
+ function getNaluBytes(entry) {
333
+ if (entry?.nalu instanceof Uint8Array) return entry.nalu;
334
+ if (entry instanceof Uint8Array) return entry;
335
+ throw new Error("Invalid SPS/PPS entry in avcC box.");
336
+ }
337
+ function getNaluByteLength(entry) {
338
+ if (entry?.nalu instanceof Uint8Array) return entry.nalu.length;
339
+ if (typeof entry?.length === "number") return entry.length;
340
+ if (entry instanceof Uint8Array) return entry.length;
341
+ throw new Error("Invalid SPS/PPS entry in avcC box.");
342
+ }
343
+ var init_codecDescription = __esm({
344
+ "src/video/codecDescription.js"() {
345
+ }
346
+ });
347
+
275
348
  // src/video/videoDecoder.base.js
276
349
  var VideoDecoderBase;
277
350
  var init_videoDecoder_base = __esm({
@@ -296,6 +369,7 @@ var init_videoDecoder_base = __esm({
296
369
  var WebCodecsDecoder;
297
370
  var init_videoDecoder_webcodecs = __esm({
298
371
  "src/video/videoDecoder.webcodecs.js"() {
372
+ init_codecDescription();
299
373
  init_videoDecoder_base();
300
374
  WebCodecsDecoder = class extends VideoDecoderBase {
301
375
  #videoInfo = null;
@@ -321,6 +395,15 @@ var init_videoDecoder_webcodecs = __esm({
321
395
  if (!videoTrack) {
322
396
  throw new Error("No video track found");
323
397
  }
398
+ this.#videoMp4 = createFile();
399
+ await new Promise((resolve, reject) => {
400
+ this.#videoMp4.onReady = resolve;
401
+ this.#videoMp4.onError = reject;
402
+ const buffer = this.#sourceBuffer.slice(0);
403
+ buffer.fileStart = 0;
404
+ this.#videoMp4.appendBuffer(buffer);
405
+ this.#videoMp4.flush();
406
+ });
324
407
  this.#videoInfo = {
325
408
  width: videoTrack.video.width,
326
409
  height: videoTrack.video.height,
@@ -328,21 +411,13 @@ var init_videoDecoder_webcodecs = __esm({
328
411
  duration: videoTrack.duration / videoTrack.timescale,
329
412
  fps: videoTrack.nb_samples / (videoTrack.duration / videoTrack.timescale),
330
413
  codec: videoTrack.codec,
331
- videoTrackId: videoTrack.id
414
+ videoTrackId: videoTrack.id,
415
+ description: extractCodecDescription(this.#videoMp4, videoTrack.id)
332
416
  };
333
417
  const audioTrack = info.audioTracks?.[0] ?? null;
334
418
  if (audioTrack) {
335
419
  this.#audioData = await this.#readTrackSamples(createFile, audioTrack);
336
420
  }
337
- this.#videoMp4 = createFile();
338
- await new Promise((resolve, reject) => {
339
- this.#videoMp4.onReady = resolve;
340
- this.#videoMp4.onError = reject;
341
- const buffer = this.#sourceBuffer.slice(0);
342
- buffer.fileStart = 0;
343
- this.#videoMp4.appendBuffer(buffer);
344
- this.#videoMp4.flush();
345
- });
346
421
  return this.#videoInfo;
347
422
  }
348
423
  /**
@@ -389,10 +464,13 @@ var init_videoDecoder_webcodecs = __esm({
389
464
  if (!this.#videoMp4 || !this.#videoInfo) {
390
465
  throw new Error("Call open() first");
391
466
  }
392
- const { width, height, videoTrackId } = this.#videoInfo;
467
+ const { width, height, videoTrackId, frameCount } = this.#videoInfo;
393
468
  const pendingFrames = [];
394
469
  let resolveNext = null;
395
470
  let done = false;
471
+ let extractionDone = false;
472
+ let flushed = false;
473
+ let samplesSubmitted = 0;
396
474
  const decoder = new VideoDecoder({
397
475
  output: (frame) => {
398
476
  const canvas = new OffscreenCanvas(width, height);
@@ -416,12 +494,18 @@ var init_videoDecoder_webcodecs = __esm({
416
494
  error: (e) => {
417
495
  console.error("Decoder error:", e);
418
496
  done = true;
497
+ if (resolveNext) {
498
+ const r = resolveNext;
499
+ resolveNext = null;
500
+ r(null);
501
+ }
419
502
  }
420
503
  });
421
504
  decoder.configure({
422
505
  codec: this.#videoInfo.codec,
423
506
  codedWidth: width,
424
- codedHeight: height
507
+ codedHeight: height,
508
+ description: this.#videoInfo.description
425
509
  });
426
510
  this.#videoMp4.onSamples = (_trackId, _user, trackSamples) => {
427
511
  for (const sample of trackSamples) {
@@ -432,6 +516,15 @@ var init_videoDecoder_webcodecs = __esm({
432
516
  data: sample.data
433
517
  });
434
518
  decoder.decode(chunk);
519
+ samplesSubmitted++;
520
+ }
521
+ if (samplesSubmitted >= frameCount) {
522
+ extractionDone = true;
523
+ if (resolveNext && pendingFrames.length === 0 && decoder.decodeQueueSize === 0) {
524
+ const r = resolveNext;
525
+ resolveNext = null;
526
+ r(null);
527
+ }
435
528
  }
436
529
  };
437
530
  this.#videoMp4.setExtractionOptions(videoTrackId);
@@ -439,18 +532,24 @@ var init_videoDecoder_webcodecs = __esm({
439
532
  while (!done) {
440
533
  if (pendingFrames.length > 0) {
441
534
  yield pendingFrames.shift();
442
- } else {
443
- const frame = await new Promise((resolve) => {
444
- resolveNext = resolve;
445
- if (decoder.decodeQueueSize === 0) {
446
- decoder.flush().then(() => {
447
- done = true;
448
- resolve(null);
449
- });
535
+ continue;
536
+ }
537
+ if (extractionDone && decoder.decodeQueueSize === 0) {
538
+ if (!flushed) {
539
+ await decoder.flush();
540
+ flushed = true;
541
+ if (pendingFrames.length > 0) {
542
+ continue;
450
543
  }
451
- });
452
- if (frame) yield frame;
453
- else break;
544
+ }
545
+ done = true;
546
+ break;
547
+ }
548
+ const frame = await new Promise((resolve) => {
549
+ resolveNext = resolve;
550
+ });
551
+ if (frame) {
552
+ yield frame;
454
553
  }
455
554
  }
456
555
  decoder.close();
@@ -511,7 +610,8 @@ var init_videoEncoder_webcodecs = __esm({
511
610
  width: config.width,
512
611
  height: config.height
513
612
  },
514
- fastStart: "in-memory"
613
+ fastStart: "in-memory",
614
+ firstTimestampBehavior: "offset"
515
615
  };
516
616
  if (config.audio) {
517
617
  muxerConfig.audio = {
@@ -534,7 +634,14 @@ var init_videoEncoder_webcodecs = __esm({
534
634
  width: config.width,
535
635
  height: config.height,
536
636
  bitrate: config.bitrate || 5e6,
537
- framerate: config.fps
637
+ framerate: config.fps,
638
+ avc: { format: "avc" },
639
+ colorSpace: {
640
+ primaries: "bt709",
641
+ transfer: "bt709",
642
+ matrix: "bt709",
643
+ fullRange: false
644
+ }
538
645
  });
539
646
  this._target = target;
540
647
  }
@@ -543,7 +650,13 @@ var init_videoEncoder_webcodecs = __esm({
543
650
  format: "RGBA",
544
651
  codedWidth: imageData.width,
545
652
  codedHeight: imageData.height,
546
- timestamp
653
+ timestamp,
654
+ colorSpace: {
655
+ primaries: "bt709",
656
+ transfer: "bt709",
657
+ matrix: "bt709",
658
+ fullRange: true
659
+ }
547
660
  });
548
661
  const isKey = this.#frameCount % 30 === 0;
549
662
  this.#encoder.encode(frame, { keyFrame: isKey });
@@ -594,6 +707,7 @@ async function processVideo(input, options = {}) {
594
707
  height: videoInfo.height,
595
708
  fps: videoInfo.fps,
596
709
  bitrate: bitrate || 5e6,
710
+ codec: videoInfo.codec,
597
711
  audio: audioData ? {
598
712
  codec: audioData.codec,
599
713
  sampleRate: audioData.sampleRate,