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); } }
static uint get_bits(bit_reader_t bs, int n) { uint retval = show_bits(bs, n); flush_bits(bs, n); return(retval); }
static uint show_bits(bit_reader_t bs, int n) { int retval; Debug.Assert(n > 0 && n <= 16); retval = (int)bs.cache >> (32 - n); return((uint)retval); }
static unsafe void set_pos_bits(bit_reader_t bs, uint pos_bits) { Debug.Assert((int)pos_bits >= 0); bs.buf = bs.origin + pos_bits / 16; bs.cache = 0; bs.cache_free_bits = 16; flush_bits(bs, 0); flush_bits(bs, (int)pos_bits & 15); }
static unsafe uint get_pos_bits(bit_reader_t bs) { // Current bitbuffer position = // position of next wobits in the internal buffer // minus bs, available in bit cache wobits uint pos_bits = (uint)(bs.buf - bs.origin) * 16; pos_bits -= (uint)(16 - bs.cache_free_bits); Debug.Assert((int)pos_bits >= 0); return(pos_bits); }
static unsafe void flush_bits(bit_reader_t bs, int n) { Debug.Assert(n >= 0 && n <= 16); bs.cache <<= n; bs.cache_free_bits += n; if (bs.cache_free_bits >= 0) { bs.cache |= (LOAD_SHORT(*bs.buf)) << bs.cache_free_bits; bs.buf++; bs.cache_free_bits -= 16; } }
static int ue_bits(bit_reader_t bs) { int clz; int val; for (clz = 0; get_bits(bs, 1) == 0; clz++) { } //get_bits(bs, clz + 1); val = (1 << clz) - 1 + (clz != 0 ? (int)get_bits(bs, clz) : 0); return(val); }
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 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 init_bits(bit_reader_t bs, void *data, uint data_bytes) { bs.origin = (ushort *)data; bs.origin_bytes = data_bytes; set_pos_bits(bs, 0); }
static int remaining_bits(bit_reader_t bs) { return((int)bs.origin_bytes * 8 - (int)get_pos_bits(bs)); }