static uint h264e_bs_byte_align(bs_t bs) { int pos = (int)h264e_bs_get_pos_bits(bs); h264e_bs_put_bits(bs, (uint)(-pos & 7), 0); return((uint)(pos + (-pos & 7))); }
static void copy_bits(bit_reader_t bs, bs_t bd) { uint cb, bits; int bit_count = remaining_bits(bs); while (bit_count > 7) { cb = (uint)Math.Min(bit_count - 7, 8); bits = get_bits(bs, (int)cb); h264e_bs_put_bits(bd, cb, bits); bit_count -= (int)cb; } // cut extra zeros after stop-bit bits = get_bits(bs, bit_count); for (; (bit_count != 0) && ((~bits & 1) != 0); bit_count--) { bits >>= 1; } if (bit_count != 0) { h264e_bs_put_bits(bd, (uint)bit_count, bits); } }
private static unsafe void h264e_bs_init_bits(bs_t bs, void *data) { bs.origin = (uint *)data; bs.buf = bs.origin; bs.shift = 32; bs.cache = 0; }
static unsafe uint h264e_bs_get_pos_bits(bs_t bs) { uint pos_bits = (uint)((bs.buf - bs.origin) * 32); pos_bits += (uint)(32 - bs.shift); Debug.Assert((int)pos_bits >= 0); return(pos_bits); }
static void h264e_bs_put_golomb(bs_t bs, uint val) { int size = 0; uint t = val + 1; do { size++; t = t >> 1; } while (t != 0); h264e_bs_put_bits(bs, (uint)(2 * size - 1), val + 1); }
static unsafe void h264e_bs_put_bits(bs_t bs, uint n, uint val) { Debug.Assert(((int)val >> (int)n) == 0); bs.shift -= (int)n; Debug.Assert((int)n <= 32); if (bs.shift < 0) { Debug.Assert(-bs.shift < 32); bs.cache |= (int)val >> -bs.shift; *bs.buf++ = SWAP32(bs.cache); bs.shift = 32 + bs.shift; bs.cache = 0; } bs.cache |= (int)val << bs.shift; }
static unsafe int change_sps_id(bit_reader_t bs, bs_t bd, int new_id, int *old_id) { uint bits, sps_id, i, bytes; for (i = 0; i < 3; i++) { bits = get_bits(bs, 8); h264e_bs_put_bits(bd, 8, bits); } sps_id = (uint)ue_bits(bs); // max = 31 *old_id = (int)sps_id; sps_id = (uint)new_id; Debug.Assert(sps_id <= 31); h264e_bs_put_golomb(bd, sps_id); copy_bits(bs, bd); bytes = h264e_bs_byte_align(bd) / 8; h264e_bs_flush(bd); return((int)bytes); }
private static unsafe int transcode_nalu(h264_sps_id_patcher_t h, byte *src, int nalu_bytes, byte *dst) { int old_id; bit_reader_t bst = new bit_reader_t(); bs_t bdt = new bs_t(); bit_reader_t bs = new bit_reader_t(); bs_t bd = new bs_t(); int payload_type = src[0] & 31; *dst = *src; h264e_bs_init_bits(bd, dst + 1); init_bits(bs, src + 1, (uint)nalu_bytes - 1); h264e_bs_init_bits(bdt, dst + 1); init_bits(bst, src + 1, (uint)nalu_bytes - 1); switch (payload_type) { case 7: { int cb = change_sps_id(bst, bdt, 0, &old_id); int id = find_mem_cache(h.sps_cache, h.sps_bytes, MINIMP4_MAX_SPS, dst + 1, cb); if (id == -1) { return(0); } h.map_sps[old_id] = id; change_sps_id(bs, bd, id, &old_id); } break; case 8: { int cb = patch_pps(h, bst, bdt, 0, &old_id); int id = find_mem_cache(h.pps_cache, h.pps_bytes, MINIMP4_MAX_PPS, dst + 1, cb); if (id == -1) { return(0); } h.map_pps[old_id] = id; patch_pps(h, bs, bd, id, &old_id); } break; case 1: case 2: case 5: patch_slice_header(h, bs, bd); break; default: memcpy(dst, src, nalu_bytes); return(nalu_bytes); } nalu_bytes = (int)(1 + h264e_bs_byte_align(bd) / 8); h264e_bs_flush(bd); return(nalu_bytes); }
private static unsafe void patch_slice_header(h264_sps_id_patcher_t h, bit_reader_t bs, bs_t bd) { uint first_mb_in_slice = (uint)ue_bits(bs); uint slice_type = (uint)ue_bits(bs); uint pps_id = (uint)ue_bits(bs); pps_id = (uint)h.map_pps[pps_id]; Debug.Assert(pps_id <= 255); h264e_bs_put_golomb(bd, first_mb_in_slice); h264e_bs_put_golomb(bd, slice_type); h264e_bs_put_golomb(bd, pps_id); copy_bits(bs, bd); }
private static unsafe int patch_pps(h264_sps_id_patcher_t h, bit_reader_t bs, bs_t bd, int new_pps_id, int *old_id) { int bytes; uint pps_id = (uint)ue_bits(bs); // max = 255 uint sps_id = (uint)ue_bits(bs); // max = 31 *old_id = (int)pps_id; sps_id = (uint)h.map_sps[sps_id]; pps_id = (uint)new_pps_id; Debug.Assert(sps_id <= 31); Debug.Assert(pps_id <= 255); h264e_bs_put_golomb(bd, pps_id); h264e_bs_put_golomb(bd, sps_id); copy_bits(bs, bd); bytes = (int)h264e_bs_byte_align(bd) / 8; h264e_bs_flush(bd); return(bytes); }
static unsafe void h264e_bs_flush(bs_t bs) { *bs.buf = SWAP32(bs.cache); }