# Pseudo-Python rendition of the code for ``get_next_access_unit()``. # ***** BEGIN LICENSE BLOCK ***** # Version: MPL 1.1 # # The contents of this file are subject to the Mozilla Public License Version # 1.1 (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # http://www.mozilla.org/MPL/ # # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License # for the specific language governing rights and limitations under the # License. # # The Original Code is the MPEG TS, PS and ES tools. # # The Initial Developer of the Original Code is Amino Communications Ltd. # Portions created by the Initial Developer are Copyright (C) 2008 # the Initial Developer. All Rights Reserved. # # Contributor(s): # Amino Communications Ltd, Swavesey, Cambridge UK # # ***** END LICENSE BLOCK ***** def get_next_access_unit(context): """Retrieve the next access unit from the file described by `context`. """ access_unit = build_access_unit() if context.pending_nal: # i.e., we already had a NAL to start this unit access_unit.append(context.pending_nal,TRUE,context.pending_list) context.pending_nal = NULL context.pending_list.reset(FALSE) while 1: try: nal = context.find_next_NAL_unit() except EOF: context.no_more_data = TRUE; # prevent future reads on this stream break except BrokenNALUnit: WARNING("!!! Ignoring broken NAL unit\n") access_unit.ignored_broken_NAL_units += 1 continue if nal.is_slice(): if not access_unit.started_primary_picture: # We're in a new access unit, but we haven't had a slice # yet, so we can be lazy and assume that this must be the # first slice nal.start_reason = "First slice of new access unit" access_unit.append(nal,TRUE,context.pending_list) context.pending_list.reset(FALSE) context.remember_earlier_primary_start(nal) elif nal.is_first_VCL_NAL(context.earlier_primary_start): # Regardless of what we determine next, we need to remember # that the NAL started (what may later be the previous) access # unit context.remember_earlier_primary_start(nal) if access_unit.started_primary_picture: # We were already in an access unit with a primary # picture, so this NAL unit must start a new access unit. # Remember it for next time, and return the access unit so # far. context.pending_nal = nal break; # Ready to return the access unit else: # This access unit was waiting for its primary picture access_unit.append(nal,TRUE,context.pending_list) context.pending_list.reset(FALSE) elif not access_unit.started_primary_picture: # But this is not a NAL unit that may start a new # access unit. So what should we do? Ignore it? if not quiet: WARNING("!!! Ignoring VCL NAL that cannot start a new" " primary picture: " nal.report(stderr) elif nal_is_redundant(nal): # printf(" ignoring redundant NAL unit\n") pass else: # We're part of the same access unit, but not special access_unit.append(nal,FALSE,context.pending_list) context.pending_list.reset(FALSE) elif nal.nal_unit_type == NAL_ACCESS_UNIT_DELIM: # An access unit delimiter always starts a new access unit if access_unit.started_primary_picture: context.pending_list.append(nal) break # Ready to return the "previous" access unit else: # The current access unit doesn't yet have any VCL NALs if context.pending_list.length > 0: WARNING("!!! Ignoring items after last VCL NAL and" " before Access Unit Delimiter\n") context.pending_list.report(stderr," ",NULL,) context.pending_list.reset(TRUE) if access_unit.nal_units.length > 0: WARNING("!!! Ignoring incomplete access unit\n") access_unit.nal_units.report(stderr," ",NULL,) access_unit.nal_units.reset(TRUE) access_unit.append(nal,FALSE,NULL) elif nal.nal_unit_type == NAL_SEI: # SEI units always precede the primary coded picture # - so they also implicitly end any access unit that has already # started its primary picture if access_unit.started_primary_picture: context.pending_list.append(nal) break # Ready to return the "previous" access unit else: context.pending_list.append(nal) elif nal.nal_unit_type in [NAL_SEQ_PARAM_SET, NAL_PIC_PARAM_SET, 13, 14, 15, 16, 17, 18]: # These start a new access unit *if* they come after the last VCL # NAL of an access unit. But we can only *tell* that they are # after the last VCL NAL of an access unit when we start the next # access unit - so we need to hold them in hand until we know that # we need them. (i.e., they'll get added to an access unit just # before the next "more determined" NAL unit we add to an access # unit) context.pending_list.append(nal) elif nal.nal_unit_type == NAL_END_OF_SEQ: if context.pending_list.length > 0: WARNING("!!! Ignoring items after last VCL NAL and" " before End of Sequence\n") context.pending_list.report(stderr," ",NULL,) context.pending_list.reset(TRUE) # And remember this as the End of Sequence marker context.end_of_sequence = nal break elif nal.nal_unit_type == NAL_END_OF_STREAM: # And remember this as the End of Stream marker context.end_of_stream = nal # Which means there's no point in reading more from this stream # (setting no_more_data like this means that *next* time this # function is called, it will return EOF) context.no_more_data = TRUE # And we're done break else: # It's not a slice, or an access unit delimiter, or an # end of sequence or stream, or a sequence or picture # parameter set, or various other odds and ends, so it # looks like we can ignore it. pass # Check for an immediate "end of file with no data" # - i.e., we read EOF or end of stream, and there was nothing # between the last access unit and such reading if context.no_more_data and access_unit.nal_units.length == 0: raise EOF # Otherwise, finish off and return the access unit we have in hand access_unit.end(context,show_details) # Remember to count it context.access_unit_index += 1 return access_unit