Mercurial > libavformat.hg
annotate avc.c @ 5786:7d670040187e libavformat
In mpegts muxer, search for h264 aud nal, it might not be the first nal.
Improve ther error message when bitstream is malformated and tell user to use
the bitstream filter.
author | bcoudurier |
---|---|
date | Mon, 08 Mar 2010 23:59:05 +0000 |
parents | d63669d827bc |
children |
rev | line source |
---|---|
201
85def00971c3
mov, 3gp, mp4 muxer by (Thomas Raivio <tjraivio at cc dot hut dot fi>)
michaelni
parents:
diff
changeset
|
1 /* |
2922
dcd599833abc
Move isom_write_avcc() and related functions into a separate file.
aurel
parents:
2921
diff
changeset
|
2 * AVC helper functions for muxers |
dcd599833abc
Move isom_write_avcc() and related functions into a separate file.
aurel
parents:
2921
diff
changeset
|
3 * Copyright (c) 2006 Baptiste Coudurier <baptiste.coudurier@smartjog.com> |
201
85def00971c3
mov, 3gp, mp4 muxer by (Thomas Raivio <tjraivio at cc dot hut dot fi>)
michaelni
parents:
diff
changeset
|
4 * |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1292
diff
changeset
|
5 * This file is part of FFmpeg. |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1292
diff
changeset
|
6 * |
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1292
diff
changeset
|
7 * FFmpeg is free software; you can redistribute it and/or |
201
85def00971c3
mov, 3gp, mp4 muxer by (Thomas Raivio <tjraivio at cc dot hut dot fi>)
michaelni
parents:
diff
changeset
|
8 * modify it under the terms of the GNU Lesser General Public |
85def00971c3
mov, 3gp, mp4 muxer by (Thomas Raivio <tjraivio at cc dot hut dot fi>)
michaelni
parents:
diff
changeset
|
9 * License as published by the Free Software Foundation; either |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1292
diff
changeset
|
10 * version 2.1 of the License, or (at your option) any later version. |
201
85def00971c3
mov, 3gp, mp4 muxer by (Thomas Raivio <tjraivio at cc dot hut dot fi>)
michaelni
parents:
diff
changeset
|
11 * |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1292
diff
changeset
|
12 * FFmpeg is distributed in the hope that it will be useful, |
201
85def00971c3
mov, 3gp, mp4 muxer by (Thomas Raivio <tjraivio at cc dot hut dot fi>)
michaelni
parents:
diff
changeset
|
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
85def00971c3
mov, 3gp, mp4 muxer by (Thomas Raivio <tjraivio at cc dot hut dot fi>)
michaelni
parents:
diff
changeset
|
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
85def00971c3
mov, 3gp, mp4 muxer by (Thomas Raivio <tjraivio at cc dot hut dot fi>)
michaelni
parents:
diff
changeset
|
15 * Lesser General Public License for more details. |
85def00971c3
mov, 3gp, mp4 muxer by (Thomas Raivio <tjraivio at cc dot hut dot fi>)
michaelni
parents:
diff
changeset
|
16 * |
85def00971c3
mov, 3gp, mp4 muxer by (Thomas Raivio <tjraivio at cc dot hut dot fi>)
michaelni
parents:
diff
changeset
|
17 * You should have received a copy of the GNU Lesser General Public |
1358
0899bfe4105c
Change license headers to say 'FFmpeg' instead of 'this program/this library'
diego
parents:
1292
diff
changeset
|
18 * License along with FFmpeg; if not, write to the Free Software |
896
edbe5c3717f9
Update licensing information: The FSF changed postal address.
diego
parents:
890
diff
changeset
|
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
201
85def00971c3
mov, 3gp, mp4 muxer by (Thomas Raivio <tjraivio at cc dot hut dot fi>)
michaelni
parents:
diff
changeset
|
20 */ |
4201
7d2f3f1b68d8
Fix build: Add intreadwrite.h and bswap.h #includes where necessary.
diego
parents:
3050
diff
changeset
|
21 |
7d2f3f1b68d8
Fix build: Add intreadwrite.h and bswap.h #includes where necessary.
diego
parents:
3050
diff
changeset
|
22 #include "libavutil/intreadwrite.h" |
201
85def00971c3
mov, 3gp, mp4 muxer by (Thomas Raivio <tjraivio at cc dot hut dot fi>)
michaelni
parents:
diff
changeset
|
23 #include "avformat.h" |
85def00971c3
mov, 3gp, mp4 muxer by (Thomas Raivio <tjraivio at cc dot hut dot fi>)
michaelni
parents:
diff
changeset
|
24 #include "avio.h" |
5724
d63669d827bc
Include avc.h from avc.c: It contains several prototypes.
cehoyos
parents:
5686
diff
changeset
|
25 #include "avc.h" |
201
85def00971c3
mov, 3gp, mp4 muxer by (Thomas Raivio <tjraivio at cc dot hut dot fi>)
michaelni
parents:
diff
changeset
|
26 |
5686
a84525174bcf
Attempt to fix the completely random values returned by ff_avc_find_startcode().
michael
parents:
5122
diff
changeset
|
27 static const uint8_t *ff_avc_find_startcode_internal(const uint8_t *p, const uint8_t *end) |
1006
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
28 { |
4792 | 29 const uint8_t *a = p + 4 - ((intptr_t)p & 3); |
1006
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
30 |
5122
6ea4f08de89a
cosmetics, remove spaces after '(' and before ')'
bcoudurier
parents:
4792
diff
changeset
|
31 for (end -= 3; p < a && p < end; p++) { |
6ea4f08de89a
cosmetics, remove spaces after '(' and before ')'
bcoudurier
parents:
4792
diff
changeset
|
32 if (p[0] == 0 && p[1] == 0 && p[2] == 1) |
1006
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
33 return p; |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
34 } |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
35 |
5122
6ea4f08de89a
cosmetics, remove spaces after '(' and before ')'
bcoudurier
parents:
4792
diff
changeset
|
36 for (end -= 3; p < end; p += 4) { |
3050
be4d4abb3eed
Fix misplaced const, avoids a cast-discards-qualifiers warning
reimar
parents:
3049
diff
changeset
|
37 uint32_t x = *(const uint32_t*)p; |
5122
6ea4f08de89a
cosmetics, remove spaces after '(' and before ')'
bcoudurier
parents:
4792
diff
changeset
|
38 // if ((x - 0x01000100) & (~x) & 0x80008000) // little endian |
6ea4f08de89a
cosmetics, remove spaces after '(' and before ')'
bcoudurier
parents:
4792
diff
changeset
|
39 // if ((x - 0x00010001) & (~x) & 0x00800080) // big endian |
6ea4f08de89a
cosmetics, remove spaces after '(' and before ')'
bcoudurier
parents:
4792
diff
changeset
|
40 if ((x - 0x01010101) & (~x) & 0x80808080) { // generic |
6ea4f08de89a
cosmetics, remove spaces after '(' and before ')'
bcoudurier
parents:
4792
diff
changeset
|
41 if (p[1] == 0) { |
6ea4f08de89a
cosmetics, remove spaces after '(' and before ')'
bcoudurier
parents:
4792
diff
changeset
|
42 if (p[0] == 0 && p[2] == 1) |
5686
a84525174bcf
Attempt to fix the completely random values returned by ff_avc_find_startcode().
michael
parents:
5122
diff
changeset
|
43 return p; |
5122
6ea4f08de89a
cosmetics, remove spaces after '(' and before ')'
bcoudurier
parents:
4792
diff
changeset
|
44 if (p[2] == 0 && p[3] == 1) |
5686
a84525174bcf
Attempt to fix the completely random values returned by ff_avc_find_startcode().
michael
parents:
5122
diff
changeset
|
45 return p+1; |
1006
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
46 } |
5122
6ea4f08de89a
cosmetics, remove spaces after '(' and before ')'
bcoudurier
parents:
4792
diff
changeset
|
47 if (p[3] == 0) { |
6ea4f08de89a
cosmetics, remove spaces after '(' and before ')'
bcoudurier
parents:
4792
diff
changeset
|
48 if (p[2] == 0 && p[4] == 1) |
5686
a84525174bcf
Attempt to fix the completely random values returned by ff_avc_find_startcode().
michael
parents:
5122
diff
changeset
|
49 return p+2; |
5122
6ea4f08de89a
cosmetics, remove spaces after '(' and before ')'
bcoudurier
parents:
4792
diff
changeset
|
50 if (p[4] == 0 && p[5] == 1) |
5686
a84525174bcf
Attempt to fix the completely random values returned by ff_avc_find_startcode().
michael
parents:
5122
diff
changeset
|
51 return p+3; |
1006
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
52 } |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
53 } |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
54 } |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
55 |
5122
6ea4f08de89a
cosmetics, remove spaces after '(' and before ')'
bcoudurier
parents:
4792
diff
changeset
|
56 for (end += 3; p < end; p++) { |
6ea4f08de89a
cosmetics, remove spaces after '(' and before ')'
bcoudurier
parents:
4792
diff
changeset
|
57 if (p[0] == 0 && p[1] == 0 && p[2] == 1) |
1006
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
58 return p; |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
59 } |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
60 |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
61 return end + 3; |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
62 } |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
63 |
5686
a84525174bcf
Attempt to fix the completely random values returned by ff_avc_find_startcode().
michael
parents:
5122
diff
changeset
|
64 const uint8_t *ff_avc_find_startcode(const uint8_t *p, const uint8_t *end){ |
a84525174bcf
Attempt to fix the completely random values returned by ff_avc_find_startcode().
michael
parents:
5122
diff
changeset
|
65 const uint8_t *out= ff_avc_find_startcode_internal(p, end); |
a84525174bcf
Attempt to fix the completely random values returned by ff_avc_find_startcode().
michael
parents:
5122
diff
changeset
|
66 if(p<out && out<end && !out[-1]) out--; |
a84525174bcf
Attempt to fix the completely random values returned by ff_avc_find_startcode().
michael
parents:
5122
diff
changeset
|
67 return out; |
a84525174bcf
Attempt to fix the completely random values returned by ff_avc_find_startcode().
michael
parents:
5122
diff
changeset
|
68 } |
a84525174bcf
Attempt to fix the completely random values returned by ff_avc_find_startcode().
michael
parents:
5122
diff
changeset
|
69 |
4224 | 70 int ff_avc_parse_nal_units(ByteIOContext *pb, const uint8_t *buf_in, int size) |
1006
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
71 { |
3049 | 72 const uint8_t *p = buf_in; |
4222
0267c4299992
Do not reallocate AVPacket's data when muxing a packet
lucabe
parents:
4201
diff
changeset
|
73 const uint8_t *end = p + size; |
3049 | 74 const uint8_t *nal_start, *nal_end; |
1006
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
75 |
4224 | 76 size = 0; |
2935
88a67636f192
Make avc_find_startcode non-static, so that it can be used from other
lucabe
parents:
2927
diff
changeset
|
77 nal_start = ff_avc_find_startcode(p, end); |
1006
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
78 while (nal_start < end) { |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
79 while(!*(nal_start++)); |
2935
88a67636f192
Make avc_find_startcode non-static, so that it can be used from other
lucabe
parents:
2927
diff
changeset
|
80 nal_end = ff_avc_find_startcode(nal_start, end); |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2669
diff
changeset
|
81 put_be32(pb, nal_end - nal_start); |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2669
diff
changeset
|
82 put_buffer(pb, nal_start, nal_end - nal_start); |
4224 | 83 size += 4 + nal_end - nal_start; |
1006
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
84 nal_start = nal_end; |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
85 } |
4224 | 86 return size; |
4222
0267c4299992
Do not reallocate AVPacket's data when muxing a packet
lucabe
parents:
4201
diff
changeset
|
87 } |
0267c4299992
Do not reallocate AVPacket's data when muxing a packet
lucabe
parents:
4201
diff
changeset
|
88 |
4226 | 89 int ff_avc_parse_nal_units_buf(const uint8_t *buf_in, uint8_t **buf, int *size) |
4222
0267c4299992
Do not reallocate AVPacket's data when muxing a packet
lucabe
parents:
4201
diff
changeset
|
90 { |
0267c4299992
Do not reallocate AVPacket's data when muxing a packet
lucabe
parents:
4201
diff
changeset
|
91 ByteIOContext *pb; |
0267c4299992
Do not reallocate AVPacket's data when muxing a packet
lucabe
parents:
4201
diff
changeset
|
92 int ret = url_open_dyn_buf(&pb); |
0267c4299992
Do not reallocate AVPacket's data when muxing a packet
lucabe
parents:
4201
diff
changeset
|
93 if(ret < 0) |
0267c4299992
Do not reallocate AVPacket's data when muxing a packet
lucabe
parents:
4201
diff
changeset
|
94 return ret; |
0267c4299992
Do not reallocate AVPacket's data when muxing a packet
lucabe
parents:
4201
diff
changeset
|
95 |
0267c4299992
Do not reallocate AVPacket's data when muxing a packet
lucabe
parents:
4201
diff
changeset
|
96 ff_avc_parse_nal_units(pb, buf_in, *size); |
0267c4299992
Do not reallocate AVPacket's data when muxing a packet
lucabe
parents:
4201
diff
changeset
|
97 |
1006
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
98 av_freep(buf); |
2771
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2669
diff
changeset
|
99 *size = url_close_dyn_buf(pb, buf); |
d52c718e83f9
Use dynamically allocated ByteIOContext in AVFormatContext
andoma
parents:
2669
diff
changeset
|
100 return 0; |
1006
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
101 } |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
102 |
3049 | 103 int ff_isom_write_avcc(ByteIOContext *pb, const uint8_t *data, int len) |
1006
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
104 { |
2921 | 105 if (len > 6) { |
1006
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
106 /* check for h264 start code */ |
4229 | 107 if (AV_RB32(data) == 0x00000001 || |
108 AV_RB24(data) == 0x000001) { | |
3049 | 109 uint8_t *buf=NULL, *end, *start; |
1006
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
110 uint32_t sps_size=0, pps_size=0; |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
111 uint8_t *sps=0, *pps=0; |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
112 |
4222
0267c4299992
Do not reallocate AVPacket's data when muxing a packet
lucabe
parents:
4201
diff
changeset
|
113 int ret = ff_avc_parse_nal_units_buf(data, &buf, &len); |
2919 | 114 if (ret < 0) |
115 return ret; | |
3049 | 116 start = buf; |
2921 | 117 end = buf + len; |
1006
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
118 |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
119 /* look for sps and pps */ |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
120 while (buf < end) { |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
121 unsigned int size; |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
122 uint8_t nal_type; |
1673 | 123 size = AV_RB32(buf); |
1006
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
124 nal_type = buf[4] & 0x1f; |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
125 if (nal_type == 7) { /* SPS */ |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
126 sps = buf + 4; |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
127 sps_size = size; |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
128 } else if (nal_type == 8) { /* PPS */ |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
129 pps = buf + 4; |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
130 pps_size = size; |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
131 } |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
132 buf += size + 4; |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
133 } |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
134 assert(sps); |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
135 assert(pps); |
1056
4af4c74a4548
get avcC profile and level indication from sps (from handbrake)
bcoudurier
parents:
1055
diff
changeset
|
136 |
4af4c74a4548
get avcC profile and level indication from sps (from handbrake)
bcoudurier
parents:
1055
diff
changeset
|
137 put_byte(pb, 1); /* version */ |
4af4c74a4548
get avcC profile and level indication from sps (from handbrake)
bcoudurier
parents:
1055
diff
changeset
|
138 put_byte(pb, sps[1]); /* profile */ |
4af4c74a4548
get avcC profile and level indication from sps (from handbrake)
bcoudurier
parents:
1055
diff
changeset
|
139 put_byte(pb, sps[2]); /* profile compat */ |
4af4c74a4548
get avcC profile and level indication from sps (from handbrake)
bcoudurier
parents:
1055
diff
changeset
|
140 put_byte(pb, sps[3]); /* level */ |
4af4c74a4548
get avcC profile and level indication from sps (from handbrake)
bcoudurier
parents:
1055
diff
changeset
|
141 put_byte(pb, 0xff); /* 6 bits reserved (111111) + 2 bits nal size length - 1 (11) */ |
4af4c74a4548
get avcC profile and level indication from sps (from handbrake)
bcoudurier
parents:
1055
diff
changeset
|
142 put_byte(pb, 0xe1); /* 3 bits reserved (111) + 5 bits number of sps (00001) */ |
4af4c74a4548
get avcC profile and level indication from sps (from handbrake)
bcoudurier
parents:
1055
diff
changeset
|
143 |
1006
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
144 put_be16(pb, sps_size); |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
145 put_buffer(pb, sps, sps_size); |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
146 put_byte(pb, 1); /* number of pps */ |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
147 put_be16(pb, pps_size); |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
148 put_buffer(pb, pps, pps_size); |
3049 | 149 av_free(start); |
1006
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
150 } else { |
2921 | 151 put_buffer(pb, data, len); |
1006
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
152 } |
15bfc3c063dc
do nal reformating when muxing H264, create avcc atom
bcoudurier
parents:
1000
diff
changeset
|
153 } |
2921 | 154 return 0; |
155 } |