var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
}) : x)(function(x) {
  if (typeof require !== "undefined") return require.apply(this, arguments);
  throw Error('Dynamic require of "' + x + '" is not supported');
});

// src/baichuan/stream/BaichuanVideoStream.ts
import { EventEmitter } from "events";
import * as fs2 from "fs";
import * as path2 from "path";

// src/protocol/crypto.ts
import { createCipheriv, createDecipheriv, createHash } from "crypto";

// src/protocol/constants.ts
var BC_TCP_DEFAULT_PORT = 9e3;
var BC_MAGIC = Buffer.from([240, 222, 188, 10]);
var BC_MAGIC_REV = Buffer.from([160, 203, 237, 15]);
var BC_XML_KEY = Uint8Array.from([
  31,
  45,
  60,
  75,
  90,
  105,
  120,
  255
]);
var BC_AES_IV = Buffer.from("0123456789abcdef", "utf8");
var BC_CLASS_LEGACY = 25876;
var BC_CLASS_MODERN_20 = 26132;
var BC_CLASS_MODERN_24 = 25620;
var BC_CLASS_MODERN_24_ALT = 0;
var BC_CLASS_FILE_DOWNLOAD = 25730;
function bcHeaderHasPayloadOffset(messageClass) {
  return messageClass === BC_CLASS_MODERN_24 || messageClass === BC_CLASS_MODERN_24_ALT || messageClass === BC_CLASS_FILE_DOWNLOAD;
}
var BC_CMD_ID_LOGIN = 1;
var BC_CMD_ID_LOGOUT = 2;
var BC_CMD_ID_VIDEO = 3;
var BC_CMD_ID_VIDEO_STOP = 4;
var BC_CMD_ID_FILE_INFO_LIST_REPLAY = 5;
var BC_CMD_ID_FILE_INFO_LIST_STOP = 7;
var BC_CMD_ID_FILE_INFO_LIST_DL_VIDEO = 8;
var BC_CMD_ID_FILE_INFO_LIST_DOWNLOAD = 13;
var BC_CMD_ID_FILE_INFO_LIST_OPEN = 14;
var BC_CMD_ID_FILE_INFO_LIST_GET = 15;
var BC_CMD_ID_FILE_INFO_LIST_CLOSE = 16;
var BC_CMD_ID_FIND_REC_VIDEO_OPEN = 272;
var BC_CMD_ID_FIND_REC_VIDEO_GET = 273;
var BC_CMD_ID_FIND_REC_VIDEO_CLOSE = 274;
var BC_CMD_ID_COVER_PREVIEW = 298;
var BC_CMD_ID_COVER_STANDALONE_458 = 458;
var BC_CMD_ID_COVER_STANDALONE_459 = 459;
var BC_CMD_ID_COVER_STANDALONE_460 = 460;
var BC_CMD_ID_COVER_STANDALONE_461 = 461;
var BC_CMD_ID_COVER_STANDALONE_462 = 462;
var BC_CMD_ID_COVER_RESPONSE = 138;
var BC_CMD_ID_TALK_ABILITY = 10;
var BC_CMD_ID_TALK_RESET = 11;
var BC_CMD_ID_TALK_CONFIG = 201;
var BC_CMD_ID_TALK = 202;
var BC_CMD_ID_PTZ_CONTROL = 18;
var BC_CMD_ID_PTZ_CONTROL_PRESET = 19;
var BC_CMD_ID_GET_PTZ_PRESET = 190;
var BC_CMD_ID_GET_PTZ_POSITION = 433;
var BC_CMD_ID_GET_ZOOM_FOCUS = 294;
var BC_CMD_ID_SET_ZOOM_FOCUS = 295;
var BC_CMD_ID_GET_BATTERY_INFO_LIST = 252;
var BC_CMD_ID_GET_BATTERY_INFO = 253;
var BC_CMD_ID_UDP_KEEP_ALIVE = 234;
var BC_CMD_ID_GET_PIR_INFO = 212;
var BC_CMD_ID_SET_PIR_INFO = 213;
var BC_CMD_ID_GET_MOTION_ALARM = 46;
var BC_CMD_ID_SET_MOTION_ALARM = 47;
var BC_CMD_ID_ALARM_EVENT_LIST = 33;
var BC_CMD_ID_GET_AI_ALARM = 342;
var BC_CMD_ID_SET_AI_ALARM = 343;
var BC_CMD_ID_GET_AUDIO_ALARM = 547;
var BC_CMD_ID_AUDIO_ALARM_PLAY = 263;
var BC_CMD_ID_GET_WHITE_LED = 289;
var BC_CMD_ID_SET_WHITE_LED_STATE = 288;
var BC_CMD_ID_SET_WHITE_LED_TASK = 290;
var BC_CMD_ID_FLOODLIGHT_STATUS_LIST = 291;
var BC_CMD_ID_ABILITY_INFO = 151;
var BC_CMD_ID_SUPPORT = 199;
var BC_CMD_ID_PING = 93;
var BC_CMD_ID_DEVICE_DETECT_CANDIDATES = [31, 132, 150];
var BC_CMD_ID_DEVICE_DETECT = null;
var BC_CMD_ID_GET_SNAPSHOT = 109;
var BC_CMD_ID_GET_UID = 114;
var BC_CMD_ID_CHANNEL_INFO_ALL = 145;
var BC_CMD_ID_GET_OSD_DATETIME = 44;
var BC_CMD_ID_SET_OSD_DATETIME = 45;
var BC_CMD_ID_GET_RECORD_CFG = 54;
var BC_CMD_ID_GET_ABILITY_SUPPORT = 58;
var BC_CMD_ID_GET_FTP_TASK = 70;
var BC_CMD_ID_GET_VERSION_INFO = 80;
var BC_CMD_ID_GET_RECORD = 81;
var BC_CMD_ID_GET_HDD_INFO_LIST = 102;
var BC_CMD_ID_GET_WIFI_SIGNAL = 115;
var BC_CMD_ID_GET_WIFI = 116;
var BC_CMD_ID_GET_ONLINE_USER_LIST = 120;
var BC_CMD_ID_GET_DAY_RECORDS = 142;
var BC_CMD_ID_GET_STREAM_INFO_LIST = 146;
var BC_CMD_ID_GET_LED_STATE = 208;
var BC_CMD_ID_GET_EMAIL_TASK = 217;
var BC_CMD_ID_GET_AUDIO_TASK = 232;
var BC_CMD_ID_GET_AUDIO_CFG = 264;
var BC_CMD_ID_GET_DAY_NIGHT_THRESHOLD = 296;
var BC_CMD_ID_GET_TIMELAPSE_CFG = 319;
var BC_CMD_ID_GET_AI_DENOISE = 439;
var BC_CMD_ID_GET_KIT_AP_CFG = 481;
var BC_CMD_ID_GET_REC_ENC_CFG = 507;
var BC_CMD_ID_GET_ACCESS_USER_LIST = 511;
var BC_CMD_ID_GET_SLEEP_STATE = 574;
var BC_CMD_ID_GET_VIDEO_INPUT = 26;
var BC_CMD_ID_GET_SYSTEM_GENERAL = 104;
var BC_CMD_ID_GET_SUPPORT = 199;
var BC_CMD_ID_GET_AI_CFG = 299;
var BC_CMD_ID_SET_AI_CFG = 300;
var BC_CMD_ID_GET_SIREN_STATUS = 547;
var BC_CMD_ID_SET_AUDIO_TASK = 231;
var BC_CMD_ID_SET_VIDEO_INPUT = 25;
var BC_CMD_ID_SET_DAY_NIGHT_THRESHOLD = 297;
var BC_CMD_ID_GET_ENC = 56;
var BC_CMD_ID_SET_ENC = 57;
var BC_CMD_ID_GET_PRIVACY_MASK = 52;
var BC_CMD_ID_SET_PRIVACY_MASK = 53;
var BC_CMD_ID_SET_AI_DENOISE = 440;
var BC_CMD_ID_SET_LED_STATE = 209;
var BC_CMD_ID_SET_AUDIO_CFG = 265;
var BC_CMD_ID_SET_RECORD = 82;
var BC_CMD_ID_SET_RECORD_CFG = 55;
var BC_CMD_ID_SET_EMAIL_TASK = 216;
var BC_CMD_ID_GET_PUSH_TASK = 219;
var BC_CMD_ID_SET_PUSH_TASK = 218;
var BC_CMD_ID_GET_AUTO_FOCUS = 224;
var BC_CMD_ID_SET_AUTO_FOCUS = 225;
var BC_CMD_ID_GET_EMAIL = 42;
var BC_CMD_ID_SET_EMAIL = 43;
var BC_CMD_ID_TEST_EMAIL = 141;
var BC_CMD_ID_GET_NTP = 38;
var BC_CMD_ID_SET_NTP = 39;
var BC_CMD_ID_SET_SYSTEM_GENERAL = 105;
var BC_CMD_ID_GET_DST = 106;
var BC_CMD_ID_SET_DST = 107;
var BC_CMD_ID_GET_AUTO_REBOOT = 101;
var BC_CMD_ID_SET_AUTO_REBOOT = 100;
var BC_CMD_ID_CMD_123 = 123;
var BC_CMD_ID_CMD_209 = 209;
var BC_CMD_ID_CMD_265 = 265;
var BC_CMD_ID_CMD_440 = 440;
var BC_CMD_ID_PUSH_VIDEO_INPUT = 78;
var BC_CMD_ID_PUSH_SERIAL = 79;
var BC_CMD_ID_PUSH_NET_INFO = 464;
var BC_CMD_ID_PUSH_DINGDONG_LIST = 484;
var BC_CMD_ID_PUSH_SLEEP_STATUS = 623;
var BC_CMD_ID_PUSH_COORDINATE_POINT_LIST = 723;
var BC_CMD_ID_DING_DONG_CTRL = 483;
var BC_CMD_ID_GET_DING_DONG_LIST = 484;
var BC_CMD_ID_DING_DONG_OPT = 485;
var BC_CMD_ID_GET_DING_DONG_CFG = 486;
var BC_CMD_ID_SET_DING_DONG_CFG = 487;
var BC_CMD_ID_QUICK_REPLY_PLAY = 349;
var BC_CMD_ID_GET_DING_DONG_SILENT = 609;
var BC_CMD_ID_SET_DING_DONG_SILENT = 610;

// src/protocol/crypto.ts
function md5HexUpper(input) {
  return createHash("md5").update(input, "utf8").digest("hex").toUpperCase();
}
function md5StrModern(input) {
  return md5HexUpper(input).slice(0, 31);
}
function deriveAesKey(nonce, password) {
  const keyStr = md5StrModern(`${nonce}-${password}`).slice(0, 16);
  return Buffer.from(keyStr, "utf8");
}
function bcEncrypt(buf, offset) {
  const off = offset & 255;
  const out = Buffer.allocUnsafe(buf.length);
  for (let i = 0; i < buf.length; i++) {
    const key = BC_XML_KEY[(off + i) % BC_XML_KEY.length];
    out[i] = buf[i] ^ key ^ off;
  }
  return out;
}
function bcDecrypt(buf, offset) {
  return bcEncrypt(buf, offset);
}
function aesEncrypt(buf, key) {
  if (buf.length === 0) return Buffer.alloc(0);
  const cipher = createCipheriv("aes-128-cfb", key, BC_AES_IV);
  cipher.setAutoPadding(false);
  return Buffer.concat([cipher.update(buf), cipher.final()]);
}
function aesDecrypt(buf, key) {
  if (buf.length === 0) return Buffer.alloc(0);
  const decipher = createDecipheriv("aes-128-cfb", key, BC_AES_IV);
  decipher.setAutoPadding(false);
  return Buffer.concat([decipher.update(buf), decipher.final()]);
}
var AesStreamDecryptor = class {
  decipher = null;
  key;
  constructor(key) {
    this.key = key;
  }
  /**
   * Reset the cipher state (start decrypting with fresh IV).
   * Call this when a new BcMedia packet is detected.
   */
  reset() {
    this.decipher = createDecipheriv("aes-128-cfb", this.key, BC_AES_IV);
    this.decipher.setAutoPadding(false);
  }
  /**
   * Decrypt a chunk using the current cipher state.
   * Automatically resets if no cipher exists.
   *
   * @param buf - Encrypted buffer to decrypt
   * @returns Decrypted buffer
   */
  update(buf) {
    if (buf.length === 0) return Buffer.alloc(0);
    if (!this.decipher) this.reset();
    return this.decipher.update(buf);
  }
  /**
   * Check if the decryptor has been initialized.
   */
  isInitialized() {
    return this.decipher !== null;
  }
};

// src/debug/DebugConfig.ts
import * as fs from "fs";
import * as path from "path";
function normalizeDebugOptions(opts) {
  const general = opts?.general === true;
  const debugRtsp = opts?.debugRtsp === true;
  const traceNativeStream = opts?.traceNativeStream === true;
  const traceRecordings = opts?.traceRecordings === true;
  const traceTalk = opts?.traceTalk === true;
  const traceEvents = opts?.traceEvents === true;
  const dumpEnabled = opts?.dump?.enabled === true;
  const dumpDir = opts?.dump?.dir && opts.dump.dir.trim() || path.join(process.cwd(), "test", "frames-debug");
  const dumpBcMedia = opts?.dump?.bcmedia ?? dumpEnabled;
  const dumpNals = opts?.dump?.nals ?? dumpEnabled;
  return {
    general,
    debugRtsp,
    traceNativeStream,
    traceRecordings,
    traceTalk,
    traceEvents,
    dumpEnabled,
    dumpDir,
    dumpBcMedia,
    dumpNals
  };
}
function recordingsTraceLog(cfg, logger, tag, message) {
  if (!cfg?.traceRecordings || !logger) return;
  logger.log(`[${tag}] ${message}`);
}
function ensureDumpDir(cfg) {
  if (!cfg.dumpEnabled) return;
  fs.mkdirSync(cfg.dumpDir, { recursive: true });
}
function debugLog(cfg, logger, tag, message) {
  if (!cfg.general) return;
  logger.debug(`[${tag}] ${message}`);
}
function traceLog(cfg, logger, tag, message) {
  if (!cfg.traceNativeStream) return;
  logger.debug(`[${tag}] ${message}`);
}
function talkTraceLog(cfg, logger, tag, message) {
  if (!cfg.traceTalk) return;
  logger.debug(`[${tag}] ${message}`);
}
function eventTraceLog(cfg, logger, tag, message) {
  if (!cfg.traceEvents) return;
  logger.debug(`[${tag}] ${message}`);
}

