blob: 163d0f59ceb5c4f20e8f1fe99795310132e44d8e
1 | /* |
2 | * H.264 MP4 to Annex B byte stream format filter |
3 | * Copyright (c) 2007 Benoit Fouet <benoit.fouet@free.fr> |
4 | * |
5 | * This file is part of FFmpeg. |
6 | * |
7 | * FFmpeg is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU Lesser General Public |
9 | * License as published by the Free Software Foundation; either |
10 | * version 2.1 of the License, or (at your option) any later version. |
11 | * |
12 | * FFmpeg is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | * Lesser General Public License for more details. |
16 | * |
17 | * You should have received a copy of the GNU Lesser General Public |
18 | * License along with FFmpeg; if not, write to the Free Software |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | */ |
21 | |
22 | #include <string.h> |
23 | |
24 | #include "libavutil/intreadwrite.h" |
25 | #include "libavutil/mem.h" |
26 | |
27 | #include "avcodec.h" |
28 | #include "bsf.h" |
29 | |
30 | typedef struct H264BSFContext { |
31 | int32_t sps_offset; |
32 | int32_t pps_offset; |
33 | uint8_t length_size; |
34 | uint8_t new_idr; |
35 | uint8_t idr_sps_seen; |
36 | uint8_t idr_pps_seen; |
37 | int extradata_parsed; |
38 | } H264BSFContext; |
39 | |
40 | static int alloc_and_copy(AVPacket *out, |
41 | const uint8_t *sps_pps, uint32_t sps_pps_size, |
42 | const uint8_t *in, uint32_t in_size) |
43 | { |
44 | uint32_t offset = out->size; |
45 | uint8_t nal_header_size = offset ? 3 : 4; |
46 | int err; |
47 | |
48 | err = av_grow_packet(out, sps_pps_size + in_size + nal_header_size); |
49 | if (err < 0) |
50 | return err; |
51 | |
52 | if (sps_pps) |
53 | memcpy(out->data + offset, sps_pps, sps_pps_size); |
54 | memcpy(out->data + sps_pps_size + nal_header_size + offset, in, in_size); |
55 | if (!offset) { |
56 | AV_WB32(out->data + sps_pps_size, 1); |
57 | } else { |
58 | (out->data + offset + sps_pps_size)[0] = |
59 | (out->data + offset + sps_pps_size)[1] = 0; |
60 | (out->data + offset + sps_pps_size)[2] = 1; |
61 | } |
62 | |
63 | return 0; |
64 | } |
65 | |
66 | static int h264_extradata_to_annexb(AVBSFContext *ctx, const int padding) |
67 | { |
68 | H264BSFContext *s = ctx->priv_data; |
69 | uint16_t unit_size; |
70 | uint64_t total_size = 0; |
71 | uint8_t *out = NULL, unit_nb, sps_done = 0, |
72 | sps_seen = 0, pps_seen = 0; |
73 | const uint8_t *extradata = ctx->par_in->extradata + 4; |
74 | static const uint8_t nalu_header[4] = { 0, 0, 0, 1 }; |
75 | int length_size = (*extradata++ & 0x3) + 1; // retrieve length coded size |
76 | |
77 | s->sps_offset = s->pps_offset = -1; |
78 | |
79 | /* retrieve sps and pps unit(s) */ |
80 | unit_nb = *extradata++ & 0x1f; /* number of sps unit(s) */ |
81 | if (!unit_nb) { |
82 | goto pps; |
83 | } else { |
84 | s->sps_offset = 0; |
85 | sps_seen = 1; |
86 | } |
87 | |
88 | while (unit_nb--) { |
89 | int err; |
90 | |
91 | unit_size = AV_RB16(extradata); |
92 | total_size += unit_size + 4; |
93 | if (total_size > INT_MAX - padding) { |
94 | av_log(ctx, AV_LOG_ERROR, |
95 | "Too big extradata size, corrupted stream or invalid MP4/AVCC bitstream\n"); |
96 | av_free(out); |
97 | return AVERROR(EINVAL); |
98 | } |
99 | if (extradata + 2 + unit_size > ctx->par_in->extradata + ctx->par_in->extradata_size) { |
100 | av_log(ctx, AV_LOG_ERROR, "Packet header is not contained in global extradata, " |
101 | "corrupted stream or invalid MP4/AVCC bitstream\n"); |
102 | av_free(out); |
103 | return AVERROR(EINVAL); |
104 | } |
105 | if ((err = av_reallocp(&out, total_size + padding)) < 0) |
106 | return err; |
107 | memcpy(out + total_size - unit_size - 4, nalu_header, 4); |
108 | memcpy(out + total_size - unit_size, extradata + 2, unit_size); |
109 | extradata += 2 + unit_size; |
110 | pps: |
111 | if (!unit_nb && !sps_done++) { |
112 | unit_nb = *extradata++; /* number of pps unit(s) */ |
113 | if (unit_nb) { |
114 | s->pps_offset = total_size; |
115 | pps_seen = 1; |
116 | } |
117 | } |
118 | } |
119 | |
120 | if (out) |
121 | memset(out + total_size, 0, padding); |
122 | |
123 | if (!sps_seen) |
124 | av_log(ctx, AV_LOG_WARNING, |
125 | "Warning: SPS NALU missing or invalid. " |
126 | "The resulting stream may not play.\n"); |
127 | |
128 | if (!pps_seen) |
129 | av_log(ctx, AV_LOG_WARNING, |
130 | "Warning: PPS NALU missing or invalid. " |
131 | "The resulting stream may not play.\n"); |
132 | |
133 | av_freep(&ctx->par_out->extradata); |
134 | ctx->par_out->extradata = out; |
135 | ctx->par_out->extradata_size = total_size; |
136 | |
137 | return length_size; |
138 | } |
139 | |
140 | static int h264_mp4toannexb_init(AVBSFContext *ctx) |
141 | { |
142 | H264BSFContext *s = ctx->priv_data; |
143 | int extra_size = ctx->par_in->extradata_size; |
144 | int ret; |
145 | |
146 | /* retrieve sps and pps NAL units from extradata */ |
147 | if (!extra_size || |
148 | (extra_size >= 3 && AV_RB24(ctx->par_in->extradata) == 1) || |
149 | (extra_size >= 4 && AV_RB32(ctx->par_in->extradata) == 1)) { |
150 | av_log(ctx, AV_LOG_VERBOSE, |
151 | "The input looks like it is Annex B already\n"); |
152 | } else if (extra_size >= 6) { |
153 | ret = h264_extradata_to_annexb(ctx, AV_INPUT_BUFFER_PADDING_SIZE); |
154 | if (ret < 0) |
155 | return ret; |
156 | |
157 | s->length_size = ret; |
158 | s->new_idr = 1; |
159 | s->idr_sps_seen = 0; |
160 | s->idr_pps_seen = 0; |
161 | s->extradata_parsed = 1; |
162 | } else { |
163 | av_log(ctx, AV_LOG_ERROR, "Invalid extradata size: %d\n", extra_size); |
164 | return AVERROR_INVALIDDATA; |
165 | } |
166 | |
167 | return 0; |
168 | } |
169 | |
170 | static int h264_mp4toannexb_filter(AVBSFContext *ctx, AVPacket *out) |
171 | { |
172 | H264BSFContext *s = ctx->priv_data; |
173 | |
174 | AVPacket *in; |
175 | uint8_t unit_type; |
176 | int32_t nal_size; |
177 | uint32_t cumul_size = 0; |
178 | const uint8_t *buf; |
179 | const uint8_t *buf_end; |
180 | int buf_size; |
181 | int ret = 0, i; |
182 | |
183 | ret = ff_bsf_get_packet(ctx, &in); |
184 | if (ret < 0) |
185 | return ret; |
186 | |
187 | /* nothing to filter */ |
188 | if (!s->extradata_parsed) { |
189 | av_packet_move_ref(out, in); |
190 | av_packet_free(&in); |
191 | return 0; |
192 | } |
193 | |
194 | buf = in->data; |
195 | buf_size = in->size; |
196 | buf_end = in->data + in->size; |
197 | |
198 | do { |
199 | ret= AVERROR(EINVAL); |
200 | if (buf + s->length_size > buf_end) |
201 | goto fail; |
202 | |
203 | for (nal_size = 0, i = 0; i<s->length_size; i++) |
204 | nal_size = (nal_size << 8) | buf[i]; |
205 | |
206 | buf += s->length_size; |
207 | unit_type = *buf & 0x1f; |
208 | |
209 | if (nal_size > buf_end - buf || nal_size < 0) |
210 | goto fail; |
211 | |
212 | if (unit_type == 7) |
213 | s->idr_sps_seen = s->new_idr = 1; |
214 | else if (unit_type == 8) { |
215 | s->idr_pps_seen = s->new_idr = 1; |
216 | /* if SPS has not been seen yet, prepend the AVCC one to PPS */ |
217 | if (!s->idr_sps_seen) { |
218 | if (s->sps_offset == -1) |
219 | av_log(ctx, AV_LOG_WARNING, "SPS not present in the stream, nor in AVCC, stream may be unreadable\n"); |
220 | else { |
221 | if ((ret = alloc_and_copy(out, |
222 | ctx->par_out->extradata + s->sps_offset, |
223 | s->pps_offset != -1 ? s->pps_offset : ctx->par_out->extradata_size - s->sps_offset, |
224 | buf, nal_size)) < 0) |
225 | goto fail; |
226 | s->idr_sps_seen = 1; |
227 | goto next_nal; |
228 | } |
229 | } |
230 | } |
231 | |
232 | /* if this is a new IDR picture following an IDR picture, reset the idr flag. |
233 | * Just check first_mb_in_slice to be 0 as this is the simplest solution. |
234 | * This could be checking idr_pic_id instead, but would complexify the parsing. */ |
235 | if (!s->new_idr && unit_type == 5 && (buf[1] & 0x80)) |
236 | s->new_idr = 1; |
237 | |
238 | /* prepend only to the first type 5 NAL unit of an IDR picture, if no sps/pps are already present */ |
239 | if (s->new_idr && unit_type == 5 && !s->idr_sps_seen && !s->idr_pps_seen) { |
240 | if ((ret=alloc_and_copy(out, |
241 | ctx->par_out->extradata, ctx->par_out->extradata_size, |
242 | buf, nal_size)) < 0) |
243 | goto fail; |
244 | s->new_idr = 0; |
245 | /* if only SPS has been seen, also insert PPS */ |
246 | } else if (s->new_idr && unit_type == 5 && s->idr_sps_seen && !s->idr_pps_seen) { |
247 | if (s->pps_offset == -1) { |
248 | av_log(ctx, AV_LOG_WARNING, "PPS not present in the stream, nor in AVCC, stream may be unreadable\n"); |
249 | if ((ret = alloc_and_copy(out, NULL, 0, buf, nal_size)) < 0) |
250 | goto fail; |
251 | } else if ((ret = alloc_and_copy(out, |
252 | ctx->par_out->extradata + s->pps_offset, ctx->par_out->extradata_size - s->pps_offset, |
253 | buf, nal_size)) < 0) |
254 | goto fail; |
255 | } else { |
256 | if ((ret=alloc_and_copy(out, NULL, 0, buf, nal_size)) < 0) |
257 | goto fail; |
258 | if (!s->new_idr && unit_type == 1) { |
259 | s->new_idr = 1; |
260 | s->idr_sps_seen = 0; |
261 | s->idr_pps_seen = 0; |
262 | } |
263 | } |
264 | |
265 | next_nal: |
266 | buf += nal_size; |
267 | cumul_size += nal_size + s->length_size; |
268 | } while (cumul_size < buf_size); |
269 | |
270 | ret = av_packet_copy_props(out, in); |
271 | if (ret < 0) |
272 | goto fail; |
273 | |
274 | fail: |
275 | if (ret < 0) |
276 | av_packet_unref(out); |
277 | av_packet_free(&in); |
278 | |
279 | return ret; |
280 | } |
281 | |
282 | static const enum AVCodecID codec_ids[] = { |
283 | AV_CODEC_ID_H264, AV_CODEC_ID_NONE, |
284 | }; |
285 | |
286 | const AVBitStreamFilter ff_h264_mp4toannexb_bsf = { |
287 | .name = "h264_mp4toannexb", |
288 | .priv_data_size = sizeof(H264BSFContext), |
289 | .init = h264_mp4toannexb_init, |
290 | .filter = h264_mp4toannexb_filter, |
291 | .codec_ids = codec_ids, |
292 | }; |
293 |