1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
# 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
|