// src/baichuan/stream/BcMediaParser.ts
var MAGIC_INFO_V1 = 825241649;
var MAGIC_INFO_V2 = 842018865;
var MAGIC_IFRAME_START = 1667510320;
var MAGIC_IFRAME_END = 1667510329;
var MAGIC_PFRAME_START = 1667510576;
var MAGIC_PFRAME_END = 1667510585;
var MAGIC_AAC = 1651979568;
var MAGIC_ADPCM = 1651978544;
var PAD_SIZE = 8;
function parseBcMedia(buf) {
  if (buf.length < 4) return null;
  const magic = buf.readUInt32LE(0);
  if (magic === MAGIC_INFO_V1) {
    return parseInfoV1(buf);
  } else if (magic === MAGIC_INFO_V2) {
    return parseInfoV2(buf);
  } else if (magic >= MAGIC_IFRAME_START && magic <= MAGIC_IFRAME_END) {
    return parseIframe(buf);
  } else if (magic >= MAGIC_PFRAME_START && magic <= MAGIC_PFRAME_END) {
    return parsePframe(buf);
  } else if (magic === MAGIC_AAC) {
    return parseAac(buf);
  } else if (magic === MAGIC_ADPCM) {
    return parseAdpcm(buf);
  }
  return null;
}
function parseInfoV1(buf) {
  if (buf.length < 32) return null;
  const headerSize = buf.readUInt32LE(4);
  if (headerSize !== 32) return null;
  const media = {
    type: "InfoV1",
    videoWidth: buf.readUInt32LE(8),
    videoHeight: buf.readUInt32LE(12),
    fps: buf.readUInt8(17),
    startYear: buf.readUInt8(18),
    startMonth: buf.readUInt8(19),
    startDay: buf.readUInt8(20),
    startHour: buf.readUInt8(21),
    startMin: buf.readUInt8(22),
    startSeconds: buf.readUInt8(23),
    endYear: buf.readUInt8(24),
    endMonth: buf.readUInt8(25),
    endDay: buf.readUInt8(26),
    endHour: buf.readUInt8(27),
    endMin: buf.readUInt8(28),
    endSeconds: buf.readUInt8(29)
  };
  return { media, consumed: 32 };
}
function parseInfoV2(buf) {
  if (buf.length < 32) return null;
  const headerSize = buf.readUInt32LE(4);
  if (headerSize !== 32) return null;
  const media = {
    type: "InfoV2",
    videoWidth: buf.readUInt32LE(8),
    videoHeight: buf.readUInt32LE(12),
    fps: buf.readUInt8(17),
    startYear: buf.readUInt8(18),
    startMonth: buf.readUInt8(19),
    startDay: buf.readUInt8(20),
    startHour: buf.readUInt8(21),
    startMin: buf.readUInt8(22),
    startSeconds: buf.readUInt8(23),
    endYear: buf.readUInt8(24),
    endMonth: buf.readUInt8(25),
    endDay: buf.readUInt8(26),
    endHour: buf.readUInt8(27),
    endMin: buf.readUInt8(28),
    endSeconds: buf.readUInt8(29)
  };
  return { media, consumed: 32 };
}
function parseIframe(buf) {
  if (buf.length < 20) return null;
  const videoTypeStr = buf.toString("utf8", 4, 8);
  if (videoTypeStr !== "H264" && videoTypeStr !== "H265") return null;
  const videoType = videoTypeStr;
  const payloadSize = buf.readUInt32LE(8);
  const additionalHeaderSize = buf.readUInt32LE(12);
  const microseconds = buf.readUInt32LE(16);
  let offset = 20;
  const unknown = buf.readUInt32LE(offset);
  offset += 4;
  let time;
  if (buf.length < offset + additionalHeaderSize) return null;
  const additionalHeader = buf.subarray(offset, offset + additionalHeaderSize);
  if (additionalHeaderSize >= 4) {
    time = additionalHeader.readUInt32LE(0);
  }
  offset += additionalHeaderSize;
  if (buf.length < offset + payloadSize) return null;
  const data = buf.subarray(offset, offset + payloadSize);
  offset += payloadSize;
  const padSize = payloadSize % PAD_SIZE === 0 ? 0 : PAD_SIZE - payloadSize % PAD_SIZE;
  if (buf.length < offset + padSize) return null;
  offset += padSize;
  const media = {
    type: "Iframe",
    videoType,
    microseconds,
    ...time !== void 0 ? { time } : {},
    additionalHeader,
    additionalHeaderSize,
    unknown,
    data
  };
  return { media, consumed: offset };
}
function parsePframe(buf) {
  if (buf.length < 20) return null;
  const videoTypeStr = buf.toString("utf8", 4, 8);
  if (videoTypeStr !== "H264" && videoTypeStr !== "H265") return null;
  const videoType = videoTypeStr;
  const payloadSize = buf.readUInt32LE(8);
  const additionalHeaderSize = buf.readUInt32LE(12);
  const microseconds = buf.readUInt32LE(16);
  let offset = 20;
  const unknown = buf.readUInt32LE(offset);
  offset += 4;
  if (buf.length < offset + additionalHeaderSize) return null;
  const additionalHeader = buf.subarray(offset, offset + additionalHeaderSize);
  offset += additionalHeaderSize;
  if (buf.length < offset + payloadSize) return null;
  const data = buf.subarray(offset, offset + payloadSize);
  offset += payloadSize;
  const padSize = payloadSize % PAD_SIZE === 0 ? 0 : PAD_SIZE - payloadSize % PAD_SIZE;
  if (buf.length < offset + padSize) return null;
  offset += padSize;
  const media = {
    type: "Pframe",
    videoType,
    microseconds,
    additionalHeader,
    additionalHeaderSize,
    unknown,
    data
  };
  return { media, consumed: offset };
}
function parseAac(buf) {
  if (buf.length < 12) return null;
  const payloadSize = buf.readUInt16LE(4);
  const payloadSizeB = buf.readUInt16LE(6);
  if (payloadSize !== payloadSizeB) return null;
  const headerLen = 8;
  const padSize = payloadSize % PAD_SIZE === 0 ? 0 : PAD_SIZE - payloadSize % PAD_SIZE;
  const totalLen = headerLen + payloadSize + padSize;
  if (buf.length < totalLen) return null;
  const data = buf.subarray(headerLen, headerLen + payloadSize);
  const media = {
    type: "Aac",
    data
  };
  return { media, consumed: totalLen };
}
function parseAdpcm(buf) {
  if (buf.length < 12) return null;
  const payloadSize = buf.readUInt16LE(4);
  const payloadSizeB = buf.readUInt16LE(6);
  if (payloadSize !== payloadSizeB) return null;
  const magicData = buf.readUInt16LE(8);
  if (magicData !== 256) return null;
  const halfBlockSize = buf.readUInt16LE(10);
  void halfBlockSize;
  const subHeaderSize = 4;
  if (payloadSize < subHeaderSize) return null;
  const blockSize = payloadSize - subHeaderSize;
  const headerLen = 12;
  const padSize = payloadSize % PAD_SIZE === 0 ? 0 : PAD_SIZE - payloadSize % PAD_SIZE;
  const totalLen = headerLen + blockSize + padSize;
  if (buf.length < totalLen) return null;
  const data = buf.subarray(headerLen, headerLen + blockSize);
  const media = {
    type: "Adpcm",
    data
  };
  return { media, consumed: totalLen };
}

// src/baichuan/stream/BcMediaCodec.ts
var BcMediaCodec = class {
  buffer = Buffer.alloc(0);
  strict;
  amountSkipped = 0;
  logger;
  onUnknownChunk;
  constructor(strict = false, logger) {
    this.strict = strict;
    this.logger = logger;
  }
  /** Register a listener that fires for every unknown chunk before recovery. */
  setUnknownChunkListener(listener) {
    this.onUnknownChunk = listener;
  }
  /**
   * Push data into the codec buffer and try to parse complete BcMedia packets.
   * Returns an array of complete BcMedia packets found.
   * 
   * @param chunk - New data chunk to add to buffer
   * @returns Array of complete BcMedia packets (empty if none complete yet)
   */
  decode(chunk) {
    this.buffer = this.buffer.length === 0 ? chunk : Buffer.concat([this.buffer, chunk]);
    const results = [];
    while (this.buffer.length >= 4) {
      const result = parseBcMedia(this.buffer);
      if (result) {
        if (this.amountSkipped > 0) {
          if (this.strict) {
            this.logger?.warn(`[BcMediaCodec] Recovered stream after skipping ${this.amountSkipped} bytes`);
          } else {
            this.logger?.warn(`[BcMediaCodec] Recovered stream after skipping ${this.amountSkipped} bytes`);
          }
          this.amountSkipped = 0;
        }
        results.push(result.media);
        this.buffer = this.buffer.subarray(result.consumed);
      } else {
        const isKnownMagic = (magic2) => {
          const isInfoV1 = magic2 === 825241649;
          const isInfoV2 = magic2 === 842018865;
          const isIFrame = magic2 >= 1667510320 && magic2 <= 1667510329;
          const isPFrame = magic2 >= 1667510576 && magic2 <= 1667510585;
          const isAac = magic2 === 1651979568;
          const isAdpcm = magic2 === 1651978544;
          return isInfoV1 || isInfoV2 || isIFrame || isPFrame || isAac || isAdpcm;
        };
        const magic = this.buffer.readUInt32LE(0);
        const startsWithKnownMagic = isKnownMagic(magic);
        if (startsWithKnownMagic) {
          break;
        }
        if (this.strict) {
          throw new Error(`[BcMediaCodec] Invalid data in stream (no valid magic at buffer start, len=${this.buffer.length})`);
        }
        if (this.amountSkipped === 0) {
          this.logger?.warn(`[BcMediaCodec] Error in stream, attempting to recover...`);
        }
        let next = -1;
        for (const off of [528, 1056, 1584]) {
          if (this.buffer.length >= off + 4 && isKnownMagic(this.buffer.readUInt32LE(off))) {
            next = off;
            break;
          }
        }
        if (next < 0) {
          for (let i = 1; i <= this.buffer.length - 4; i++) {
            if (isKnownMagic(this.buffer.readUInt32LE(i))) {
              next = i;
              break;
            }
          }
        }
        if (next > 0) {
          if (this.onUnknownChunk) {
            this.onUnknownChunk({
              magic,
              preview: Buffer.from(this.buffer.subarray(0, Math.min(256, next))),
              skipped: next
            });
          }
          this.amountSkipped += next;
          this.buffer = this.buffer.subarray(next);
          continue;
        }
        if (this.buffer.length > 3) {
          const keep = 3;
          this.amountSkipped += this.buffer.length - keep;
          this.buffer = this.buffer.subarray(this.buffer.length - keep);
        }
        break;
      }
    }
    return results;
  }
  /**
   * Get remaining buffer (for debugging)
   */
  getRemainingBuffer() {
    return this.buffer;
  }
  /**
   * Clear the buffer (useful for resetting the codec)
   */
  clear() {
    this.buffer = Buffer.alloc(0);
    this.amountSkipped = 0;
  }
};

