def main(): """ """ F = 'bqmall.bin' s = BitStream(filename=F) nals = list(s.findall('0x000001', bytealigned=True)) size = [y - x for x, y in zip(nals, nals[1:])] for i, n in zip(nals, size): print print "!! Found NAL @ offset {0:d} ({0:#x})".format((i + 24) / 8) read_nal_unit(s, i, n / 8) # bits to bytes
class H26xParser: """ H.264 extractor for Annex B streams. """ START_CODE_PREFIX = "0x00000001" START_CODE_PREFIX_SHORT = "0x000001" VALID_CALLBACKS = [ "sps", "pps", "slice", "aud", "nalu" ] def __init__(self, f, verbose=False, use_bitstream=None): """ Create a new extractor for a .264/h264 file in Annex B format. f: input file use_bitstream: blob to use as bitstream (for testing) verbose: whether to print out NAL structure and fields """ if use_bitstream: # testing the parser in a bitstream self.file = None self.stream = BitStream(use_bitstream) else: fn, ext = os.path.splitext(os.path.basename(f)) valid_input_ext = ['.264', '.h264'] # TODO: extend for H.265 # valid_input_ext = ['.264', 'h264', '.265', '.h265'] if not ext in valid_input_ext: raise RuntimeError("Valid input types: " + str(valid_input_ext)) bitstream_file = f self.file = bitstream_file self.stream = BitStream(filename=bitstream_file) self.verbose = verbose self.callbacks = {} def set_callback(self, name, fun): """ Set a callback function for raw data extracted. The function will be called with the raw bytes of the complete NALU. Valid callbacks are: - aud: for every AUD found - nalu: for every complete NAL unit found - sps: for every SPS NAL unit found - pps: for every PPS NAL unit found - slice: for every VCL NAL unit found with a slice in it (args: data, buffer_size, first_mb_in_slice) Raw data for all callbacks never includes the start code, but all the NAL headers, except for the "nalu" callback. """ if name not in self.VALID_CALLBACKS: raise RuntimeError(name + " is not a valid callback. Choose one of " + str(self.VALID_CALLBACKS) + ".") if not callable(fun): raise RuntimeError(str(fun) + " is not a callable function") self.callbacks[name] = fun def __call(self, name, *args): """ Calls a given callback, and silently skips if it is not implemented. name: name of the callback, e.g. "nalu", "aud", whatever args: will be expanded to the list of arguments, so you can call this with: self.__call("foo", arg1, arg2, ...) """ if name not in self.VALID_CALLBACKS: return if name not in self.callbacks.keys(): return else: self.callbacks[name](*args) def _get_nalu_positions(self): """ Saves all the NALU positions as bit positions in self.nal_unit_positions """ self.nal_unit_positions = list(self.stream.findall(self.START_CODE_PREFIX, bytealigned=True)) self.short_nal_unit_positions = list(self.stream.findall(self.START_CODE_PREFIX_SHORT, bytealigned=True)) if not self.nal_unit_positions and not self.short_nal_unit_positions: print("No NALUs found in stream") sys.exit(1) if not self.nal_unit_positions: self.nal_unit_positions = self.short_nal_unit_positions else: # if there were extraneous 3-byte NAL unit start codes, use them too extra_nal_unit_pos = set([max(s - 8, 0) for s in self.short_nal_unit_positions]) - set(self.nal_unit_positions) if len(extra_nal_unit_pos) and self.nal_unit_positions: if self.verbose: print("Warning: 3-byte extra NAL unit start code found") self.nal_unit_positions.extend([s + 8 for s in extra_nal_unit_pos]) self.nal_unit_positions = sorted(self.nal_unit_positions) self.end_of_stream = len(self.stream) self.nal_unit_positions.append(self.end_of_stream) return self.nal_unit_positions def _decode_nalu(self, nalu_bytes): """ Returns nal_unit_type and RBSP payload from a NALU stream """ if "0x" + nalu_bytes[0: 4*8].hex == self.START_CODE_PREFIX: start_code = nalu_bytes.read('bytes:4') else: start_code = nalu_bytes.read('bytes:3') forbidden_zero_bit = nalu_bytes.read(1) nal_ref_idc = nalu_bytes.read('uint:2') nal_unit_type = nalu_bytes.read('uint:5') nal_unit_payload = nalu_bytes[nalu_bytes.pos:] rbsp_payload = BitStream() for i in range(int(len(nal_unit_payload)/8)): if len(nal_unit_payload) - nal_unit_payload.pos >= 24 and \ nal_unit_payload.peek('bits:24') == '0x000003': rbsp_payload.append(nal_unit_payload.read('bits:8')) rbsp_payload.append(nal_unit_payload.read('bits:8')) nal_unit_payload.read('bits:8') else: if nal_unit_payload.pos == len(nal_unit_payload): continue rbsp_payload.append(nal_unit_payload.read('bits:8')) return nal_unit_type, rbsp_payload def parse(self): """ Parse the bitstream and extract each NALU. Call the respective callbacks for each NALU type found. """ self._get_nalu_positions() nalu_sps = None nalu_pps = None for current_nalu_pos, next_nalu_pos in zip(self.nal_unit_positions, islice(self.nal_unit_positions, 1, None)): current_nalu_bytepos = int(current_nalu_pos / 8) next_nalu_bytepos = int(next_nalu_pos / 8) nalu_bytes = self.stream[current_nalu_pos: next_nalu_pos] self.__call('nalu', nalu_bytes) if self.verbose: print("") print("========================================================================================================") print("") print("NALU bytepos:\t[" + str(current_nalu_bytepos) + ", " + str(next_nalu_bytepos - 1) + "]") print("NALU offset:\t" + str(current_nalu_bytepos) + " Bytes") print("NALU length:\t" + str(next_nalu_bytepos - current_nalu_bytepos) + " Bytes (including start code)") current_nalu_stream_segment = BitStream(self.stream[current_nalu_pos: next_nalu_pos]) nal_unit_type, rbsp_payload = self._decode_nalu(current_nalu_stream_segment) if self.verbose: print("NALU type:\t" + str(nal_unit_type) + " (" + nalutypes.get_description(nal_unit_type) + ")") print("NALU bytes:\t" + str(nalu_bytes)) print("NALU RBSP:\t" + str(rbsp_payload)) print("") if nal_unit_type == nalutypes.NAL_UNIT_TYPE_SPS: nalu_sps = nalutypes.SPS(rbsp_payload, self.verbose) self.__call('sps', rbsp_payload) elif nal_unit_type == nalutypes.NAL_UNIT_TYPE_PPS: nalu_pps = nalutypes.PPS(rbsp_payload, self.verbose) self.__call('pps', rbsp_payload) elif nal_unit_type == nalutypes.NAL_UNIT_TYPE_AUD: aud = nalutypes.AUD(rbsp_payload, self.verbose) self.__call('aud', rbsp_payload) elif nal_unit_type == nalutypes.NAL_UNIT_TYPE_CODED_SLICE_NON_IDR: nalu_slice = nalutypes.CodedSliceNonIDR(rbsp_payload, nalu_sps, nalu_pps, self.verbose) self.__call('slice', rbsp_payload) elif nal_unit_type == nalutypes.NAL_UNIT_TYPE_CODED_SLICE_IDR: nalu_slice = nalutypes.CodedSliceIDR(rbsp_payload, nalu_sps, nalu_pps, self.verbose) self.__call('slice', rbsp_payload)
class GmoFile(): def __init__(self, data = None, offset = 0, filename = None): self.data = None self.__gim_files = [] self.gimconv = GimConverter() if not data == None: self.load_data(data, offset) elif not filename == None: self.load_file(filename) def load_file(self, filename): data = BitStream(filename = filename) self.load_data(data) def load_data(self, data, offset = 0): if not data[offset * 8 : offset * 8 + GMO_MAGIC.len] == GMO_MAGIC: _LOGGER.error("GMO header not found at 0x%04X." % offset) return data.bytepos = offset + GMO_SIZE_OFFSET gmo_size = data.read("uintle:32") + GMO_SIZE_DIFF self.data = BitStream(data[offset * 8 : (offset + gmo_size) * 8]) self.__find_gims() def save(self, filename): with open(filename, "wb") as f: self.data.tofile(f) def __find_gims(self): if self.data == None: return self.__gim_files = [] for gim_start in self.data.findall(GIM_MAGIC, bytealigned = True): gim_size_pos = gim_start + (GIM_SIZE_OFFSET * 8) # Bit pos. gim_size = self.data[gim_size_pos : gim_size_pos + 32].uintle + GIM_SIZE_DIFF # And turn it into a byte position. gim_start /= 8 self.__gim_files.append((gim_start, gim_size)) def gim_count(self): return len(self.__gim_files) def get_gim(self, gim_id): if gim_id >= self.gim_count(): raise GimIndexError("Invalid GIM ID.") gim_start, gim_size = self.__gim_files[gim_id] gim_data = self.data[gim_start * 8 : (gim_start + gim_size) * 8] return gim_data def replace_png_file(self, gim_id, filename, quantize_to_fit = True): if quantize_to_fit: quantize_order = [QuantizeType.auto, QuantizeType.index8, QuantizeType.index4] else: quantize_order = [QuantizeType.auto] quantize_id = 0 (fd, temp_gim) = tempfile.mkstemp(suffix = ".gim", prefix = "sdse-") os.close(fd) # Don't need the open file handle. while True: self.gimconv.png_to_gim(filename, temp_gim, quantize_order[quantize_id]) try: self.replace_gim_file(gim_id, temp_gim) except GimSizeError: quantize_id += 1 except GimIndexError: os.remove(temp_gim) raise else: # If we didn't except, that means we succeeded, so we can leave. _LOGGER.debug("Quantized PNG to %s" % quantize_order[quantize_id]) break if quantize_id > len(quantize_order): _LOGGER.error("Unable to convert %s into a GIM small enough to insert." % filename) break os.remove(temp_gim) def replace_gim_file(self, gim_id, filename): gim_data = BitStream(filename = filename) self.replace_gim(gim_id, gim_data) def replace_gim(self, gim_id, gim_data): if gim_id >= self.gim_count(): raise GimIndexError("Invalid GIM ID.") gim_start, gim_size = self.__gim_files[gim_id] if gim_data.len / 8 > gim_size: raise GimSizeError("GIM too large. %d bytes > %d bytes" % (gim_data.len / 8, gim_size)) # return self.data.overwrite(gim_data, gim_start * 8) # Leave the length alone, though, because we know we have that much space # to work with from the original GIM file that was there, and there's no # point in shrinking that down if someone happens to want to re-replace # this GIM file without reloading the whole thing. def extract(self, directory, to_png = False): if not os.path.isdir(directory): os.makedirs(directory) for id in range(self.gim_count()): gim = self.get_gim(id) out_gim = os.path.join(directory, "%04d.gim" % id) out_png = os.path.join(directory, "%04d.png" % id) with open(out_gim, "wb") as f: gim.tofile(f) if to_png: self.gimconv.gim_to_png(out_gim, out_png) os.remove(out_gim)
def main(): """ """ if args.infile == args.outfile : print ('Error! Source and Destination can not be the same file!') sys.exit() if not os.path.exists(args.infile) : print ('Error! Given input file name not found! Please check path given in CMD or set in script code!') sys.exit() if md_arg_str : md = re.findall('\d+',md_arg_str) if len(md) != 10 : print ('Specified wrong "-masterdisplay" parameter! Please check!\n Example: G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(10000000,1) or do not specify') sys.exit() if maxcll : mcll = re.findall('\d+',maxcll) sei_ok = 0 F = open (args.infile,'r+b') o = open (args.outfile,'wb') print ('Parsing the infile:') print ('') print ('==========================') print ('') print ('Prepending SEI data') s = BitStream(F.read(chunk)) nals = list(s.findall('0x000001', bytealigned=True)) sps_nals = list(s.findall('0x00000142', bytealigned=True)) sei_pref_nals = list (s.findall('0x0000014e', bytealigned=True)) size = [y - x for x,y in zip(nals,nals[1:])] sps_pos = list(set(nals).intersection(sps_nals)) sei_pref_nals_pos = list(set(nals).intersection(sei_pref_nals)) sps_size = size[nals.index(sps_nals[0])] if sei_pref_nals : sei_pref_nal_size = ( size[nals.index(sei_pref_nals[0])]) ### MAXCLL & MAXFALL ### if args.maxcll or md_arg_str : sei_forbidden_zero_bit = 0 sei_nal_unit_type = 39 sei_nuh_layer_id = 0 sei_nuh_temporal_id_plus1 = 1 new_sei_string = pack ('uint:1,2*uint:6,uint:3',sei_forbidden_zero_bit,sei_nal_unit_type,sei_nuh_layer_id,sei_nuh_temporal_id_plus1) print ('Starting new SEI NALu...') if maxcll : sei_last_payload_type_byte = 144 sei_last_payload_size_byte = 4 sei_max_content_light_level = int(mcll[0]) sei_max_pic_average_light_level = int(mcll[1]) new_sei_string += pack ('2*uint:8,2*uint:16',sei_last_payload_type_byte,sei_last_payload_size_byte,sei_max_content_light_level,sei_max_pic_average_light_level) print ('SEI message with MaxCLL=',sei_max_content_light_level,' and MaxFall=',sei_max_pic_average_light_level,' created in SEI NAL') if md_arg_str : md_sei_last_payload_type_byte = 137 md_sei_last_payload_size_byte = 24 #MD string ref #G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(10000000,1) new_sei_string += pack ('2*uint:8',md_sei_last_payload_type_byte,md_sei_last_payload_size_byte) for i in range (len(md)-2) : new_sei_string += pack ('uint:16',int(md[i])) new_sei_string += pack ('uint:32',int(md[8])) new_sei_string += pack ('uint:32',int(md[9])) new_sei_string.replace ('0x0000','0x000003',bytealigned=True) print ('SEI message Mastering Display Data',md_arg_str,'created in SEI NAL') new_sei_string = '0x00000001' + new_sei_string + '0x00' sei_ok = True ### ------------------ ### print ('Looking for SPS.........', sps_pos) print ('SPS_Nals_addresses', sps_pos) print ('SPS NAL Size', sps_size) print ('Starting reading SPS NAL contents') s.pos = sps_pos[0] t = s.peek(sps_size) t.pos = t.pos + 24 forbidden_zero_bit = t.read('uint:1') nal_unit_type = t.read('uint:6') nuh_layer_id = t.read('uint:6') nuh_temporal_id_plus1 = t.read('uint:3') nal_t = t[:] # 7.3.1.1 # Convert NAL data (Annex B format) to RBSP data t.tobytes() t.replace ('0x000003','0x0000') # SPS parse block sps_video_parameter_set_id = t.read('uint:4') sps_max_sub_layers_minus1 = t.read('uint:3') sps_temporal_id_nesting_flag = t.read('uint:1') ptl = profile_tier_level(t, sps_max_sub_layers_minus1) sps_seq_parameter_set_id = t.read('ue') chroma_format_idc = t.read('ue') if chroma_format_idc == 3: separate_colour_plane_flag = t.read('uint:1') pic_width_in_luma_samples = t.read ('ue') pic_height_in_luma_samples = t.read ('ue') conformance_window_flag = t.read ('uint:1') if (conformance_window_flag) : conf_win_left_offset = t.read('ue') conf_win_right_offset = t.read('ue') conf_win_top_offset = t.read('ue') conf_win_bottom_offset = t.read('ue') bit_depth_luma_minus8 = t.read ('ue') bit_depth_chroma_minus8 = t.read ('ue') log2_max_pic_order_cnt_lsb_minus4 = t.read('ue') sps_sub_layer_ordering_info_present_flag = t.read('uint:1') # for (i = (sps_sub_layer_ordering_info_present_flag ? 0 : sps.max_sub_layers_minus1); i <= sps.max_sub_layers_minus1; i++) if sps_sub_layer_ordering_info_present_flag : sps_max_dec_pic_buffering_minus1 = t.read('ue') sps_max_num_reorder_pics = t.read('ue') sps_max_latency_increase_plus1 = t.read('ue') log2_min_luma_coding_block_size_minus3 = t.read ('ue') log2_diff_max_min_luma_coding_block_size = t.read ('ue') log2_min_luma_transform_block_size_minus2 = t.read ('ue') log2_diff_max_min_luma_transform_block_size = t.read ('ue') max_transform_hierarchy_depth_inter = t.read ('ue') max_transform_hierarchy_depth_intra = t.read ('ue') scaling_list_enabled_flag = t.read ('uint:1') """ if( scaling_list_enabled_flag ) { sps_scaling_list_data_present_flag u(1) if( sps_scaling_list_data_present_flag ) scaling_list_data( ) } """ amp_enabled_flag = t.read ('uint:1') sample_adaptive_offset_enabled_flag = t.read ('uint:1') pcm_enabled_flag = t.read ('uint:1') if pcm_enabled_flag : pcm_sample_bit_depth_luma_minus1 = t.read ('uint:4') pcm_sample_bit_depth_chroma_minus1 = t.read ('uint:4') log2_min_pcm_luma_coding_block_size_minus3 = t.read ('ue') log2_diff_max_min_pcm_luma_coding_block_size = t.read ('ue') pcm_loop_filter_disabled_flag = t.read ('uint:1') num_short_term_ref_pic_sets = t.read ('ue') if num_short_term_ref_pic_sets : for i in range (num_short_term_ref_pic_sets): if i != 0 : inter_ref_pic_set_prediction_flag = t.read ('uint:1') if not 'inter_ref_pic_set_prediction_flag' in globals() : """ if i == num_short_term_ref_pic_sets : delta_idx_minus1 = t.read ('ue') if not 'delta_idx_minus1' in globals(): delta_idx_minus1 = 0 delta_rps_sign = t.read ('uint:1') abs_delta_rps_minus1 = t.read ('ue') for j in range (NumDeltaPoc) : used_by_curr_pic_flag[j] = t.read ('uint:1') if used_by_curr_pic_flag[j] : use_delta_flag[j] = t.read ('uint:1') else: """ num_negative_pics = t.read ('ue') num_positive_pics = t.read ('ue') delta_poc_s0_minus1 = [t.read ('ue') for _ in range (num_negative_pics)] used_by_curr_pic_s0_flag = [ t.read ('uint:1') for _ in range (num_negative_pics)] delta_poc_s1_minus1 = [t.read ('ue') for _ in range(num_positive_pics)] used_by_curr_pic_s1_flag = [t.read ('uint:1') for _ in range(num_positive_pics)] long_term_ref_pics_present_flag = t.read ('uint:1') if long_term_ref_pics_present_flag : num_long_term_ref_pics_sps = t.read ('ue') for i in range < (num_long_term_ref_pics_sps): lt_ref_pic_poc_lsb_sps[i] = t.read ('ue') used_by_curr_pic_lt_sps_flag[i] = t.read ('uint:1') sps_temporal_mvp_enabled_flag = t.read ('uint:1') strong_intra_smoothing_enabled_flag = t.read ('uint:1') vui_parameters_present_flag = t.read ('uint:1') if vui_parameters_present_flag : vp = vui_parameters(t) sps_extension_present_flag = t.read ('uint:1') if sps_extension_present_flag : sps_range_extension_flag = t.read ('uint:1') sps_multilayer_extension_flag = t.read ('uint:1') sps_3d_extension_flag = t.read ('uint:1') sps_extension_5bits = t.read ('uint:1') tb = rbsp_trailing_bits(t,len(t)) print ('Reading of SPS NAL finished. Read ',len(t),' of SPS NALu data.\n') # print block """ print ('sps_video_parameter_set_id', sps_video_parameter_set_id) print ('sps_max_sub_layers_minus1', sps_max_sub_layers_minus1) print ('sps_temporal_id_nesting_flag', sps_temporal_id_nesting_flag) ptl.show() print ('sps_seq_parameter_set_id', sps_seq_parameter_set_id) print ('chroma_format_idc', chroma_format_idc) if chroma_format_idc == 3: print ('separate_colour_plane_flag', separate_colour_plane_flag) print ('pic_width_in_luma_samples ', pic_width_in_luma_samples) #produces wrong number print ('pic_height_in_luma_samples', pic_height_in_luma_samples) #produces wrong number print ('conformance_window_flag', conformance_window_flag) print ('bit_depth_luma_minus8', bit_depth_luma_minus8) print ('bit_depth_chroma_minus8', bit_depth_chroma_minus8) print ('log2_max_pic_order_cnt_lsb_minus4', log2_max_pic_order_cnt_lsb_minus4) print ('sps_sub_layer_ordering_info_present_flag', sps_sub_layer_ordering_info_present_flag) if sps_sub_layer_ordering_info_present_flag : print ('sps_max_dec_pic_buffering_minus1', sps_max_dec_pic_buffering_minus1) print ('sps_max_num_reorder_pics', sps_max_num_reorder_pics) print ('sps_max_latency_increase_plus1', sps_max_latency_increase_plus1) print ('log2_min_luma_coding_block_size_minus3',log2_min_luma_coding_block_size_minus3) print ('log2_diff_max_min_luma_coding_block_size',log2_diff_max_min_luma_coding_block_size) print ('log2_min_luma_transform_block_size_minus2',log2_min_luma_transform_block_size_minus2) print ('log2_diff_max_min_luma_transform_block_size', log2_diff_max_min_luma_transform_block_size) print ('max_transform_hierarchy_depth_inter', max_transform_hierarchy_depth_inter) print ('max_transform_hierarchy_depth_intra', max_transform_hierarchy_depth_intra) print ('scaling_list_enabled_flag',scaling_list_enabled_flag) print ('amp_enabled_flag',amp_enabled_flag) print ('sample_adaptive_offset_enabled_flag',sample_adaptive_offset_enabled_flag) print ('pcm_enabled_flag',pcm_enabled_flag) if pcm_enabled_flag : print ('pcm_sample_bit_depth_luma_minus1',pcm_sample_bit_depth_luma_minus1) print ('pcm_sample_bit_depth_chroma_minus1',pcm_sample_bit_depth_chroma_minus1) print ('log2_min_pcm_luma_coding_block_size_minus3',log2_min_pcm_luma_coding_block_size_minus3) print ('log2_diff_max_min_pcm_luma_coding_block_size',log2_diff_max_min_pcm_luma_coding_block_size) print ('pcm_loop_filter_disabled_flag',pcm_loop_filter_disabled_flag) print ('num_short_term_ref_pic_sets',num_short_term_ref_pic_sets) print ('long_term_ref_pics_present_flag',long_term_ref_pics_present_flag) print ('sps_temporal_mvp_enabled_flag',sps_temporal_mvp_enabled_flag) print ('strong_intra_smoothing_enabled_flag',strong_intra_smoothing_enabled_flag) print ('vui_parameters_present_flag',vui_parameters_present_flag) if vui_parameters_present_flag : vp.show() print ('sps_extension_present_flag',sps_extension_present_flag) """ # New BS write Block print ('Making modified SPS NALu...') new_bs = BitStream() new_bs += pack('uint:4,uint:3,uint:1',sps_video_parameter_set_id,sps_max_sub_layers_minus1,sps_temporal_id_nesting_flag) new_bs += pack ('uint:2,uint:1,uint:5',ptl.general_profile_space, ptl.general_tier_flag,ptl.general_profile_idc) for i in range (32) : new_bs += pack('uint:1',int(ptl.general_profile_compatibility_flag[i])) new_bs += pack ('uint:1',ptl.general_progressive_source_flag) new_bs += pack ('uint:1',ptl.general_interlaced_source_flag) new_bs += pack ('uint:1',ptl.general_non_packed_constraint_flag) new_bs += pack ('uint:1',ptl.general_frame_only_constraint_flag) new_bs += pack ('uint:44',ptl.general_reserved_zero_44bits) new_bs += pack ('uint:8',ptl.general_level_idc) new_bs += pack ('ue',sps_seq_parameter_set_id) new_bs += pack ('ue',chroma_format_idc) if chroma_format_idc == 3: new_bs += pack ('uint:1',separate_colour_plane_flag) new_bs += pack ('ue',pic_width_in_luma_samples) new_bs += pack ('ue',pic_height_in_luma_samples) new_bs += pack ('uint:1',conformance_window_flag) if (conformance_window_flag) : new_bs += pack ('ue',conf_win_left_offset) new_bs += pack ('ue',conf_win_right_offset) new_bs += pack ('ue',conf_win_top_offset) new_bs += pack ('ue',conf_win_bottom_offset) new_bs += pack ('ue',bit_depth_luma_minus8) new_bs += pack ('ue',bit_depth_chroma_minus8) new_bs += pack ('ue',log2_max_pic_order_cnt_lsb_minus4) new_bs += pack ('uint:1',sps_sub_layer_ordering_info_present_flag) # for (i = (sps_sub_layer_ordering_info_present_flag ? 0 : sps.max_sub_layers_minus1); i <= sps.max_sub_layers_minus1; i++) if sps_sub_layer_ordering_info_present_flag : new_bs += pack ('ue',sps_max_dec_pic_buffering_minus1) new_bs += pack ('ue',sps_max_num_reorder_pics) new_bs += pack ('ue',sps_max_latency_increase_plus1) new_bs += pack ('ue',log2_min_luma_coding_block_size_minus3) new_bs += pack ('ue',log2_diff_max_min_luma_coding_block_size) new_bs += pack ('ue',log2_min_luma_transform_block_size_minus2) new_bs += pack ('ue',log2_diff_max_min_luma_transform_block_size) new_bs += pack ('ue',max_transform_hierarchy_depth_inter) new_bs += pack ('ue',max_transform_hierarchy_depth_intra) new_bs += pack ('uint:1',scaling_list_enabled_flag) # new_bs += pack ('uint:1',amp_enabled_flag) new_bs += pack ('uint:1',sample_adaptive_offset_enabled_flag) new_bs += pack ('uint:1',pcm_enabled_flag) if pcm_enabled_flag : new_bs += pack ('uint:4',pcm_sample_bit_depth_luma_minus1) new_bs += pack ('uint:4',pcm_sample_bit_depth_chroma_minus1) new_bs += pack ('ue',log2_min_pcm_luma_coding_block_size_minus3) new_bs += pack ('ue',log2_diff_max_min_pcm_luma_coding_block_size) new_bs += pack ('uint:1',pcm_loop_filter_disabled_flag) new_bs += pack ('ue',num_short_term_ref_pic_sets) if num_short_term_ref_pic_sets : for i in range (num_short_term_ref_pic_sets) : if i != 0 : new_bs += pack ('uint:1',inter_ref_pic_set_prediction_flag) if not 'inter_ref_pic_set_prediction_flag' in globals() : """ if i == num_short_term_ref_pic_sets : new_bs += pack ('ue',delta_idx_minus1) new_bs += pack ('uint:1', delta_rps_sign) new_bs += pack ('ue',abs_delta_rps_minus1) for j in range (NumDeltaPocs[i - (delta_idx_minus1 +1)]) : new_bs += pack ('uint:1', used_by_curr_pic_flag[j]) if used_by_curr_pic_flag[j] : new_bs += pack ('uint:1',use_delta_flag[j]) else : """ new_bs += pack ('ue',num_negative_pics) new_bs += pack ('ue',num_positive_pics) new_bs += [pack ('ue',delta_poc_s0_minus1[_]) for _ in range (num_negative_pics)] new_bs += [pack ('uint:1',used_by_curr_pic_s0_flag[_]) for _ in range (num_negative_pics)] new_bs += [pack ('ue',delta_poc_s1_minus1[_]) for _ in range(num_positive_pics)] new_bs += [pack ('uint:1',used_by_curr_pic_s1_flag[_]) for _ in range(num_positive_pics)] new_bs += pack ('uint:1',long_term_ref_pics_present_flag) if long_term_ref_pics_present_flag : new_bs += pack ('ue',num_long_term_ref_pics_sps) new_bs += pack ('uint:1',sps_temporal_mvp_enabled_flag) new_bs += pack ('uint:1',strong_intra_smoothing_enabled_flag) new_bs += pack ('uint:1',vui_parameters_present_flag) # VUI VP pack Section if vui_parameters_present_flag : new_bs += pack ('uint:1',vp.aspect_ratio_info_present_flag) if vp.aspect_ratio_info_present_flag : new_bs += pack ('uint:8',vp.aspect_ratio_idc) if vp.aspect_ratio_idc == 255 : new_bs += pack ('uint:16',vp.sar_width) new_bs += pack ('uint:16',vp.sar_height) new_bs += pack ('uint:1',vp.overscan_info_present_flag) if vp.overscan_info_present_flag : new_bs += pack ('uint:1',vp.overscan_appropriate_flag) new_bs += pack ('uint:1',vp.video_signal_type_present_flag) if vp.video_signal_type_present_flag : new_bs += pack ('uint:3',vp.video_format) new_bs += pack ('uint:1',vp.video_full_range_flag) new_bs += pack ('uint:1',vp.colour_description_present_flag) if vp.colour_description_present_flag : new_bs += pack ('uint:8',vp.colour_primaries) new_bs += pack ('uint:8',vp.transfer_characteristics) new_bs += pack ('uint:8',vp.matrix_coeffs) new_bs += pack ('uint:1',vp.chroma_loc_info_present_flag) if vp.chroma_loc_info_present_flag : new_bs += pack ('ue',vp.chroma_sample_loc_type_top_field) new_bs += pack ('ue',vp.chroma_sample_loc_type_bottom_field) new_bs += pack ('uint:1',vp.neutral_chroma_indication_flag) new_bs += pack ('uint:1',vp.field_seq_flag) new_bs += pack ('uint:1',vp.frame_field_info_present_flag) new_bs += pack ('uint:1',vp.default_display_window_flag) if vp.default_display_window_flag : new_bs += pack ('ue',vp.def_disp_win_left_offset) new_bs += pack ('ue',vp.def_disp_win_right_offset) new_bs += pack ('ue',vp.def_disp_win_top_offset) new_bs += pack ('ue',vp.def_disp_win_bottom_offset) new_bs += pack ('uint:1',vp.vui_timing_info_present_flag) if vp.vui_timing_info_present_flag : new_bs += pack ('uint:32',vp.vui_num_units_in_tick) new_bs += pack ('uint:32',vp.vui_time_scale) new_bs += pack ('uint:1',vp.vui_poc_proportional_to_timing_flag) if vp.vui_poc_proportional_to_timing_flag : new_bs += pack ('ue',vp.vui_num_ticks_poc_diff_one_minus1) new_bs += pack ('uint:1',vp.vui_hrd_parameters_present_flag) """ if( vui_hrd_parameters_present_flag ) hrd_parameters( 1, sps_max_sub_layers_minus1 ) """ new_bs += pack ('uint:1',vp.bitstream_restriction_flag) if vp. bitstream_restriction_flag : new_bs += pack ('uint:1',vp.tiles_fixed_structure_flag) new_bs += pack ('uint:1',vp.motion_vectors_over_pic_boundaries_flag) new_bs += pack ('uint:1',vp.restricted_ref_pic_lists_flag) new_bs += pack ('ue',vp.min_spatial_segmentation_idc) new_bs += pack ('ue',vp.max_bytes_per_pic_denom) new_bs += pack ('ue',vp.max_bits_per_min_cu_denom) new_bs += pack ('ue',vp.log2_max_mv_length_horizontal) new_bs += pack ('ue',vp.log2_max_mv_length_vertical) new_bs += pack ('uint:1',sps_extension_present_flag) if sps_extension_present_flag : new_bs += pack ('uint:1',sps_range_extension_flag) new_bs += pack ('uint:1',sps_multilayer_extension_flag) new_bs += pack ('uint:1',sps_3d_extension_flag) new_bs += pack ('uint:1',sps_extension_5bits) new_bs += pack ('uint:1',tb.rbsp_stop_one_bit) while len(new_bs) < t.pos : new_bs += pack ('uint:1',tb.rbsp_alignment_zero_bit) # self.sub_layer_profile_present_flag = [] # self.sub_layer_level_present_flag = [] # for i in range(maxNumSubLayersMinus1): # self.sub_layer_profile_present_flag.append(t.read('uint:1')) # self.sub_layer_level_present_flag.append(t.read('uint:1')) pre_new_bs = pack ('uint:1,2*uint:6,uint:3', forbidden_zero_bit,nal_unit_type,nuh_layer_id,nuh_temporal_id_plus1) new_bs.replace ('0x0000','0x000003',bytealigned=True) new_bs = pre_new_bs + new_bs + '0x00' nal_t_rep = nal_t[24:] repl = s.replace (nal_t_rep,new_bs, bytealigned=True) print ('Made modified SPS NALu - OK') if sei_ok : s.prepend (new_sei_string) print ('New SEI prepended') print ('Writing new stream...') s.tofile(o) progr = chunk while True: s = F.read(chunk) o.write(s) if progr < os.path.getsize(args.infile): print ('\rProgress ',int(round((progr/os.path.getsize(args.infile))*100)),'%',end='') progr = progr + chunk if not s: break o.close() F.close() print ('\rProgress: 100 %') print ('=====================') print ('Done!') print ('') print ('File ',args.outfile,' created.') sys.exit()
import sys import bitstring import shutil import random import pandas as pd import subprocess from bitstring import BitStream, BitArray, ConstBitStream, pack name = str(sys.argv[1]) name = name.split('.')[0] s = BitStream(filename=str(sys.argv[1])) # take the file name posu = None if (len(sys.argv) == 3): posu = str(sys.argv[2]) pcksTOPs = list( s.findall('0x00000001', bytealigned=True)) # All frame headers includes VPS,SPS and PPS pcks = list(s.findall( '0x000001', bytealigned=True)) # Find NAL for slices includes VPS,SPS,PPS and SEI pcksAdj = [ p + 8 for p in pcksTOPs ] # +8 to bring the postion to first of 0x00'000001 from 0x'00000001) to compare positions found b = set(pcksAdj) allowedIDS = [i for i, item in enumerate(pcks) if item not in b] del allowedIDS[0:12] # exclude SEI NAL which has delimiter 0x000001 def conceal_p1(s, posi): #constants: NAL_header = 16 NAL_delimiter = 24
class GmoFile(): def __init__(self, data=None, offset=0, filename=None): self.data = None self.__gim_files = [] self.gimconv = GimConverter() if not data == None: self.load_data(data, offset) elif not filename == None: self.load_file(filename) def load_file(self, filename): data = BitStream(filename=filename) self.load_data(data) def load_data(self, data, offset=0): if not data[offset * 8:offset * 8 + GMO_MAGIC.len] == GMO_MAGIC: _LOGGER.error("GMO header not found at 0x%04X." % offset) return data.bytepos = offset + GMO_SIZE_OFFSET gmo_size = data.read("uintle:32") + GMO_SIZE_DIFF self.data = BitStream(data[offset * 8:(offset + gmo_size) * 8]) self.__find_gims() def save(self, filename): with open(filename, "wb") as f: self.data.tofile(f) def __find_gims(self): if self.data == None: return self.__gim_files = [] for gim_start in self.data.findall(GIM_MAGIC, bytealigned=True): gim_size_pos = gim_start + (GIM_SIZE_OFFSET * 8) # Bit pos. gim_size = self.data[gim_size_pos:gim_size_pos + 32].uintle + GIM_SIZE_DIFF # And turn it into a byte position. gim_start /= 8 self.__gim_files.append((gim_start, gim_size)) def gim_count(self): return len(self.__gim_files) def get_gim(self, gim_id): if gim_id >= self.gim_count(): raise GimIndexError("Invalid GIM ID.") gim_start, gim_size = self.__gim_files[gim_id] gim_data = self.data[gim_start * 8:(gim_start + gim_size) * 8] return gim_data def replace_png_file(self, gim_id, filename, quantize_to_fit=True): if quantize_to_fit: quantize_order = [ QuantizeType.auto, QuantizeType.index8, QuantizeType.index4 ] else: quantize_order = [QuantizeType.auto] quantize_id = 0 (fd, temp_gim) = tempfile.mkstemp(suffix=".gim", prefix="sdse-") os.close(fd) # Don't need the open file handle. while True: self.gimconv.png_to_gim(filename, temp_gim, quantize_order[quantize_id]) try: self.replace_gim_file(gim_id, temp_gim) except GimSizeError: quantize_id += 1 except GimIndexError: os.remove(temp_gim) raise else: # If we didn't except, that means we succeeded, so we can leave. _LOGGER.debug("Quantized PNG to %s" % quantize_order[quantize_id]) break if quantize_id > len(quantize_order): _LOGGER.error( "Unable to convert %s into a GIM small enough to insert." % filename) break os.remove(temp_gim) def replace_gim_file(self, gim_id, filename): gim_data = BitStream(filename=filename) self.replace_gim(gim_id, gim_data) def replace_gim(self, gim_id, gim_data): if gim_id >= self.gim_count(): raise GimIndexError("Invalid GIM ID.") gim_start, gim_size = self.__gim_files[gim_id] if gim_data.len / 8 > gim_size: raise GimSizeError("GIM too large. %d bytes > %d bytes" % (gim_data.len / 8, gim_size)) # return self.data.overwrite(gim_data, gim_start * 8) # Leave the length alone, though, because we know we have that much space # to work with from the original GIM file that was there, and there's no # point in shrinking that down if someone happens to want to re-replace # this GIM file without reloading the whole thing. def extract(self, directory, to_png=False): if not os.path.isdir(directory): os.makedirs(directory) for id in range(self.gim_count()): gim = self.get_gim(id) out_gim = os.path.join(directory, "%04d.gim" % id) out_png = os.path.join(directory, "%04d.png" % id) with open(out_gim, "wb") as f: gim.tofile(f) if to_png: self.gimconv.gim_to_png(out_gim, out_png) os.remove(out_gim)