// frame.mbt
//
// 音频帧头解析与同步扫描。帧头结构(各字段宽度与校验已由 ffmpeg
// 交叉验证:帧同步 14 位 + 保留位 + 块长码/采样率码/声道分配/位深码 +
// UTF-8 形变变长帧号/样本号 + 扩展字段 + CRC-8)。

///|
/// 解析成功的帧头。
priv struct FrameHeader {
  /// 本帧每声道的样本数。
  block_size : Int32
  /// 声道分配码:0..7 独立声道,8=left/side,9=right/side,10=mid/side。
  channel_assignment : Int32
  /// 声道数。
  channels : Int32
  /// 本帧位深(side 声道会在此基础上 +1)。
  bits_per_sample : Int32
  /// 帧起始字节偏移(CRC-16 覆盖范围的起点)。
  start_byte : Int32
}

///|
/// 采样率码 1..11 对应的固定采样率。
fn fixed_sample_rate(code : Int32) -> Int32 {
  if code == 1 {
    return 88200
  }
  if code == 2 {
    return 176400
  }
  if code == 3 {
    return 192000
  }
  if code == 4 {
    return 8000
  }
  if code == 5 {
    return 16000
  }
  if code == 6 {
    return 22050
  }
  if code == 7 {
    return 24000
  }
  if code == 8 {
    return 32000
  }
  if code == 9 {
    return 44100
  }
  if code == 10 {
    return 48000
  }
  96000
}

///|
/// 读 UTF-8 形变的变长正整数(借 UTF-8 字节形状编码最长 36 位,
/// 与 Unicode 语义无关:0xFF 非法、前缀单个 1 非法、续字节须为 10xxxxxx)。
fn read_coded_number(br : BitReader) -> Int64 raise FlacError {
  let b0 = br.read_bits64(8).to_int()
  br.check()
  if b0 == 0xFF {
    raise BadFrameHeader(reason="变长帧号出现 0xFF")
  }
  let mut k = 0
  let mut mask = 0x80
  while mask != 0 && (b0 & mask) != 0 {
    k += 1
    mask = mask >> 1
  }
  if k == 0 {
    return Int64::from_int(b0)
  }
  if k == 1 {
    // 10xxxxxx 是续字节形状,不能作为首字节
    raise BadFrameHeader(reason="变长帧号首字节非法")
  }
  // k 个前导 1 -> 共 k 字节;首字节数据位 8-k-1 个
  let mut value = Int64::from_int(b0 & ((1 << (7 - k)) - 1))
  for _ in 1.. Int32 {
  let mut i = if from_byte < 0 { 0 } else { from_byte }
  while i + 1 < data.length() {
    if data.unsafe_get(i).to_int() == 0xFF &&
      (data.unsafe_get(i + 1).to_int() & 0xFE) == 0xF8 {
      return i
    }
    i += 1
  }
  -1
}

///|
/// 从当前位置(须在帧起始字节上)解析完整帧头,含 CRC-8 校验。
/// 成功后读取器停在子帧区起点(字节对齐)。
fn parse_frame_header(
  br : BitReader,
  info : StreamInfo,
) -> FrameHeader raise FlacError {
  if !br.is_aligned() {
    raise BadFrameHeader(reason="帧头未字节对齐")
  }
  let start_byte = br.pos >> 3
  let sync = br.read_bits64(14).to_int()
  // 每读完一个字段就先 check 越界,避免"数据不足"被后续字段校验
  // 误报成 BadFrameHeader(增量解码依赖 Truncated 与之区分)。
  br.check()
  if sync != 0x3FFE {
    raise BadFrameHeader(reason="帧同步码错误")
  }
  let reserved = br.read_bit()
  br.check()
  if reserved != 0 {
    raise BadFrameHeader(reason="帧头保留位非零")
  }
  let _ = br.read_bit() // 阻塞策略位:M1 不做按样本号校验,读过即可
  br.check()
  let bs_code = br.read_bits64(4).to_int()
  br.check()
  if bs_code == 0 {
    raise BadFrameHeader(reason="块长码 0 为保留值")
  }
  let sr_code = br.read_bits64(4).to_int()
  br.check()
  if sr_code == 15 {
    raise BadFrameHeader(reason="采样率码 15 为保留值")
  }
  let ch_code = br.read_bits64(4).to_int()
  br.check()
  if ch_code > 10 {
    raise BadFrameHeader(reason="声道分配码超过 10")
  }
  let ss_code = br.read_bits64(3).to_int()
  br.check()
  if ss_code == 3 {
    raise BadFrameHeader(reason="位深码 3 为保留值")
  }
  let last_reserved = br.read_bit()
  br.check()
  if last_reserved != 0 {
    raise BadFrameHeader(reason="帧头末保留位非零")
  }
  let _ = read_coded_number(br) // 帧号/样本号:读过即校验其编码合法性
  // 块长扩展字段(跟在变长帧号之后)
  let mut block_size = if bs_code == 1 {
    192
  } else if bs_code <= 5 {
    576 << (bs_code - 2)
  } else if bs_code <= 7 {
    0 // 8/16 位扩展字段,下面读取
  } else {
    256 << (bs_code - 8)
  }
  if bs_code == 6 {
    block_size = br.read_bits64(8).to_int() + 1
  } else if bs_code == 7 {
    block_size = br.read_bits64(16).to_int() + 1
  }
  br.check()
  // RFC 9639 §9.1.6:块长 65536(码 7 的字段值 65535)被规范禁止
  // ("A value of 65535 ... is forbidden"),因为 STREAMINFO 的
  // max_block_size 是 u(16),最大只能表示 65535。合法上限是 65535。
  if block_size < 1 || block_size > 65535 {
    raise BadFrameHeader(reason="块长超出合法范围(1..65535)")
  }
  // 采样率扩展字段
  let mut sample_rate = if sr_code == 0 {
    info.sample_rate
  } else if sr_code <= 11 {
    fixed_sample_rate(sr_code)
  } else {
    0
  }
  if sr_code == 12 {
    sample_rate = br.read_bits64(8).to_int() * 1000
  } else if sr_code == 13 {
    sample_rate = br.read_bits64(16).to_int()
  } else if sr_code == 14 {
    sample_rate = br.read_bits64(16).to_int() * 10
  }
  br.check()
  if sample_rate < 1 {
    raise BadFrameHeader(reason="采样率为 0")
  }
  // 此处读取器落在字节边界:帧头全部字段都是字节数的整数倍
  if !br.is_aligned() {
    raise BadFrameHeader(reason="帧头结束未字节对齐")
  }
  let header_end = br.pos >> 3
  let expect_crc = br.read_bits64(8).to_int()
  br.check()
  let actual = crc8_range(br.data, start_byte, header_end)
  if expect_crc != actual {
    raise BadCrc(kind="CRC-8", expected=actual, actual=expect_crc)
  }
  let channels = if ch_code < 8 { ch_code + 1 } else { 2 }
  let bits_per_sample = if ss_code == 0 {
    info.bits_per_sample
  } else if ss_code == 1 {
    8
  } else if ss_code == 2 {
    12
  } else if ss_code == 4 {
    16
  } else if ss_code == 5 {
    20
  } else if ss_code == 6 {
    24
  } else {
    32
  }
  {
    block_size,
    channel_assignment: ch_code,
    channels,
    bits_per_sample,
    start_byte,
  }
}