// src/baichuan/stream/H264Converter.ts
var NAL_START_CODE_4B = Buffer.from([0, 0, 0, 1]);
var NAL_START_CODE_3B = Buffer.from([0, 0, 1]);
function hasStartCodes(data) {
  if (data.length < 4) return false;
  if (data.subarray(0, 4).equals(NAL_START_CODE_4B)) return true;
  if (data.subarray(0, 3).equals(NAL_START_CODE_3B)) return true;
  return false;
}
function tryConvertWithLengthReader(data, readLen) {
  const result = [];
  let offset = 0;
  let nalCount = 0;
  while (offset < data.length) {
    if (offset + 4 > data.length) return null;
    const nalLength = readLen(data, offset);
    offset += 4;
    if (nalLength <= 0) return null;
    if (nalLength > data.length - offset) return null;
    result.push(NAL_START_CODE_4B);
    result.push(data.subarray(offset, offset + nalLength));
    offset += nalLength;
    nalCount++;
  }
  if (nalCount === 0) return null;
  return Buffer.concat(result);
}
function tryConvertWithLengthReader16(data, readLen) {
  const result = [];
  let offset = 0;
  let nalCount = 0;
  while (offset < data.length) {
    if (offset + 2 > data.length) return null;
    const nalLength = readLen(data, offset);
    offset += 2;
    if (nalLength <= 0) return null;
    if (nalLength > data.length - offset) return null;
    result.push(NAL_START_CODE_4B);
    result.push(data.subarray(offset, offset + nalLength));
    offset += nalLength;
    nalCount++;
  }
  if (nalCount === 0) return null;
  return Buffer.concat(result);
}
function tryConvertWithLengthReader24(data, endian) {
  const result = [];
  let offset = 0;
  let nalCount = 0;
  const readLen24 = (buf, at) => {
    if (at + 3 > buf.length) return 0;
    const b0 = buf[at];
    const b1 = buf[at + 1];
    const b2 = buf[at + 2];
    return endian === "be" ? (b0 << 16 | b1 << 8 | b2) >>> 0 : (b2 << 16 | b1 << 8 | b0) >>> 0;
  };
  while (offset < data.length) {
    if (offset + 3 > data.length) return null;
    const nalLength = readLen24(data, offset);
    offset += 3;
    if (nalLength <= 0) return null;
    if (nalLength > data.length - offset) return null;
    result.push(NAL_START_CODE_4B);
    result.push(data.subarray(offset, offset + nalLength));
    offset += nalLength;
    nalCount++;
  }
  if (nalCount === 0) return null;
  return Buffer.concat(result);
}
function looksLikeSingleH264Nal(nalPayload) {
  if (nalPayload.length < 1) return false;
  const b0 = nalPayload[0];
  if (b0 === void 0) return false;
  if ((b0 & 128) !== 0) return false;
  const nalType = b0 & 31;
  return nalType >= 1 && nalType <= 23;
}
function depacketizeRtpAggregationToAnnexB(payload) {
  if (payload.length < 1) return null;
  const nalHeader = payload[0];
  const nalType = nalHeader & 31;
  const out = [];
  const pushNal = (nal) => {
    if (nal.length === 0) return;
    out.push(NAL_START_CODE_4B, nal);
  };
  if (nalType === 24) {
    let off = 1;
    while (off + 2 <= payload.length) {
      const size = payload.readUInt16BE(off);
      off += 2;
      if (size <= 0 || off + size > payload.length) return null;
      pushNal(payload.subarray(off, off + size));
      off += size;
    }
    return out.length ? Buffer.concat(out) : null;
  }
  if (nalType === 25) {
    let off = 1 + 2;
    if (off > payload.length) return null;
    while (off + 2 <= payload.length) {
      const size = payload.readUInt16BE(off);
      off += 2;
      if (size <= 0 || off + size > payload.length) return null;
      pushNal(payload.subarray(off, off + size));
      off += size;
    }
    return out.length ? Buffer.concat(out) : null;
  }
  if (nalType === 26) {
    let off = 1 + 2;
    if (off > payload.length) return null;
    while (off + 2 <= payload.length) {
      const size = payload.readUInt16BE(off);
      off += 2;
      if (off + 1 + 2 > payload.length) return null;
      off += 1;
      off += 2;
      if (size <= 0 || off + size > payload.length) return null;
      pushNal(payload.subarray(off, off + size));
      off += size;
    }
    return out.length ? Buffer.concat(out) : null;
  }
  if (nalType === 27) {
    let off = 1 + 2;
    if (off > payload.length) return null;
    while (off + 2 <= payload.length) {
      const size = payload.readUInt16BE(off);
      off += 2;
      if (off + 1 + 3 > payload.length) return null;
      off += 1;
      off += 3;
      if (size <= 0 || off + size > payload.length) return null;
      pushNal(payload.subarray(off, off + size));
      off += size;
    }
    return out.length ? Buffer.concat(out) : null;
  }
  return null;
}
function convertToAnnexB(data) {
  if (hasStartCodes(data)) {
    return data;
  }
  const sc4 = Buffer.from([0, 0, 0, 1]);
  const sc3 = Buffer.from([0, 0, 1]);
  const maxScan = Math.min(64, data.length);
  const idx4 = data.subarray(0, maxScan).indexOf(sc4);
  if (idx4 > 0) return data.subarray(idx4);
  const idx3 = data.subarray(0, maxScan).indexOf(sc3);
  if (idx3 > 0) return data.subarray(idx3);
  const be = tryConvertWithLengthReader(data, (b, o) => b.readUInt32BE(o));
  if (be) return be;
  const le = tryConvertWithLengthReader(data, (b, o) => b.readUInt32LE(o));
  if (le) return le;
  const be24 = tryConvertWithLengthReader24(data, "be");
  if (be24) return be24;
  const le24 = tryConvertWithLengthReader24(data, "le");
  if (le24) return le24;
  const be16 = tryConvertWithLengthReader16(data, (b, o) => b.readUInt16BE(o));
  if (be16) return be16;
  const le16 = tryConvertWithLengthReader16(data, (b, o) => b.readUInt16LE(o));
  if (le16) return le16;
  const agg = depacketizeRtpAggregationToAnnexB(data);
  if (agg) return agg;
  if (looksLikeSingleH264Nal(data)) {
    return Buffer.concat([NAL_START_CODE_4B, data]);
  }
  return data;
}
function splitAnnexBToNalPayloads(annexB) {
  const starts = [];
  for (let i = 0; i < annexB.length - 3; i++) {
    if (annexB[i] === 0 && annexB[i + 1] === 0) {
      if (annexB[i + 2] === 1) {
        starts.push({ idx: i, len: 3 });
        i += 2;
      } else if (annexB[i + 2] === 0 && annexB[i + 3] === 1) {
        starts.push({ idx: i, len: 4 });
        i += 3;
      }
    }
  }
  if (starts.length === 0) return [];
  const out = [];
  for (let s = 0; s < starts.length; s++) {
    const st = starts[s];
    const start = st.idx + st.len;
    const end = starts[s + 1] ? starts[s + 1].idx : annexB.length;
    if (end > start) out.push(annexB.subarray(start, end));
  }
  return out;
}
function isValidH264AnnexBAccessUnit(annexB) {
  if (!hasStartCodes(annexB)) return false;
  const nals = splitAnnexBToNalPayloads(annexB);
  if (nals.length === 0) return false;
  for (const nal of nals) {
    if (nal.length < 1) return false;
    const b0 = nal[0];
    if (b0 === void 0) return false;
    if ((b0 & 128) !== 0) return false;
    const nalType = b0 & 31;
    if (nalType === 0 || nalType >= 24) return false;
  }
  return true;
}
function isH264KeyframeAnnexB(annexB) {
  const nals = splitAnnexBToNalPayloads(annexB);
  let hasSps = false;
  let hasPps = false;
  let hasIdr = false;
  for (const nal of nals) {
    const t = (nal[0] ?? 0) & 31;
    if (t === 7) hasSps = true;
    if (t === 8) hasPps = true;
    if (t === 5) hasIdr = true;
  }
  return hasIdr && hasSps && hasPps;
}
var H264RtpDepacketizer = class _H264RtpDepacketizer {
  fuNalHeader = null;
  fuParts = [];
  static parseRtpPayload(packet) {
    if (!packet || packet.length < 12) return null;
    const version = packet[0] >> 6 & 3;
    if (version !== 2) return null;
    const padding = (packet[0] & 32) !== 0;
    const extension = (packet[0] & 16) !== 0;
    const csrcCount = packet[0] & 15;
    let offset = 12 + csrcCount * 4;
    if (offset > packet.length) return null;
    if (extension) {
      if (offset + 4 > packet.length) return null;
      const extLenWords = packet.readUInt16BE(offset + 2);
      offset += 4 + extLenWords * 4;
      if (offset > packet.length) return null;
    }
    let end = packet.length;
    if (padding) {
      const padLen = packet[packet.length - 1];
      if (padLen <= 0 || padLen > packet.length) return null;
      end = packet.length - padLen;
      if (end < offset) return null;
    }
    if (end <= offset) return null;
    return packet.subarray(offset, end);
  }
  reset() {
    this.fuNalHeader = null;
    this.fuParts = [];
  }
  push(payload) {
    if (payload.length === 0) return [];
    const rtpPayload = _H264RtpDepacketizer.parseRtpPayload(payload);
    if (rtpPayload) payload = rtpPayload;
    if (hasStartCodes(payload)) return [payload];
    const b0 = payload[0];
    if ((b0 & 128) !== 0) return [];
    const nalType = b0 & 31;
    if (nalType >= 1 && nalType <= 23) {
      return [Buffer.concat([NAL_START_CODE_4B, payload])];
    }
    if (nalType === 24) {
      if (payload.length < 1 + 2) return [];
      let off = 1;
      const out = [];
      while (off + 2 <= payload.length) {
        const size = payload.readUInt16BE(off);
        off += 2;
        if (size <= 0 || off + size > payload.length) return [];
        const nal = payload.subarray(off, off + size);
        off += size;
        if (nal.length < 1) return [];
        if ((nal[0] & 128) !== 0) return [];
        const t = nal[0] & 31;
        if (t === 0 || t >= 24) return [];
        out.push(Buffer.concat([NAL_START_CODE_4B, nal]));
      }
      return out;
    }
    if (nalType === 28 || nalType === 29) {
      if (payload.length < 2) return [];
      const fuIndicator = payload[0];
      const fuHeader = payload[1];
      const start = (fuHeader & 128) !== 0;
      const end = (fuHeader & 64) !== 0;
      const origType = fuHeader & 31;
      const reconstructedHeader = fuIndicator & 224 | origType;
      let off = 2;
      if (nalType === 29) {
        if (payload.length < off + 2) return [];
        off += 2;
      }
      const frag = payload.subarray(off);
      if (start) {
        this.fuNalHeader = reconstructedHeader;
        this.fuParts = [frag];
      } else if (this.fuNalHeader != null) {
        this.fuParts.push(frag);
      } else {
        return [];
      }
      if (end && this.fuNalHeader != null) {
        const nal = Buffer.concat([Buffer.from([this.fuNalHeader]), ...this.fuParts]);
        this.reset();
        return [Buffer.concat([NAL_START_CODE_4B, nal])];
      }
      return [];
    }
    return [];
  }
};
function convertToLengthPrefixed(data) {
  const result = [];
  let offset = 0;
  while (offset < data.length) {
    let startCodeOffset = -1;
    let startCodeLength = 0;
    if (offset + 4 <= data.length && data.subarray(offset, offset + 4).equals(NAL_START_CODE_4B)) {
      startCodeOffset = offset;
      startCodeLength = 4;
    } else if (offset + 3 <= data.length && data.subarray(offset, offset + 3).equals(NAL_START_CODE_3B)) {
      startCodeOffset = offset;
      startCodeLength = 3;
    }
    if (startCodeOffset === -1) {
      result.push(data.subarray(offset));
      break;
    }
    offset = startCodeOffset + startCodeLength;
    let nextStartCode = -1;
    let nextStartCodeLength = 0;
    for (let i = offset; i < data.length - 3; i++) {
      if (i + 4 <= data.length && data.subarray(i, i + 4).equals(NAL_START_CODE_4B)) {
        nextStartCode = i;
        nextStartCodeLength = 4;
        break;
      }
      if (i + 3 <= data.length && data.subarray(i, i + 3).equals(NAL_START_CODE_3B)) {
        nextStartCode = i;
        nextStartCodeLength = 3;
        break;
      }
    }
    const nalEnd = nextStartCode !== -1 ? nextStartCode : data.length;
    const nalData = data.subarray(offset, nalEnd);
    const lengthBuf = Buffer.alloc(4);
    lengthBuf.writeUInt32BE(nalData.length, 0);
    result.push(lengthBuf);
    result.push(nalData);
    offset = nalEnd;
  }
  return Buffer.concat(result);
}

