kopia lustrzana https://github.com/F5OEO/tstools
160 wiersze
7.4 KiB
Python
160 wiersze
7.4 KiB
Python
# 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
|