File: get_next_access_unit.py

package info (click to toggle)
tstools 1.13~git20151030-5
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 2,916 kB
  • sloc: ansic: 37,970; java: 2,243; makefile: 466; python: 319; sh: 5
file content (159 lines) | stat: -rw-r--r-- 7,589 bytes parent folder | download | duplicates (3)
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