// src/baichuan/stream/H265Converter.ts
var NAL_START_CODE_4B2 = Buffer.from([0, 0, 0, 1]);
var NAL_START_CODE_3B2 = Buffer.from([0, 0, 1]);
function hasStartCodes2(data) {
  if (data.length < 4) return false;
  if (data.subarray(0, 4).equals(NAL_START_CODE_4B2)) return true;
  if (data.subarray(0, 3).equals(NAL_START_CODE_3B2)) return true;
  return false;
}
function tryConvertWithLengthReader2(data, readLen) {
  const result = [];
  let offset = 0;
  let nalCount = 0;
  while (offset < data.length) {
    if (offset + 4 > data.length) return null;
    const nalLength = readLen(data, offset);
    offset += 4;
    if (nalLength <= 0) return null;
    if (nalLength > data.length - offset) return null;
    result.push(NAL_START_CODE_4B2);
    result.push(data.subarray(offset, offset + nalLength));
    offset += nalLength;
    nalCount++;
  }
  if (nalCount === 0) return null;
  return Buffer.concat(result);
}
function tryConvertWithLengthReader162(data, readLen) {
  const result = [];
  let offset = 0;
  let nalCount = 0;
  while (offset < data.length) {
    if (offset + 2 > data.length) return null;
    const nalLength = readLen(data, offset);
    offset += 2;
    if (nalLength <= 0) return null;
    if (nalLength > data.length - offset) return null;
    result.push(NAL_START_CODE_4B2);
    result.push(data.subarray(offset, offset + nalLength));
    offset += nalLength;
    nalCount++;
  }
  if (nalCount === 0) return null;
  return Buffer.concat(result);
}
function tryConvertWithLengthReader242(data, endian) {
  const result = [];
  let offset = 0;
  let nalCount = 0;
  const readLen24 = (buf, at) => {
    if (at + 3 > buf.length) return 0;
    const b0 = buf[at];
    const b1 = buf[at + 1];
    const b2 = buf[at + 2];
    return endian === "be" ? (b0 << 16 | b1 << 8 | b2) >>> 0 : (b2 << 16 | b1 << 8 | b0) >>> 0;
  };
  while (offset < data.length) {
    if (offset + 3 > data.length) return null;
    const nalLength = readLen24(data, offset);
    offset += 3;
    if (nalLength <= 0) return null;
    if (nalLength > data.length - offset) return null;
    result.push(NAL_START_CODE_4B2);
    result.push(data.subarray(offset, offset + nalLength));
    offset += nalLength;
    nalCount++;
  }
  if (nalCount === 0) return null;
  return Buffer.concat(result);
}
function looksLikeSingleH265Nal(nalPayload) {
  if (nalPayload.length < 2) return false;
  const b0 = nalPayload[0];
  const b1 = nalPayload[1];
  if (b0 === void 0 || b1 === void 0) return false;
  if ((b0 & 128) !== 0) return false;
  const nalType = b0 >> 1 & 63;
  return nalType <= 40;
}
function convertToAnnexB2(data) {
  if (hasStartCodes2(data)) {
    return data;
  }
  const sc4 = Buffer.from([0, 0, 0, 1]);
  const sc3 = Buffer.from([0, 0, 1]);
  const maxScan = Math.min(64, data.length);
  const idx4 = data.subarray(0, maxScan).indexOf(sc4);
  if (idx4 > 0) return data.subarray(idx4);
  const idx3 = data.subarray(0, maxScan).indexOf(sc3);
  if (idx3 > 0) return data.subarray(idx3);
  const be = tryConvertWithLengthReader2(data, (b, o) => b.readUInt32BE(o));
  if (be) return be;
  const le = tryConvertWithLengthReader2(data, (b, o) => b.readUInt32LE(o));
  if (le) return le;
  const be24 = tryConvertWithLengthReader242(data, "be");
  if (be24) return be24;
  const le24 = tryConvertWithLengthReader242(data, "le");
  if (le24) return le24;
  const be16 = tryConvertWithLengthReader162(data, (b, o) => b.readUInt16BE(o));
  if (be16) return be16;
  const le16 = tryConvertWithLengthReader162(data, (b, o) => b.readUInt16LE(o));
  if (le16) return le16;
  if (looksLikeSingleH265Nal(data)) {
    return Buffer.concat([NAL_START_CODE_4B2, data]);
  }
  return data;
}
var H265RtpDepacketizer = class _H265RtpDepacketizer {
  fuParts = null;
  reset() {
    this.fuParts = null;
  }
  static parseRtpPayload(packet) {
    if (!packet || packet.length < 12) return null;
    const version = packet[0] >> 6 & 3;
    if (version !== 2) return null;
    const padding = (packet[0] & 32) !== 0;
    const extension = (packet[0] & 16) !== 0;
    const csrcCount = packet[0] & 15;
    let offset = 12 + csrcCount * 4;
    if (offset > packet.length) return null;
    if (extension) {
      if (offset + 4 > packet.length) return null;
      const extLenWords = packet.readUInt16BE(offset + 2);
      offset += 4 + extLenWords * 4;
      if (offset > packet.length) return null;
    }
    let end = packet.length;
    if (padding) {
      const padLen = packet[packet.length - 1];
      if (padLen <= 0 || padLen > packet.length) return null;
      end = packet.length - padLen;
      if (end < offset) return null;
    }
    if (end <= offset) return null;
    return packet.subarray(offset, end);
  }
  push(payload) {
    if (!payload || payload.length < 2) return [];
    const rtpPayload = _H265RtpDepacketizer.parseRtpPayload(payload);
    if (rtpPayload) payload = rtpPayload;
    const h0 = payload[0];
    const h1 = payload[1];
    if ((h0 & 128) !== 0) return [];
    const nalType = h0 >> 1 & 63;
    if (nalType === 48) {
      let off = 2;
      const out = [];
      while (off + 2 <= payload.length) {
        const size = payload.readUInt16BE(off);
        off += 2;
        if (size <= 0 || off + size > payload.length) return [];
        const nal = payload.subarray(off, off + size);
        off += size;
        if (nal.length) out.push(NAL_START_CODE_4B2, nal);
      }
      return out.length ? [Buffer.concat(out)] : [];
    }
    if (nalType === 49) {
      if (payload.length < 3) return [];
      const fuHeader = payload[2];
      const start = (fuHeader & 128) !== 0;
      const end = (fuHeader & 64) !== 0;
      const origType = fuHeader & 63;
      const orig0 = h0 & 129 | (origType & 63) << 1;
      const orig1 = h1;
      const frag = payload.subarray(3);
      if (start) {
        this.fuParts = [NAL_START_CODE_4B2, Buffer.from([orig0, orig1]), frag];
      } else {
        if (!this.fuParts) return [];
        this.fuParts.push(frag);
      }
      if (end) {
        if (!this.fuParts) return [];
        const out = Buffer.concat(this.fuParts);
        this.fuParts = null;
        return [out];
      }
      return [];
    }
    return [Buffer.concat([NAL_START_CODE_4B2, payload])];
  }
};
function splitAnnexBToNalPayloads2(annexB) {
  const starts = [];
  for (let i = 0; i < annexB.length - 3; i++) {
    if (annexB[i] === 0 && annexB[i + 1] === 0) {
      if (annexB[i + 2] === 1) {
        starts.push({ idx: i, len: 3 });
        i += 2;
      } else if (annexB[i + 2] === 0 && annexB[i + 3] === 1) {
        starts.push({ idx: i, len: 4 });
        i += 3;
      }
    }
  }
  if (starts.length === 0) return [];
  const out = [];
  for (let s = 0; s < starts.length; s++) {
    const st = starts[s];
    const start = st.idx + st.len;
    const end = starts[s + 1] ? starts[s + 1].idx : annexB.length;
    if (end > start) out.push(annexB.subarray(start, end));
  }
  return out;
}
function getH265NalType(nalPayload) {
  if (nalPayload.length < 1) return null;
  const b0 = nalPayload[0];
  if (b0 === void 0) return null;
  if ((b0 & 128) !== 0) return null;
  return b0 >> 1 & 63;
}
function isH265Irap(nalType) {
  return nalType >= 16 && nalType <= 23;
}
function isValidH265AnnexBAccessUnit(annexB) {
  if (!hasStartCodes2(annexB)) return false;
  const nals = splitAnnexBToNalPayloads2(annexB);
  if (nals.length === 0) return false;
  for (const nal of nals) {
    if (nal.length < 2) return false;
    const b0 = nal[0];
    if (b0 === void 0) return false;
    if ((b0 & 128) !== 0) return false;
    const nalType = getH265NalType(nal);
    if (nalType === null) return false;
    if (nalType > 40) return false;
  }
  return true;
}
function isH265KeyframeAnnexB(annexB) {
  const nals = splitAnnexBToNalPayloads2(annexB);
  let hasVps = false;
  let hasSps = false;
  let hasPps = false;
  let hasIrap = false;
  for (const nal of nals) {
    const nalType = getH265NalType(nal);
    if (nalType === null) continue;
    if (nalType === 32) hasVps = true;
    if (nalType === 33) hasSps = true;
    if (nalType === 34) hasPps = true;
    if (isH265Irap(nalType)) hasIrap = true;
  }
  return hasIrap && hasVps && hasSps && hasPps;
}
function extractVpsFromAnnexB(annexB) {
  const nals = splitAnnexBToNalPayloads2(annexB);
  for (const nal of nals) {
    const nalType = getH265NalType(nal);
    if (nalType === 32) {
      return nal;
    }
  }
  return null;
}
function extractSpsFromAnnexB(annexB) {
  const nals = splitAnnexBToNalPayloads2(annexB);
  for (const nal of nals) {
    const nalType = getH265NalType(nal);
    if (nalType === 33) {
      return nal;
    }
  }
  return null;
}
function extractPpsFromAnnexB(annexB) {
  const nals = splitAnnexBToNalPayloads2(annexB);
  for (const nal of nals) {
    const nalType = getH265NalType(nal);
    if (nalType === 34) {
      return nal;
    }
  }
  return null;
}

// src/baichuan/stream/BcMediaAnnexBDecoder.ts
var ANNEXB_START_CODE_4B = Buffer.from([0, 0, 0, 1]);
function detectVideoCodecFromNal(data) {
  if (!data || data.length < 5) return null;
  let nalStart = -1;
  for (let i = 0; i < Math.min(data.length - 4, 100); i++) {
    if (data[i] === 0 && data[i + 1] === 0) {
      if (data[i + 2] === 0 && data[i + 3] === 1) {
        nalStart = i + 4;
        break;
      }
      if (data[i + 2] === 1) {
        nalStart = i + 3;
        break;
      }
    }
  }
  if (nalStart < 0 && data.length >= 5) {
    const len = data.readUInt32BE(0);
    if (len > 0 && len < data.length - 4) {
      nalStart = 4;
    }
  }
  if (nalStart < 0 || nalStart >= data.length) return null;
  const nalByte = data[nalStart];
  if (nalByte === void 0) return null;
  const forbiddenBit264 = nalByte >> 7 & 1;
  const h264Type = nalByte & 31;
  if (forbiddenBit264 === 0 && h264Type > 0 && h264Type <= 12) {
    if (h264Type === 7 || h264Type === 8) {
      return "H264";
    }
    if (h264Type === 5) {
      return "H264";
    }
    if (h264Type === 1) {
      const nalRefIdc = nalByte >> 5 & 3;
      if (nalRefIdc >= 1) {
        return "H264";
      }
    }
  }
  if (nalStart + 1 < data.length) {
    const nalByte2 = data[nalStart + 1];
    if (nalByte2 !== void 0) {
      const forbiddenBit = nalByte >> 7 & 1;
      const hevcType = nalByte >> 1 & 63;
      const temporalId = nalByte2 & 7;
      if (forbiddenBit === 0 && temporalId > 0 && hevcType <= 40) {
        if (hevcType === 32 || hevcType === 33 || hevcType === 34) {
          return "H265";
        }
        if (hevcType === 19 || hevcType === 20 || hevcType === 21) {
          return "H265";
        }
        if (hevcType <= 1 && nalByte <= 3) {
          return "H265";
        }
      }
    }
  }
  return null;
}
var BcMediaAnnexBDecoder = class {
  codec;
  logger;
  onVideoAccessUnit;
  onAudioFrame;
  stats = {
    bytesIn: 0,
    bytesOut: 0,
    audioBytesOut: 0,
    packets: 0,
    videoPackets: 0,
    audioPackets: 0,
    aacPackets: 0,
    adpcmPackets: 0,
    keyframes: 0,
    videoType: null,
    audioType: null,
    infos: [],
    recoveredSkips: 0
  };
  lastH264Sps = null;
  lastH264Pps = null;
  lastH265Vps = null;
  lastH265Sps = null;
  lastH265Pps = null;
  constructor(params) {
    this.logger = params?.logger;
    this.onVideoAccessUnit = params?.onVideoAccessUnit;
    this.onAudioFrame = params?.onAudioFrame;
    this.codec = new BcMediaCodec(params?.strict ?? false, this.logger);
  }
  getStats() {
    return { ...this.stats, infos: [...this.stats.infos] };
  }
  /**
   * Push arbitrary bytes from a Baichuan/BcMedia transport into the decoder.
   * Emits complete Annex-B access units via callback.
   */
  push(chunk) {
    if (!chunk || chunk.length === 0) return;
    this.stats.bytesIn += chunk.length;
    const packets = this.codec.decode(chunk);
    this.stats.packets += packets.length;
    for (const media of packets) {
      this.handleMedia(media);
    }
  }
  handleMedia(media) {
    if (media.type === "InfoV1" || media.type === "InfoV2") {
      const info = media;
      this.stats.infos.push({
        type: media.type,
        videoWidth: info.videoWidth,
        videoHeight: info.videoHeight,
        fps: info.fps,
        startYear: info.startYear,
        startMonth: info.startMonth,
        startDay: info.startDay,
        startHour: info.startHour,
        startMin: info.startMin,
        startSeconds: info.startSeconds,
        endYear: info.endYear,
        endMonth: info.endMonth,
        endDay: info.endDay,
        endHour: info.endHour,
        endMin: info.endMin,
        endSeconds: info.endSeconds
      });
      return;
    }
    if (media.type === "Aac" || media.type === "Adpcm") {
      const audioMedia = media;
      this.stats.audioPackets++;
      if (media.type === "Aac") {
        this.stats.aacPackets++;
      } else {
        this.stats.adpcmPackets++;
      }
      if (this.stats.audioType == null) {
        this.stats.audioType = media.type;
      }
      if (this.onAudioFrame) {
        this.stats.audioBytesOut += audioMedia.data.length;
        this.onAudioFrame({
          audioType: media.type,
          data: audioMedia.data
        });
      }
      return;
    }
    if (media.type !== "Iframe" && media.type !== "Pframe") return;
    this.stats.videoPackets++;
    const microseconds = media.microseconds;
    const raw = media.data;
    let videoType = media.videoType;
    const detectedType = detectVideoCodecFromNal(raw);
    if (detectedType != null && detectedType !== videoType) {
      this.logger?.debug?.(
        `[BcMediaAnnexBDecoder] Codec mismatch: reported ${videoType}, detected ${detectedType}`
      );
      videoType = detectedType;
    }
    if (this.stats.videoType == null) this.stats.videoType = videoType;
    let annexB = videoType === "H265" ? convertToAnnexB2(raw) : convertToAnnexB(raw);
    const isKeyframe = media.type === "Iframe" || (videoType === "H265" ? isH265KeyframeAnnexB(annexB) : isH264KeyframeAnnexB(annexB));
    if (videoType === "H264") {
      const nals = splitAnnexBToNalPayloads(annexB);
      for (const nal of nals) {
        const t = (nal[0] ?? 0) & 31;
        if (t === 7) this.lastH264Sps = nal;
        if (t === 8) this.lastH264Pps = nal;
      }
      if (isKeyframe) {
        const hasSps = nals.some((nal) => ((nal[0] ?? 0) & 31) === 7);
        const hasPps = nals.some((nal) => ((nal[0] ?? 0) & 31) === 8);
        const toPrepend = [];
        if (!hasSps && this.lastH264Sps)
          toPrepend.push(ANNEXB_START_CODE_4B, this.lastH264Sps);
        if (!hasPps && this.lastH264Pps)
          toPrepend.push(ANNEXB_START_CODE_4B, this.lastH264Pps);
        if (toPrepend.length > 0)
          annexB = Buffer.concat([...toPrepend, annexB]);
      }
    } else {
      const vps = extractVpsFromAnnexB(annexB);
      const sps = extractSpsFromAnnexB(annexB);
      const pps = extractPpsFromAnnexB(annexB);
      if (vps) this.lastH265Vps = vps;
      if (sps) this.lastH265Sps = sps;
      if (pps) this.lastH265Pps = pps;
      if (isKeyframe) {
        const hasVps = vps != null;
        const hasSps = sps != null;
        const hasPps = pps != null;
        const toPrepend = [];
        if (!hasVps && this.lastH265Vps)
          toPrepend.push(ANNEXB_START_CODE_4B, this.lastH265Vps);
        if (!hasSps && this.lastH265Sps)
          toPrepend.push(ANNEXB_START_CODE_4B, this.lastH265Sps);
        if (!hasPps && this.lastH265Pps)
          toPrepend.push(ANNEXB_START_CODE_4B, this.lastH265Pps);
        if (toPrepend.length > 0)
          annexB = Buffer.concat([...toPrepend, annexB]);
      }
    }
    if (isKeyframe) this.stats.keyframes++;
    this.stats.bytesOut += annexB.length;
    this.onVideoAccessUnit?.({ videoType, annexB, microseconds, isKeyframe });
  }
};

// src/baichuan/stream/BaichuanVideoStream.ts
var NAL_START_CODE_4B3 = Buffer.from([0, 0, 0, 1]);
var WATCHDOG_TICK_MS = 1e3;
var WATCHDOG_MAX_RESTARTS_PER_MINUTE = 3;
var AsyncFsQueue = class {
  running = false;
  queue = [];
  maxQueueSize;
  constructor(maxQueueSize) {
    this.maxQueueSize = maxQueueSize;
  }
  enqueue(task) {
    if (this.queue.length >= this.maxQueueSize) return;
    this.queue.push(task);
    this.pump();
  }
  pump() {
    if (this.running) return;
    this.running = true;
    void this.run();
  }
  async run() {
    try {
      while (this.queue.length > 0) {
        const task = this.queue.shift();
        if (!task) continue;
        try {
          await task();
        } catch {
        }
      }
    } finally {
      this.running = false;
    }
  }
};
function removeEmulationPreventionBytes(rbsp) {
  const out = [];
  for (let i = 0; i < rbsp.length; i++) {
    if (i >= 2 && rbsp[i] === 3 && rbsp[i - 1] === 0 && rbsp[i - 2] === 0) {
      continue;
    }
    out.push(rbsp[i]);
  }
  return Buffer.from(out);
}
var BitReader = class {
  b;
  bitPos = 0;
  constructor(buf) {
    this.b = buf;
  }
  readBits(n) {
    if (n <= 0) return 0;
    let v = 0;
    for (let i = 0; i < n; i++) {
      const bytePos = this.bitPos >> 3;
      if (bytePos >= this.b.length) return null;
      const bitInByte = 7 - (this.bitPos & 7);
      const bit = this.b[bytePos] >> bitInByte & 1;
      v = v << 1 | bit;
      this.bitPos++;
    }
    return v >>> 0;
  }
  readUE() {
    let zeros = 0;
    while (true) {
      const bit = this.readBits(1);
      if (bit == null) return null;
      if (bit === 0) zeros++;
      else break;
      if (zeros > 31) return null;
    }
    const rest = zeros ? this.readBits(zeros) : 0;
    if (rest == null) return null;
    return (1 << zeros) - 1 + rest >>> 0;
  }
};
function parseSpsIdFromNal(nalPayload) {
  if (((nalPayload[0] ?? 0) & 31) !== 7) return null;
  const rbsp = removeEmulationPreventionBytes(nalPayload.subarray(1));
  const r = new BitReader(rbsp);
  if (r.readBits(8) == null) return null;
  if (r.readBits(8) == null) return null;
  if (r.readBits(8) == null) return null;
  return r.readUE();
}
function parsePpsIdsFromNal(nalPayload) {
  if (((nalPayload[0] ?? 0) & 31) !== 8) return null;
  const rbsp = removeEmulationPreventionBytes(nalPayload.subarray(1));
  const r = new BitReader(rbsp);
  const ppsId = r.readUE();
  const spsId = r.readUE();
  if (ppsId == null || spsId == null) return null;
  return { ppsId, spsId };
}
function parseSlicePpsIdFromNal(nalPayload) {
  const t = (nalPayload[0] ?? 0) & 31;
  if (t !== 1 && t !== 5) return null;
  const rbsp = removeEmulationPreventionBytes(nalPayload.subarray(1));
  const r = new BitReader(rbsp);
  if (r.readUE() == null) return null;
  if (r.readUE() == null) return null;
  return r.readUE();
}
var BaichuanVideoStream = class _BaichuanVideoStream extends EventEmitter {
  client;
  api;
  channel;
  profile;
  variant;
  logger;
  active = false;
  videoFrameHandler;
  expectedStreamTypes;
  activeMsgNum;
  cmdId;
  acceptAnyStreamType;
  lockedChannelId;
  bcMediaCodec;
  /**
   * Diagnostic-only accessor for the BcMedia codec. Used by tools that need to
   * inspect unknown chunks (for example to discover undocumented audio
   * sub-packets the parser currently skips). Not part of the supported public
   * surface — do not rely on it in application code.
   */
  get _bcMediaCodec() {
    return this.bcMediaCodec;
  }
  debugH264LogsLeft;
  debugSavedSamples;
  warnedNonAnnexBOnce = false;
  // "RTP-like" depacketizer (some models encapsulate NAL units in FU-A/STAP)
  depacketizer = new H264RtpDepacketizer();
  depacketizerH265 = new H265RtpDepacketizer();
  dumpChunkIdx = 0;
  dumpNalLines = 0;
  dumpIo = new AsyncFsQueue(200);
  spsById = /* @__PURE__ */ new Map();
  // NAL payload (without start code) - H.264
  ppsById = /* @__PURE__ */ new Map();
  // NAL payload + mapping - H.264
  lastSps = null;
  // H.264
  lastPps = null;
  // H.264
  lastPrependedPpsId = null;
  // H.264
  // H.265 parameter sets
  lastVps = null;
  // H.265 VPS
  lastSpsH265 = null;
  // H.265 SPS
  lastPpsH265 = null;
  // H.265 PPS
  lastPrependedParamSetsH265 = false;
  // Track if we've prepended H.265 param sets
  // Stateful AES decryptor for fragmented BcMedia packets (full_aes mode)
  // In CFB mode, continuation frames must use the cipher state from previous frames.
  aesStreamDecryptor = null;
  // Latest frame dimensions reported by BcMedia InfoV1/V2 packets.
  // Used to attach width/height context to the `additionalHeader` event so
  // consumers can normalize box coordinates to a fraction of the stream size.
  latestFrameWidth;
  latestFrameHeight;
  // Teardown returned by ReolinkBaichuanApi._registerVideoStreamForDetection.
  // Called from stop() to detach the detection bridge.
  detectionTeardown;
  /**
   * Pending startup error stashed when emitSafeError is called before any
   * "error" listener is registered (e.g. camera returns 400 during start()).
   * The rfc4571-server's waitForKeyframe can consume this immediately instead
   * of waiting for the full keyframe timeout.
   */
  _pendingStartupError;
  /** Consume and clear any pending startup error. */
  consumePendingStartupError() {
    const err = this._pendingStartupError;
    this._pendingStartupError = void 0;
    return err;
  }
  emitSafeError(err) {
    if (!this.active) {
      this.logger?.warn?.(
        `[BaichuanVideoStream] Suppressed error after stop: ${err.message}`
      );
      return;
    }
    if (this.listenerCount("error") === 0) {
      this.logger?.warn?.(
        `[BaichuanVideoStream] Unhandled stream error: ${err.message}`
      );
      this._pendingStartupError = err;
      return;
    }
    this.emit("error", err);
  }
  lastMediaAtMs = 0;
  watchdogTimer;
  restarting = false;
  restartWindowStartMs = 0;
  restartCountInWindow = 0;
  idleRestartMs;
  // Note: reassembly happens at the BcMediaCodec transport level, so we do not
  // accumulate frames here.
  static scoreBcMediaLike(b) {
    if (b.length < 4) return { score: -1, first: -1 };
    const maxScan = Math.min(64 * 1024, b.length - 4);
    let count = 0;
    let first = -1;
    for (let i = 0; i <= maxScan; i++) {
      const magic = b.readUInt32LE(i);
      const isInfoV1 = magic === 825241649;
      const isInfoV2 = magic === 842018865;
      const isIFrame = magic >= 1667510320 && magic <= 1667510329;
      const isPFrame = magic >= 1667510576 && magic <= 1667510585;
      const isAac = magic === 1651979568;
      const isAdpcm = magic === 1651978544;
      if (isInfoV1 || isInfoV2 || isIFrame || isPFrame || isAac || isAdpcm) {
        count++;
        if (first < 0) first = i;
        if (count > 32 && first === 0) break;
      }
    }
    return { score: count * 1e3 - (first < 0 ? 5e4 : first), first };
  }
  chooseDecryptedOrRawCandidate(params) {
    const { raw, enc, channelId, allowResync, encryptLen } = params;
    if (encryptLen !== void 0 && encryptLen > 0 && encryptLen < raw.length) {
      const encryptedPart = raw.subarray(0, encryptLen);
      const clearPart = raw.subarray(encryptLen);
      const decryptedPart = this.client.tryDecryptBinary(
        encryptedPart,
        channelId,
        enc
      );
      const chosen2 = Buffer.concat([decryptedPart, clearPart]);
      if (!allowResync) return chosen2;
      const best2 = _BaichuanVideoStream.scoreBcMediaLike(chosen2);
      return best2.first > 0 ? chosen2.subarray(best2.first) : chosen2;
    }
    if (enc.kind === "full_aes") {
      const key = enc.key;
      const isReplayMode = this.cmdId === 5;
      const freshDecrypted = aesDecrypt(raw, key);
      const freshScore = _BaichuanVideoStream.scoreBcMediaLike(freshDecrypted);
      const rawScore2 = _BaichuanVideoStream.scoreBcMediaLike(raw);
      const startsWithMagic = freshScore.first === 0 && freshScore.score > 0;
      if (!isReplayMode) {
        const chosen3 = freshScore.score > rawScore2.score ? freshDecrypted : raw;
        if (!allowResync) return chosen3;
        const best3 = _BaichuanVideoStream.scoreBcMediaLike(chosen3);
        return best3.first > 0 ? chosen3.subarray(best3.first) : chosen3;
      }
      if (startsWithMagic && freshDecrypted.length >= 24) {
        const magic = freshDecrypted.readUInt32LE(0);
        const isIFrame = magic >= 1667510320 && magic <= 1667510329;
        const isPFrame = magic >= 1667510576 && magic <= 1667510585;
        if ((isIFrame || isPFrame) && freshDecrypted.length >= 24) {
          const additionalHeaderSize = freshDecrypted.readUInt32LE(12);
          const headerLen = 24 + additionalHeaderSize;
          if (headerLen > 0 && headerLen < raw.length) {
            const rawPayloadStart = raw.subarray(headerLen, headerLen + 4);
            const hasRawStartCode = rawPayloadStart.length >= 4 && rawPayloadStart[0] === 0 && rawPayloadStart[1] === 0 && (rawPayloadStart[2] === 1 || rawPayloadStart[2] === 0 && rawPayloadStart[3] === 1);
            if (hasRawStartCode) {
              const headerDecrypted = aesDecrypt(
                raw.subarray(0, headerLen),
                key
              );
              const clearPayload = raw.subarray(headerLen);
              const chosen3 = Buffer.concat([headerDecrypted, clearPayload]);
              if (!allowResync) return chosen3;
              const best3 = _BaichuanVideoStream.scoreBcMediaLike(chosen3);
              return best3.first > 0 ? chosen3.subarray(best3.first) : chosen3;
            }
          }
        }
        const IFRAME_ENCRYPT_BOUNDARY = 1024;
        if (raw.length > IFRAME_ENCRYPT_BOUNDARY) {
          const encryptedPart = raw.subarray(0, IFRAME_ENCRYPT_BOUNDARY);
          const clearPart = raw.subarray(IFRAME_ENCRYPT_BOUNDARY);
          const decryptedPart = aesDecrypt(encryptedPart, key);
          const chosen3 = Buffer.concat([decryptedPart, clearPart]);
          if (!allowResync) return chosen3;
          const best3 = _BaichuanVideoStream.scoreBcMediaLike(chosen3);
          return best3.first > 0 ? chosen3.subarray(best3.first) : chosen3;
        }
        {
          const chosen3 = freshDecrypted;
          if (!allowResync) return chosen3;
          const best3 = _BaichuanVideoStream.scoreBcMediaLike(chosen3);
          return best3.first > 0 ? chosen3.subarray(best3.first) : chosen3;
        }
      }
      if (rawScore2.first === 0 && rawScore2.score > freshScore.score) {
        const chosen3 = raw;
        if (!allowResync) return chosen3;
        const best3 = _BaichuanVideoStream.scoreBcMediaLike(chosen3);
        return best3.first > 0 ? chosen3.subarray(best3.first) : chosen3;
      }
      if (this.aesStreamDecryptor && this.aesStreamDecryptor.isInitialized()) {
        const statefulDecrypted = this.aesStreamDecryptor.update(raw);
        return statefulDecrypted;
      }
      const chosen2 = freshScore.score > rawScore2.score ? freshDecrypted : raw;
      if (!allowResync) return chosen2;
      const best2 = _BaichuanVideoStream.scoreBcMediaLike(chosen2);
      return best2.first > 0 ? chosen2.subarray(best2.first) : chosen2;
    }
    const rawScore = _BaichuanVideoStream.scoreBcMediaLike(raw);
    const dec = this.client.enc.kind === "aes" || this.client.enc.kind === "bc" ? this.client.tryDecryptBinary(raw, channelId, enc) : raw;
    const decScore = _BaichuanVideoStream.scoreBcMediaLike(dec);
    const chosen = decScore.score > rawScore.score ? dec : raw;
    if (!allowResync) return chosen;
    const best = _BaichuanVideoStream.scoreBcMediaLike(chosen);
    return best.first > 0 ? chosen.subarray(best.first) : chosen;
  }
  constructor(options) {
    super();
    this.client = options.client;
    this.api = options.api;
    this.channel = options.channel;
    this.profile = options.profile;
    this.variant = options.variant ?? "default";
    this.logger = options.logger;
    this.cmdId = options.cmdId ?? 3;
    this.acceptAnyStreamType = options.acceptAnyStreamType ?? false;
    this.expectedStreamTypes = this.profile === "sub" ? /* @__PURE__ */ new Set([1, 3]) : /* @__PURE__ */ new Set([0, 2]);
    if (this.variant === "telephoto") this.expectedStreamTypes.add(0);
    this.bcMediaCodec = new BcMediaCodec(false, this.logger);
    const dbg = this.client.getDebugConfig();
    this.debugH264LogsLeft = dbg.traceNativeStream ? 200 : 0;
    this.debugSavedSamples = false;
    this.dumpChunkIdx = 0;
    this.spsById = /* @__PURE__ */ new Map();
    this.ppsById = /* @__PURE__ */ new Map();
    this.lastSps = null;
    this.lastPps = null;
    this.lastPrependedPpsId = null;
    this.lastVps = null;
    this.lastSpsH265 = null;
    this.lastPpsH265 = null;
    this.lastPrependedParamSetsH265 = false;
    if (options.msgNum !== void 0) {
      this.activeMsgNum = options.msgNum;
    }
    const transport = this.client.getTransport?.();
    this.idleRestartMs = transport === "udp" ? 6e4 : 3e4;
  }
  noteMediaActivity() {
    this.lastMediaAtMs = Date.now();
  }
  startWatchdog() {
    if (!this.api) return;
    if (this.watchdogTimer) return;
    this.restartWindowStartMs = Date.now();
    this.restartCountInWindow = 0;
    this.watchdogTimer = setInterval(() => {
      void this.watchdogTick();
    }, WATCHDOG_TICK_MS);
  }
  stopWatchdog() {
    if (this.watchdogTimer) clearInterval(this.watchdogTimer);
    this.watchdogTimer = void 0;
  }
  async watchdogTick() {
    if (!this.active) return;
    if (!this.api) return;
    if (this.restarting) return;
    if (this.lastMediaAtMs <= 0) return;
    const now = Date.now();
    const idleMs = now - this.lastMediaAtMs;
    if (idleMs < this.idleRestartMs) return;
    if (now - this.restartWindowStartMs > 6e4) {
      this.restartWindowStartMs = now;
      this.restartCountInWindow = 0;
    }
    if (this.restartCountInWindow >= WATCHDOG_MAX_RESTARTS_PER_MINUTE) {
      this.logger?.warn(
        `[BaichuanVideoStream] Watchdog: idle for ${idleMs}ms, but restart budget exceeded (${WATCHDOG_MAX_RESTARTS_PER_MINUTE}/min); leaving stream as-is`
      );
      this.lastMediaAtMs = now;
      return;
    }
    this.restartCountInWindow++;
    void this.restartNativeStream({ reason: `idle ${idleMs}ms` });
  }
  async restartNativeStream(params) {
    if (!this.api) return;
    if (!this.active) return;
    if (this.restarting) return;
    this.restarting = true;
    try {
      const transport = this.client.getTransport?.() ?? "unknown";
      const msgNum = this.activeMsgNum ?? "unknown";
      this.logger?.warn(
        `[BaichuanVideoStream] Watchdog restarting native stream (channel=${this.channel} profile=${this.profile} expectedStreamTypes=[${[
          ...this.expectedStreamTypes
        ].join(
          ","
        )}] msgNum=${msgNum} transport=${transport} reason=${params.reason})`
      );
      this.depacketizer.reset();
      this.depacketizerH265.reset();
      this.bcMediaCodec.clear();
      this.activeMsgNum = void 0;
      this.lockedChannelId = void 0;
      this.lastPrependedPpsId = null;
      this.lastPrependedParamSetsH265 = false;
      try {
        await this.api.stopVideoStream(this.channel, this.profile, {
          variant: this.variant,
          client: this.client
        });
      } catch {
      }
      await this.api.startVideoStream(this.channel, this.profile, {
        variant: this.variant,
        client: this.client
      });
      try {
        const getMsgNum = this.api.getActiveVideoMsgNumWithVariant;
        const v = typeof getMsgNum === "function" ? getMsgNum(this.channel, this.profile, this.variant) : void 0;
        if (v !== void 0) this.activeMsgNum = v;
      } catch {
      }
      this.lastMediaAtMs = Date.now();
    } catch (error) {
      const err = error instanceof Error ? error : new Error(String(error));
      this.emitSafeError(err);
    } finally {
      this.restarting = false;
    }
  }
  /**
   * Start video stream.
   * Listens to `push` events and processes cmd_id=3 frames carrying BcMedia packets.
   */
  async start() {
    if (this.active) {
      throw new Error("Video stream already active");
    }
    this.depacketizer.reset();
    this.depacketizerH265.reset();
    let totalFramesReceived = 0;
    let totalMediaPackets = 0;
    this.videoFrameHandler = (frame) => {
      if (frame.header.cmdId !== this.cmdId) return;
      if (this.activeMsgNum !== void 0 && frame.header.msgNum !== this.activeMsgNum) {
        const allowMsgNum0Fallback = this.acceptAnyStreamType && frame.header.msgNum === 0;
        if (!allowMsgNum0Fallback) {
          const frameCount = this._msgNumMismatchCount = (this._msgNumMismatchCount || 0) + 1;
          if (frameCount <= 5 && this.client.getDebugConfig().general) {
            this.logger?.log(
              `[BaichuanVideoStream] Frame msgNum mismatch: received=${frame.header.msgNum}, expected=${this.activeMsgNum}, channel=${this.channel}, profile=${this.profile}, variant=${this.variant} (frame discarded)`
            );
          }
          return;
        }
      }
      if (!this.acceptAnyStreamType && !this.expectedStreamTypes.has(frame.header.streamType)) {
        const frameCount = this._streamTypeMismatchCount = (this._streamTypeMismatchCount || 0) + 1;
        if (frameCount <= 5 && this.client.getDebugConfig().general) {
          this.logger?.log(
            `[BaichuanVideoStream] Frame streamType mismatch: received=${frame.header.streamType}, expectedAny=[${[
              ...this.expectedStreamTypes
            ].join(
              ","
            )}], channel=${this.channel}, profile=${this.profile}, variant=${this.variant} (frame discarded)`
          );
        }
        return;
      }
      if (this.lockedChannelId === void 0) {
        this.lockedChannelId = frame.header.channelId;
      } else if (frame.header.channelId !== this.lockedChannelId) {
        const frameCount = this._channelIdMismatchCount = (this._channelIdMismatchCount || 0) + 1;
        if (frameCount <= 5) {
          this.logger?.warn(
            `[BaichuanVideoStream] Frame channelId mismatch: received=${frame.header.channelId}, locked=${this.lockedChannelId}, streamType=${frame.header.streamType}, msgNum=${frame.header.msgNum}, activeMsgNum=${this.activeMsgNum ?? "unknown"}, channel=${this.channel}, profile=${this.profile}, variant=${this.variant} (frame discarded)`
          );
        }
        return;
      }
      totalFramesReceived++;
      const dbg = this.client.getDebugConfig();
      const rtspDebug = dbg.debugRtsp;
      if (totalFramesReceived === 1) {
        if (rtspDebug) {
          this.logger?.log(
            `[BaichuanVideoStream] First cmd_id=${this.cmdId} frame received (bodyLen: ${frame.body.length}, channelId: ${frame.header.channelId})`
          );
        }
      }
      if (totalFramesReceived % 10 === 0 || totalFramesReceived <= 5) {
        if (rtspDebug) {
          this.logger?.log(
            `[BaichuanVideoStream] Received ${totalFramesReceived} Baichuan frames (cmd_id=${this.cmdId})`
          );
        }
      }
      const enc = this.client.enc;
      const rawCandidate = frame.payload.length > 0 ? frame.payload : frame.body;
      let dataToParse = rawCandidate;
      if (frame.payload.length === 0) {
        let searchStart = 0;
        const extensionEnd = rawCandidate.indexOf(Buffer.from("</Extension>"));
        const bodyEnd = rawCandidate.indexOf(Buffer.from("</body>"));
        if (extensionEnd !== -1)
          searchStart = extensionEnd + Buffer.from("</Extension>").length;
        else if (bodyEnd !== -1)
          searchStart = bodyEnd + Buffer.from("</body>").length;
        dataToParse = rawCandidate.subarray(searchStart);
      }
      let encryptLen;
      if (frame.extension && frame.extension.length > 0) {
        try {
          const extDec = this.client.tryDecryptXml(
            frame.extension,
            frame.header.channelId,
            enc
          );
          const encryptLenMatch = extDec.match(
            /<encryptLen>(\d+)<\/encryptLen>/i
          );
          if (encryptLenMatch && encryptLenMatch[1]) {
            encryptLen = parseInt(encryptLenMatch[1], 10);
          }
        } catch {
        }
      }
      const dataAfterXml = this.chooseDecryptedOrRawCandidate({
        raw: dataToParse,
        enc,
        channelId: frame.header.channelId,
        // Some NVR/Hub streams appear to include non-media bytes even when payloadOffset is present.
        // Allow a one-time resync at startup to avoid delaying the first keyframe.
        allowResync: frame.payload.length === 0 || totalFramesReceived <= 10 && totalMediaPackets === 0,
        ...encryptLen !== void 0 ? { encryptLen } : {}
      });
      if (this.bcMediaCodec.getRemainingBuffer().length === 0 && dataAfterXml.length <= 600) {
        const s = _BaichuanVideoStream.scoreBcMediaLike(dataAfterXml);
        if (s.first < 0) {
          return;
        }
      }
      if (totalFramesReceived === 1) {
        if (rtspDebug) {
          this.logger?.log(
            `[BaichuanVideoStream] Data after XML: ${dataAfterXml.length} bytes, first 32 bytes: ${dataAfterXml.subarray(0, Math.min(32, dataAfterXml.length)).toString("hex")}`
          );
        }
      }
      if (dbg.dumpEnabled) ensureDumpDir(dbg);
      if (dbg.dumpBcMedia && this.dumpChunkIdx < 200) {
        const outDir = dbg.dumpDir;
        const idx = String(this.dumpChunkIdx).padStart(4, "0");
        const chunkPath = path2.join(outDir, `bcmedia_chunk_${idx}.bin`);
        const infoPath = path2.join(outDir, "bcmedia_info.json");
        const chunk = Buffer.from(dataAfterXml);
        const writeInfo = this.dumpChunkIdx === 0;
        const infoJson = writeInfo ? JSON.stringify(
          {
            note: "Chunks fed into the BcMedia decoder (after XML stripping/alignment).",
            profile: this.profile,
            channel: this.channel,
            encKind: this.client.enc.kind
          },
          null,
          2
        ) : "";
        this.dumpIo.enqueue(async () => {
          await fs2.promises.writeFile(chunkPath, chunk);
          if (writeInfo) {
            await fs2.promises.writeFile(infoPath, infoJson);
          }
        });
        this.dumpChunkIdx++;
      }
      const mediaPackets = this.bcMediaCodec.decode(dataAfterXml);
      totalMediaPackets += mediaPackets.length;
      const packetTypes = /* @__PURE__ */ new Map();
      for (const pkt of mediaPackets) {
        packetTypes.set(pkt.type, (packetTypes.get(pkt.type) || 0) + 1);
      }
      let videoFramesEmitted = 0;
      let audioFramesEmitted = 0;
      for (const media of mediaPackets) {
        const maybeCacheParamSets = (annexB, source, videoType) => {
          if (videoType === "H264") {
            const nals = splitAnnexBToNalPayloads(annexB);
            for (const nal of nals) {
              const t = (nal[0] ?? 0) & 31;
              if (t === 7) {
                const id = parseSpsIdFromNal(nal);
                if (id != null) {
                  if (!isPlausibleH264Sps(nal)) continue;
                  this.spsById.set(id, nal);
                  if (dbg.traceNativeStream) {
                    this.logger?.warn(
                      `[BaichuanVideoStream] Cached H.264 SPS id=${id} len=${nal.length}`
                    );
                  }
                }
                if (isPlausibleH264Sps(nal)) this.lastSps = nal;
              }
              if (t === 8) {
                const ids = parsePpsIdsFromNal(nal);
                if (ids) {
                  const sps = this.spsById.get(ids.spsId);
                  if (sps && !isPlausibleH264Sps(sps)) continue;
                  this.ppsById.set(ids.ppsId, { nal, spsId: ids.spsId });
                  if (dbg.traceNativeStream) {
                    this.logger?.warn(
                      `[BaichuanVideoStream] Cached H.264 PPS id=${ids.ppsId} (spsId=${ids.spsId}) len=${nal.length}`
                    );
                  }
                }
                this.lastPps = nal;
              }
            }
          } else if (videoType === "H265") {
            const vps = extractVpsFromAnnexB(annexB);
            if (vps) {
              this.lastVps = vps;
              if (dbg.traceNativeStream) {
                this.logger?.warn(
                  `[BaichuanVideoStream] Cached H.265 VPS len=${vps.length}`
                );
              }
            }
            const sps = extractSpsFromAnnexB(annexB);
            if (sps) {
              this.lastSpsH265 = sps;
              if (dbg.traceNativeStream) {
                this.logger?.warn(
                  `[BaichuanVideoStream] Cached H.265 SPS len=${sps.length}`
                );
              }
            }
            const pps = extractPpsFromAnnexB(annexB);
            if (pps) {
              this.lastPpsH265 = pps;
              if (dbg.traceNativeStream) {
                this.logger?.warn(
                  `[BaichuanVideoStream] Cached H.265 PPS len=${pps.length}`
                );
              }
            }
          }
        };
        const prependParamSetsIfNeeded = (annexB, videoType, isPframe = false) => {
          if (videoType === "H264") {
            const nals = splitAnnexBToNalPayloads(annexB);
            if (nals.length === 0) return annexB;
            const types = nals.map((n) => (n[0] ?? 0) & 31);
            const hasVcl = types.some(
              (t) => t === 1 || t === 5 || t === 19 || t === 20
            );
            if (isPframe && !hasVcl) {
              if (dbg.traceNativeStream) {
                this.logger?.warn(
                  `[BaichuanVideoStream] Dropping P-frame without VCL (only param sets): types=${types.join(",")}`
                );
              }
              return Buffer.alloc(0);
            }
            if (types.includes(7) && types.includes(8)) {
              let ppsIdFromSlice = null;
              for (const nal of nals) {
                const t = (nal[0] ?? 0) & 31;
                if (t === 1 || t === 5) {
                  ppsIdFromSlice = parseSlicePpsIdFromNal(nal);
                  break;
                }
              }
              if (ppsIdFromSlice != null && ppsIdFromSlice <= 255) {
                this.lastPrependedPpsId = ppsIdFromSlice;
              } else {
                this.lastPrependedPpsId = -1;
              }
              return annexB;
            }
            if (!hasVcl) return annexB;
            let ppsId = null;
            for (const nal of nals) {
              const t = (nal[0] ?? 0) & 31;
              if (t === 1 || t === 5) {
                ppsId = parseSlicePpsIdFromNal(nal);
                break;
              }
            }
            if (dbg.traceNativeStream) {
              this.logger?.warn(
                `[BaichuanVideoStream] Slice references ppsId=${ppsId ?? "?"} lastPrepended=${this.lastPrependedPpsId ?? "?"}`
              );
            }
            if (ppsId == null || ppsId > 255) {
              if (this.lastPrependedPpsId != null) return annexB;
              if (!this.lastSps || !this.lastPps) return annexB;
              this.lastPrependedPpsId = -1;
              return Buffer.concat([
                NAL_START_CODE_4B3,
                this.lastSps,
                NAL_START_CODE_4B3,
                this.lastPps,
                annexB
              ]);
            }
            if (this.lastPrependedPpsId === ppsId) return annexB;
            const pps = this.ppsById.get(ppsId);
            if (pps) {
              const sps = this.spsById.get(pps.spsId);
              if (sps) {
                this.lastPrependedPpsId = ppsId;
                return Buffer.concat([
                  NAL_START_CODE_4B3,
                  sps,
                  NAL_START_CODE_4B3,
                  pps.nal,
                  annexB
                ]);
              }
            }
            return Buffer.alloc(0);
          } else if (videoType === "H265") {
            const nals = splitAnnexBToNalPayloads2(annexB);
            if (nals.length === 0) return annexB;
            const types = nals.map((n) => getH265NalType(n)).filter((t) => t !== null);
            const hasVcl = types.some(
              (t) => t >= 0 && t <= 9 || t >= 16 && t <= 23
            );
            if (isPframe && !hasVcl) {
              if (dbg.traceNativeStream) {
                this.logger?.warn(
                  `[BaichuanVideoStream] Dropping H.265 P-frame without VCL (only param sets): types=${types.join(",")}`
                );
              }
              return Buffer.alloc(0);
            }
            if (types.includes(32) && types.includes(33) && types.includes(34))
              return annexB;
            if (!hasVcl) return annexB;
            if (this.lastPrependedParamSetsH265) return annexB;
            if (!this.lastVps || !this.lastSpsH265 || !this.lastPpsH265)
              return annexB;
            this.lastPrependedParamSetsH265 = true;
            if (dbg.traceNativeStream) {
              this.logger?.warn(
                `[BaichuanVideoStream] Prepending H.265 VPS/SPS/PPS to frame`
              );
            }
            return Buffer.concat([
              NAL_START_CODE_4B3,
              this.lastVps,
              NAL_START_CODE_4B3,
              this.lastSpsH265,
              NAL_START_CODE_4B3,
              this.lastPpsH265,
              annexB
            ]);
          }
          return annexB;
        };
        const dumpNalSummary = (annexB, label, microseconds) => {
          if (!dbg.dumpNals) return;
          try {
            if (dbg.dumpEnabled) ensureDumpDir(dbg);
            const outDir = dbg.dumpDir;
            const nals = splitAnnexBToNalPayloads(annexB);
            const types = nals.map((n) => (n[0] ?? 0) & 31);
            let slicePpsId = null;
            const spsIds = [];
            const ppsIds = [];
            for (const nal of nals) {
              const t = (nal[0] ?? 0) & 31;
              if ((t === 1 || t === 5) && slicePpsId == null) {
                slicePpsId = parseSlicePpsIdFromNal(nal);
              }
              if (t === 7) {
                const id = parseSpsIdFromNal(nal);
                if (id != null) spsIds.push(id);
              }
              if (t === 8) {
                const ids = parsePpsIdsFromNal(nal);
                if (ids) ppsIds.push(ids.ppsId);
              }
            }
            if (this.dumpNalLines >= 2e4) return;
            const line = JSON.stringify({
              label,
              microseconds,
              len: annexB.length,
              nalTypes: types,
              slicePpsId,
              auSpsIds: spsIds,
              auPpsIds: ppsIds,
              cachedSps: this.spsById.size,
              cachedPps: this.ppsById.size,
              lastPrependedPpsId: this.lastPrependedPpsId
            }) + "\n";
            this.dumpNalLines++;
            const outPath = path2.join(outDir, "nal_dump.ndjson");
            this.dumpIo.enqueue(async () => {
              await fs2.promises.appendFile(outPath, line);
            });
          } catch {
          }
        };
        const isPlausibleH264Sps = (nal) => {
          if (nal.length < 4) return false;
          if (((nal[0] ?? 0) & 31) !== 7) return false;
          const profileIdc = nal[1] ?? 0;
          const levelIdc = nal[3] ?? 0;
          const knownProfiles = /* @__PURE__ */ new Set([66, 77, 88, 100, 110, 122, 244]);
          if (!knownProfiles.has(profileIdc)) return false;
          if (levelIdc === 0 || levelIdc > 255) return false;
          return true;
        };
        if (media.type === "Iframe") {
          let videoType = media.videoType;
          const detectedCodec = detectVideoCodecFromNal(media.data);
          if (detectedCodec && detectedCodec !== videoType) {
            if (dbg.traceNativeStream) {
              this.logger?.warn(
                `[BaichuanVideoStream] Codec mismatch in Iframe: header says ${videoType}, NAL says ${detectedCodec} - using ${detectedCodec}`
              );
            }
            videoType = detectedCodec;
          }
          if (media.additionalHeader && media.additionalHeader.length > 0) {
            this.emit("additionalHeader", {
              raw: media.additionalHeader,
              frameType: "Iframe",
              videoType,
              microseconds: media.microseconds,
              ...this.latestFrameWidth !== void 0 ? { frameWidth: this.latestFrameWidth } : {},
              ...this.latestFrameHeight !== void 0 ? { frameHeight: this.latestFrameHeight } : {}
            });
          }
          const annexBData = videoType === "H265" ? convertToAnnexB2(media.data) : convertToAnnexB(media.data);
          const isKeyframe = true;
          maybeCacheParamSets(annexBData, "Iframe", videoType);
          const outAnnex = prependParamSetsIfNeeded(annexBData, videoType);
          if (outAnnex.length === 0) {
            if (dbg.traceNativeStream) {
              this.logger?.warn(
                `[BaichuanVideoStream] Iframe DROPPED: outAnnex is empty`
              );
            }
            continue;
          }
          dumpNalSummary(outAnnex, "Iframe", media.microseconds);
          if (videoType === "H264") {
            if (!isValidH264AnnexBAccessUnit(outAnnex) || !isH264KeyframeAnnexB(outAnnex)) {
              if (dbg.traceNativeStream) {
                this.logger?.warn(
                  `[BaichuanVideoStream] Dropping invalid H.264 Iframe (Annex-B) len=${outAnnex.length}`
                );
              }
              continue;
            }
          } else if (videoType === "H265") {
            if (!isValidH265AnnexBAccessUnit(outAnnex)) {
              if (dbg.traceNativeStream) {
                this.logger?.warn(
                  `[BaichuanVideoStream] Dropping invalid H.265 Iframe (Annex-B) len=${outAnnex.length} first16=${outAnnex.subarray(0, 16).toString("hex")}`
                );
              }
              continue;
            }
            if (!isH265KeyframeAnnexB(outAnnex)) {
              if (dbg.traceNativeStream) {
                this.logger?.warn(
                  `[BaichuanVideoStream] H.265 Iframe missing VPS/SPS/PPS or IRAP, but continuing len=${outAnnex.length}`
                );
              }
            }
          }
          if (dbg.traceNativeStream && !this.debugSavedSamples) {
            try {
              const outDir = dbg.dumpDir;
              fs2.mkdirSync(outDir, { recursive: true });
              if (media.type === "Iframe" && hasStartCodes(annexBData)) {
                fs2.writeFileSync(
                  path2.join(outDir, "iframe_annexb.bin"),
                  annexBData
                );
              }
            } catch {
            }
          }
          if (!this.warnedNonAnnexBOnce && !hasStartCodes(annexBData)) {
            this.warnedNonAnnexBOnce = true;
            const b = media.data;
            const head = b.subarray(0, Math.min(24, b.length)).toString("hex");
            const headAnnex = annexBData.subarray(0, Math.min(24, annexBData.length)).toString("hex");
            this.logger?.warn(
              `[BaichuanVideoStream] WARNING: non-AnnexB frame after conversion (${media.type} ${media.videoType}) len=${b.length} head=${head} convertedLen=${annexBData.length} convertedHead=${headAnnex}`
            );
          }
          this.emit("videoFrame", outAnnex);
          this.emit("videoAccessUnit", {
            data: outAnnex,
            isKeyframe,
            videoType,
            // Use the detected/corrected videoType, not media.videoType
            microseconds: media.microseconds,
            ...media.type === "Iframe" && "time" in media ? media.time !== void 0 ? { time: media.time } : {} : {}
          });
          videoFramesEmitted++;
          if (totalFramesReceived <= 5 || videoFramesEmitted <= 5) {
            const sc = hasStartCodes(annexBData) ? "yes" : "no";
            if (rtspDebug) {
              this.logger?.log(
                `[BaichuanVideoStream] Emitted ${media.type} (${media.videoType}) ${media.data.length} bytes -> ${annexBData.length} bytes (Annex-B, startCode:${sc})`
              );
            }
          }
        } else if (media.type === "Pframe") {
          const chunk = media.data;
          if (media.additionalHeader && media.additionalHeader.length > 0) {
            const detected = detectVideoCodecFromNal(chunk);
            const videoTypeForHeader = detected ?? media.videoType;
            this.emit("additionalHeader", {
              raw: media.additionalHeader,
              frameType: "Pframe",
              videoType: videoTypeForHeader,
              microseconds: media.microseconds,
              ...this.latestFrameWidth !== void 0 ? { frameWidth: this.latestFrameWidth } : {},
              ...this.latestFrameHeight !== void 0 ? { frameHeight: this.latestFrameHeight } : {}
            });
          }
          let videoType = media.videoType;
          const detectedCodec = detectVideoCodecFromNal(chunk);
          if (detectedCodec && detectedCodec !== videoType) {
            videoType = detectedCodec;
          }
          const annexBOrRaw = hasStartCodes(chunk) ? chunk : videoType === "H265" ? convertToAnnexB2(chunk) : convertToAnnexB(chunk);
          const parts = hasStartCodes(annexBOrRaw) ? [annexBOrRaw] : videoType === "H265" ? this.depacketizerH265.push(chunk) : this.depacketizer.push(chunk);
          if (parts.length === 0) {
            continue;
          }
          for (const p of parts) {
            maybeCacheParamSets(p, "Pframe", videoType);
            const outP0 = prependParamSetsIfNeeded(p, videoType, true);
            if (outP0.length === 0) continue;
            const outP = outP0;
            dumpNalSummary(outP, "Pframe", media.microseconds);
            const isValid = videoType === "H265" ? isValidH265AnnexBAccessUnit(outP) : isValidH264AnnexBAccessUnit(outP);
            if (!isValid) {
              if (dbg.traceNativeStream && this.debugH264LogsLeft > 0) {
                this.debugH264LogsLeft--;
                const head = outP.subarray(0, Math.min(24, outP.length)).toString("hex");
                this.logger?.warn(
                  `[BaichuanVideoStream] Dropping invalid Pframe (${videoType}): len=${outP.length} head=${head}`
                );
              }
              continue;
            }
            this.emit("videoFrame", outP);
            this.emit("videoAccessUnit", {
              data: outP,
              isKeyframe: false,
              videoType,
              microseconds: media.microseconds
            });
            videoFramesEmitted++;
          }
        }
        if (media.type === "Aac" || media.type === "Adpcm") {
          audioFramesEmitted++;
          this.emit("audioFrame", media.data);
        }
        if (media.type === "InfoV1" || media.type === "InfoV2") {
          if (media.videoWidth > 0) this.latestFrameWidth = media.videoWidth;
          if (media.videoHeight > 0) this.latestFrameHeight = media.videoHeight;
        }
      }
      if (totalFramesReceived <= 10 || totalFramesReceived % 20 === 0 && (videoFramesEmitted > 0 || audioFramesEmitted > 0)) {
        if (rtspDebug) {
          this.logger?.log(
            `[BaichuanVideoStream] Frame #${totalFramesReceived}: emitted ${videoFramesEmitted} video frames, ${audioFramesEmitted} audio frames`
          );
        }
      }
      if (videoFramesEmitted > 0 || audioFramesEmitted > 0) {
        this.noteMediaActivity();
      }
      if (videoFramesEmitted > 0 && (totalFramesReceived <= 10 || totalFramesReceived % 50 === 0)) {
        let totalVideoFrames = 0;
      }
    };
    this.client.on("push", this.videoFrameHandler);
    this.active = true;
    this.startWatchdog();
    if (this.api && typeof this.api._registerVideoStreamForDetection === "function") {
      this.detectionTeardown = this.api._registerVideoStreamForDetection(this, {
        channel: this.channel,
        profile: this.profile
      });
    }
    this.lastMediaAtMs = Date.now();
    if (this.api) {
      try {
        if (this.variant === "default") {
          try {
            await this.api.stopVideoStream(this.channel, this.profile, {
              variant: "default",
              client: this.client
            });
          } catch {
          }
        } else {
          try {
            await this.api.stopVideoStream(this.channel, this.profile, {
              variant: this.variant,
              client: this.client
            });
            this.logger?.log(
              `[BaichuanVideoStream] Successfully stopped existing variant stream: ${this.variant}`
            );
          } catch (e) {
            this.logger?.log(
              `[BaichuanVideoStream] Error stopping variant stream ${this.variant} (may not exist): ${e instanceof Error ? e.message : String(e)}`
            );
          }
        }
        await new Promise((resolve) => setTimeout(resolve, 100));
        const startPromise = this.api.startVideoStream(
          this.channel,
          this.profile,
          { variant: this.variant, client: this.client }
        );
        const updateActiveMsgNum = () => {
          try {
            const getMsgNum = this.api.getActiveVideoMsgNumWithVariant;
            const v = typeof getMsgNum === "function" ? getMsgNum(this.channel, this.profile, this.variant) : void 0;
            if (v !== void 0) this.activeMsgNum = v;
          } catch {
          }
        };
        updateActiveMsgNum();
        if (this.client.getTransport?.() === "udp") {
          await startPromise;
        } else {
          await Promise.race([
            startPromise,
            new Promise((resolve) => setTimeout(resolve, 400))
          ]);
        }
        updateActiveMsgNum();
        void startPromise.then(() => updateActiveMsgNum()).catch((e) => {
          const err = e instanceof Error ? e : new Error(String(e));
          this.emitSafeError(err);
        });
      } catch (error) {
        const err = error instanceof Error ? error : new Error(String(error));
        if (this.client.getTransport?.() === "udp") {
          this.stopWatchdog();
          this.active = false;
          if (this.videoFrameHandler)
            this.client.off("push", this.videoFrameHandler);
          this.videoFrameHandler = void 0;
          throw err;
        }
        this.emitSafeError(err);
      }
    }
  }
  // isVideoFrame, isAudioFrame, and extractVideoData are no longer needed
  // BcMediaParser handles all frame parsing and extraction
  /**
   * Stop video stream.
   */
  async stop() {
    if (!this.active) return;
    this.stopWatchdog();
    this.depacketizer.reset();
    this.depacketizerH265.reset();
    if (this.videoFrameHandler) {
      this.client.removeListener("push", this.videoFrameHandler);
    }
    this.videoFrameHandler = void 0;
    this.bcMediaCodec.clear();
    this.activeMsgNum = void 0;
    if (this.api) {
      try {
        await this.api.stopVideoStream(this.channel, this.profile, {
          variant: this.variant,
          client: this.client
        });
      } catch (error) {
        this.emitSafeError(
          error instanceof Error ? error : new Error(String(error))
        );
      }
    }
    this.active = false;
    if (this.detectionTeardown) {
      try {
        this.detectionTeardown();
      } catch {
      }
      this.detectionTeardown = void 0;
    }
    this.emit("close");
  }
  isActive() {
    return this.active;
  }
};

export {
  __require,
  BC_TCP_DEFAULT_PORT,
  BC_MAGIC,
  BC_MAGIC_REV,
  BC_XML_KEY,
  BC_AES_IV,
  BC_CLASS_LEGACY,
  BC_CLASS_MODERN_20,
  BC_CLASS_MODERN_24,
  BC_CLASS_MODERN_24_ALT,
  BC_CLASS_FILE_DOWNLOAD,
  bcHeaderHasPayloadOffset,
  BC_CMD_ID_LOGIN,
  BC_CMD_ID_LOGOUT,
  BC_CMD_ID_VIDEO,
  BC_CMD_ID_VIDEO_STOP,
  BC_CMD_ID_FILE_INFO_LIST_REPLAY,
  BC_CMD_ID_FILE_INFO_LIST_STOP,
  BC_CMD_ID_FILE_INFO_LIST_DL_VIDEO,
  BC_CMD_ID_FILE_INFO_LIST_DOWNLOAD,
  BC_CMD_ID_FILE_INFO_LIST_OPEN,
  BC_CMD_ID_FILE_INFO_LIST_GET,
  BC_CMD_ID_FILE_INFO_LIST_CLOSE,
  BC_CMD_ID_FIND_REC_VIDEO_OPEN,
  BC_CMD_ID_FIND_REC_VIDEO_GET,
  BC_CMD_ID_FIND_REC_VIDEO_CLOSE,
  BC_CMD_ID_COVER_PREVIEW,
  BC_CMD_ID_COVER_STANDALONE_458,
  BC_CMD_ID_COVER_STANDALONE_459,
  BC_CMD_ID_COVER_STANDALONE_460,
  BC_CMD_ID_COVER_STANDALONE_461,
  BC_CMD_ID_COVER_STANDALONE_462,
  BC_CMD_ID_COVER_RESPONSE,
  BC_CMD_ID_TALK_ABILITY,
  BC_CMD_ID_TALK_RESET,
  BC_CMD_ID_TALK_CONFIG,
  BC_CMD_ID_TALK,
  BC_CMD_ID_PTZ_CONTROL,
  BC_CMD_ID_PTZ_CONTROL_PRESET,
  BC_CMD_ID_GET_PTZ_PRESET,
  BC_CMD_ID_GET_PTZ_POSITION,
  BC_CMD_ID_GET_ZOOM_FOCUS,
  BC_CMD_ID_SET_ZOOM_FOCUS,
  BC_CMD_ID_GET_BATTERY_INFO_LIST,
  BC_CMD_ID_GET_BATTERY_INFO,
  BC_CMD_ID_UDP_KEEP_ALIVE,
  BC_CMD_ID_GET_PIR_INFO,
  BC_CMD_ID_SET_PIR_INFO,
  BC_CMD_ID_GET_MOTION_ALARM,
  BC_CMD_ID_SET_MOTION_ALARM,
  BC_CMD_ID_ALARM_EVENT_LIST,
  BC_CMD_ID_GET_AI_ALARM,
  BC_CMD_ID_SET_AI_ALARM,
  BC_CMD_ID_GET_AUDIO_ALARM,
  BC_CMD_ID_AUDIO_ALARM_PLAY,
  BC_CMD_ID_GET_WHITE_LED,
  BC_CMD_ID_SET_WHITE_LED_STATE,
  BC_CMD_ID_SET_WHITE_LED_TASK,
  BC_CMD_ID_FLOODLIGHT_STATUS_LIST,
  BC_CMD_ID_ABILITY_INFO,
  BC_CMD_ID_SUPPORT,
  BC_CMD_ID_PING,
  BC_CMD_ID_DEVICE_DETECT_CANDIDATES,
  BC_CMD_ID_DEVICE_DETECT,
  BC_CMD_ID_GET_SNAPSHOT,
  BC_CMD_ID_GET_UID,
  BC_CMD_ID_CHANNEL_INFO_ALL,
  BC_CMD_ID_GET_OSD_DATETIME,
  BC_CMD_ID_SET_OSD_DATETIME,
  BC_CMD_ID_GET_RECORD_CFG,
  BC_CMD_ID_GET_ABILITY_SUPPORT,
  BC_CMD_ID_GET_FTP_TASK,
  BC_CMD_ID_GET_VERSION_INFO,
  BC_CMD_ID_GET_RECORD,
  BC_CMD_ID_GET_HDD_INFO_LIST,
  BC_CMD_ID_GET_WIFI_SIGNAL,
  BC_CMD_ID_GET_WIFI,
  BC_CMD_ID_GET_ONLINE_USER_LIST,
  BC_CMD_ID_GET_DAY_RECORDS,
  BC_CMD_ID_GET_STREAM_INFO_LIST,
  BC_CMD_ID_GET_LED_STATE,
  BC_CMD_ID_GET_EMAIL_TASK,
  BC_CMD_ID_GET_AUDIO_TASK,
  BC_CMD_ID_GET_AUDIO_CFG,
  BC_CMD_ID_GET_DAY_NIGHT_THRESHOLD,
  BC_CMD_ID_GET_TIMELAPSE_CFG,
  BC_CMD_ID_GET_AI_DENOISE,
  BC_CMD_ID_GET_KIT_AP_CFG,
  BC_CMD_ID_GET_REC_ENC_CFG,
  BC_CMD_ID_GET_ACCESS_USER_LIST,
  BC_CMD_ID_GET_SLEEP_STATE,
  BC_CMD_ID_GET_VIDEO_INPUT,
  BC_CMD_ID_GET_SYSTEM_GENERAL,
  BC_CMD_ID_GET_SUPPORT,
  BC_CMD_ID_GET_AI_CFG,
  BC_CMD_ID_SET_AI_CFG,
  BC_CMD_ID_GET_SIREN_STATUS,
  BC_CMD_ID_SET_AUDIO_TASK,
  BC_CMD_ID_SET_VIDEO_INPUT,
  BC_CMD_ID_SET_DAY_NIGHT_THRESHOLD,
  BC_CMD_ID_GET_ENC,
  BC_CMD_ID_SET_ENC,
  BC_CMD_ID_GET_PRIVACY_MASK,
  BC_CMD_ID_SET_PRIVACY_MASK,
  BC_CMD_ID_SET_AI_DENOISE,
  BC_CMD_ID_SET_LED_STATE,
  BC_CMD_ID_SET_AUDIO_CFG,
  BC_CMD_ID_SET_RECORD,
  BC_CMD_ID_SET_RECORD_CFG,
  BC_CMD_ID_SET_EMAIL_TASK,
  BC_CMD_ID_GET_PUSH_TASK,
  BC_CMD_ID_SET_PUSH_TASK,
  BC_CMD_ID_GET_AUTO_FOCUS,
  BC_CMD_ID_SET_AUTO_FOCUS,
  BC_CMD_ID_GET_EMAIL,
  BC_CMD_ID_SET_EMAIL,
  BC_CMD_ID_TEST_EMAIL,
  BC_CMD_ID_GET_NTP,
  BC_CMD_ID_SET_NTP,
  BC_CMD_ID_SET_SYSTEM_GENERAL,
  BC_CMD_ID_GET_DST,
  BC_CMD_ID_SET_DST,
  BC_CMD_ID_GET_AUTO_REBOOT,
  BC_CMD_ID_SET_AUTO_REBOOT,
  BC_CMD_ID_CMD_123,
  BC_CMD_ID_CMD_209,
  BC_CMD_ID_CMD_265,
  BC_CMD_ID_CMD_440,
  BC_CMD_ID_PUSH_VIDEO_INPUT,
  BC_CMD_ID_PUSH_SERIAL,
  BC_CMD_ID_PUSH_NET_INFO,
  BC_CMD_ID_PUSH_DINGDONG_LIST,
  BC_CMD_ID_PUSH_SLEEP_STATUS,
  BC_CMD_ID_PUSH_COORDINATE_POINT_LIST,
  BC_CMD_ID_DING_DONG_CTRL,
  BC_CMD_ID_GET_DING_DONG_LIST,
  BC_CMD_ID_DING_DONG_OPT,
  BC_CMD_ID_GET_DING_DONG_CFG,
  BC_CMD_ID_SET_DING_DONG_CFG,
  BC_CMD_ID_QUICK_REPLY_PLAY,
  BC_CMD_ID_GET_DING_DONG_SILENT,
  BC_CMD_ID_SET_DING_DONG_SILENT,
  md5HexUpper,
  md5StrModern,
  deriveAesKey,
  bcEncrypt,
  bcDecrypt,
  aesEncrypt,
  aesDecrypt,
  AesStreamDecryptor,
  normalizeDebugOptions,
  recordingsTraceLog,
  debugLog,
  traceLog,
  talkTraceLog,
  eventTraceLog,
  parseBcMedia,
  BcMediaCodec,
  hasStartCodes,
  convertToAnnexB,
  splitAnnexBToNalPayloads,
  isValidH264AnnexBAccessUnit,
  isH264KeyframeAnnexB,
  H264RtpDepacketizer,
  convertToLengthPrefixed,
  hasStartCodes2,
  convertToAnnexB2,
  H265RtpDepacketizer,
  splitAnnexBToNalPayloads2,
  getH265NalType,
  isH265Irap,
  isValidH265AnnexBAccessUnit,
  isH265KeyframeAnnexB,
  extractVpsFromAnnexB,
  extractSpsFromAnnexB,
  extractPpsFromAnnexB,
  detectVideoCodecFromNal,
  BcMediaAnnexBDecoder,
  BaichuanVideoStream
};
//# sourceMappingURL=chunk-MZUSWKF3.js.map