Commit | Line | Data |
---|---|---|
18f1706f MT |
1 | /* |
2 | * This file is part of Libav. | |
3 | * | |
4 | * Libav is free software; you can redistribute it and/or | |
5 | * modify it under the terms of the GNU Lesser General Public | |
6 | * License as published by the Free Software Foundation; either | |
7 | * version 2.1 of the License, or (at your option) any later version. | |
8 | * | |
9 | * Libav is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
12 | * Lesser General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU Lesser General Public | |
15 | * License along with Libav; if not, write to the Free Software | |
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
17 | */ | |
18 | ||
19 | #include <string.h> | |
20 | ||
21 | #include "config.h" | |
22 | ||
23 | #include "libavutil/avassert.h" | |
24 | #include "libavutil/common.h" | |
25 | ||
26 | #include "cbs.h" | |
27 | #include "cbs_internal.h" | |
28 | ||
29 | ||
30 | static const CodedBitstreamType *cbs_type_table[] = { | |
acf06f45 MT |
31 | #if CONFIG_CBS_H264 |
32 | &ff_cbs_type_h264, | |
33 | #endif | |
18f1706f MT |
34 | }; |
35 | ||
36 | int ff_cbs_init(CodedBitstreamContext *ctx, | |
37 | enum AVCodecID codec_id, void *log_ctx) | |
38 | { | |
39 | const CodedBitstreamType *type; | |
40 | int i; | |
41 | ||
42 | type = NULL; | |
43 | for (i = 0; i < FF_ARRAY_ELEMS(cbs_type_table); i++) { | |
44 | if (cbs_type_table[i]->codec_id == codec_id) { | |
45 | type = cbs_type_table[i]; | |
46 | break; | |
47 | } | |
48 | } | |
49 | if (!type) | |
50 | return AVERROR(EINVAL); | |
51 | ||
52 | ctx->log_ctx = log_ctx; | |
53 | ctx->codec = type; | |
54 | ||
55 | ctx->priv_data = av_mallocz(ctx->codec->priv_data_size); | |
56 | if (!ctx->priv_data) | |
57 | return AVERROR(ENOMEM); | |
58 | ||
59 | ctx->decompose_unit_types = NULL; | |
60 | ||
61 | ctx->trace_enable = 0; | |
62 | ctx->trace_level = AV_LOG_TRACE; | |
63 | ||
64 | return 0; | |
65 | } | |
66 | ||
67 | void ff_cbs_close(CodedBitstreamContext *ctx) | |
68 | { | |
69 | if (ctx->codec && ctx->codec->close) | |
70 | ctx->codec->close(ctx); | |
71 | ||
72 | av_freep(&ctx->priv_data); | |
73 | } | |
74 | ||
75 | static void cbs_unit_uninit(CodedBitstreamContext *ctx, | |
76 | CodedBitstreamUnit *unit) | |
77 | { | |
78 | if (ctx->codec->free_unit && unit->content && !unit->content_external) | |
79 | ctx->codec->free_unit(unit); | |
80 | ||
81 | av_freep(&unit->data); | |
82 | unit->data_size = 0; | |
83 | unit->data_bit_padding = 0; | |
84 | } | |
85 | ||
86 | void ff_cbs_fragment_uninit(CodedBitstreamContext *ctx, | |
87 | CodedBitstreamFragment *frag) | |
88 | { | |
89 | int i; | |
90 | ||
91 | for (i = 0; i < frag->nb_units; i++) | |
92 | cbs_unit_uninit(ctx, &frag->units[i]); | |
93 | av_freep(&frag->units); | |
94 | frag->nb_units = 0; | |
95 | ||
96 | av_freep(&frag->data); | |
97 | frag->data_size = 0; | |
98 | frag->data_bit_padding = 0; | |
99 | } | |
100 | ||
101 | static int cbs_read_fragment_content(CodedBitstreamContext *ctx, | |
102 | CodedBitstreamFragment *frag) | |
103 | { | |
104 | int err, i, j; | |
105 | ||
106 | for (i = 0; i < frag->nb_units; i++) { | |
107 | if (ctx->decompose_unit_types) { | |
108 | for (j = 0; j < ctx->nb_decompose_unit_types; j++) { | |
109 | if (ctx->decompose_unit_types[j] == frag->units[i].type) | |
110 | break; | |
111 | } | |
112 | if (j >= ctx->nb_decompose_unit_types) | |
113 | continue; | |
114 | } | |
115 | ||
116 | err = ctx->codec->read_unit(ctx, &frag->units[i]); | |
117 | if (err == AVERROR(ENOSYS)) { | |
118 | av_log(ctx->log_ctx, AV_LOG_WARNING, | |
119 | "Decomposition unimplemented for unit %d " | |
120 | "(type %d).\n", i, frag->units[i].type); | |
121 | } else if (err < 0) { | |
122 | av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to read unit %d " | |
123 | "(type %d).\n", i, frag->units[i].type); | |
124 | return err; | |
125 | } | |
126 | } | |
127 | ||
128 | return 0; | |
129 | } | |
130 | ||
131 | int ff_cbs_read_extradata(CodedBitstreamContext *ctx, | |
132 | CodedBitstreamFragment *frag, | |
133 | const AVCodecParameters *par) | |
134 | { | |
135 | int err; | |
136 | ||
137 | memset(frag, 0, sizeof(*frag)); | |
138 | ||
139 | frag->data = par->extradata; | |
140 | frag->data_size = par->extradata_size; | |
141 | ||
142 | err = ctx->codec->split_fragment(ctx, frag, 1); | |
143 | if (err < 0) | |
144 | return err; | |
145 | ||
146 | frag->data = NULL; | |
147 | frag->data_size = 0; | |
148 | ||
149 | return cbs_read_fragment_content(ctx, frag); | |
150 | } | |
151 | ||
152 | int ff_cbs_read_packet(CodedBitstreamContext *ctx, | |
153 | CodedBitstreamFragment *frag, | |
154 | const AVPacket *pkt) | |
155 | { | |
156 | int err; | |
157 | ||
158 | memset(frag, 0, sizeof(*frag)); | |
159 | ||
160 | frag->data = pkt->data; | |
161 | frag->data_size = pkt->size; | |
162 | ||
163 | err = ctx->codec->split_fragment(ctx, frag, 0); | |
164 | if (err < 0) | |
165 | return err; | |
166 | ||
167 | frag->data = NULL; | |
168 | frag->data_size = 0; | |
169 | ||
170 | return cbs_read_fragment_content(ctx, frag); | |
171 | } | |
172 | ||
173 | int ff_cbs_read(CodedBitstreamContext *ctx, | |
174 | CodedBitstreamFragment *frag, | |
175 | const uint8_t *data, size_t size) | |
176 | { | |
177 | int err; | |
178 | ||
179 | memset(frag, 0, sizeof(*frag)); | |
180 | ||
181 | // (We won't write to this during split.) | |
182 | frag->data = (uint8_t*)data; | |
183 | frag->data_size = size; | |
184 | ||
185 | err = ctx->codec->split_fragment(ctx, frag, 0); | |
186 | if (err < 0) | |
187 | return err; | |
188 | ||
189 | frag->data = NULL; | |
190 | frag->data_size = 0; | |
191 | ||
192 | return cbs_read_fragment_content(ctx, frag); | |
193 | } | |
194 | ||
195 | ||
196 | int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx, | |
197 | CodedBitstreamFragment *frag) | |
198 | { | |
199 | int err, i; | |
200 | ||
201 | for (i = 0; i < frag->nb_units; i++) { | |
202 | if (!frag->units[i].content) | |
203 | continue; | |
204 | ||
205 | err = ctx->codec->write_unit(ctx, &frag->units[i]); | |
206 | if (err < 0) { | |
207 | av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to write unit %d " | |
208 | "(type %d).\n", i, frag->units[i].type); | |
209 | return err; | |
210 | } | |
211 | } | |
212 | ||
213 | err = ctx->codec->assemble_fragment(ctx, frag); | |
214 | if (err < 0) { | |
215 | av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to assemble fragment.\n"); | |
216 | return err; | |
217 | } | |
218 | ||
219 | return 0; | |
220 | } | |
221 | ||
222 | int ff_cbs_write_extradata(CodedBitstreamContext *ctx, | |
223 | AVCodecParameters *par, | |
224 | CodedBitstreamFragment *frag) | |
225 | { | |
226 | int err; | |
227 | ||
228 | err = ff_cbs_write_fragment_data(ctx, frag); | |
229 | if (err < 0) | |
230 | return err; | |
231 | ||
232 | av_freep(&par->extradata); | |
233 | ||
234 | par->extradata = av_malloc(frag->data_size + | |
235 | AV_INPUT_BUFFER_PADDING_SIZE); | |
236 | if (!par->extradata) | |
237 | return AVERROR(ENOMEM); | |
238 | ||
239 | memcpy(par->extradata, frag->data, frag->data_size); | |
240 | memset(par->extradata + frag->data_size, 0, | |
241 | AV_INPUT_BUFFER_PADDING_SIZE); | |
242 | par->extradata_size = frag->data_size; | |
243 | ||
244 | return 0; | |
245 | } | |
246 | ||
247 | int ff_cbs_write_packet(CodedBitstreamContext *ctx, | |
248 | AVPacket *pkt, | |
249 | CodedBitstreamFragment *frag) | |
250 | { | |
251 | int err; | |
252 | ||
253 | err = ff_cbs_write_fragment_data(ctx, frag); | |
254 | if (err < 0) | |
255 | return err; | |
256 | ||
257 | av_new_packet(pkt, frag->data_size); | |
258 | if (err < 0) | |
259 | return err; | |
260 | ||
261 | memcpy(pkt->data, frag->data, frag->data_size); | |
262 | pkt->size = frag->data_size; | |
263 | ||
264 | return 0; | |
265 | } | |
266 | ||
267 | ||
268 | void ff_cbs_trace_header(CodedBitstreamContext *ctx, | |
269 | const char *name) | |
270 | { | |
271 | if (!ctx->trace_enable) | |
272 | return; | |
273 | ||
274 | av_log(ctx->log_ctx, ctx->trace_level, "%s\n", name); | |
275 | } | |
276 | ||
277 | void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, int position, | |
278 | const char *name, const char *bits, | |
279 | int64_t value) | |
280 | { | |
281 | size_t name_len, bits_len; | |
282 | int pad; | |
283 | ||
284 | if (!ctx->trace_enable) | |
285 | return; | |
286 | ||
287 | av_assert0(value >= INT_MIN && value <= UINT32_MAX); | |
288 | ||
289 | name_len = strlen(name); | |
290 | bits_len = strlen(bits); | |
291 | ||
292 | if (name_len + bits_len > 60) | |
293 | pad = bits_len + 2; | |
294 | else | |
295 | pad = 61 - name_len; | |
296 | ||
297 | av_log(ctx->log_ctx, ctx->trace_level, "%-10d %s%*s = %"PRId64"\n", | |
298 | position, name, pad, bits, value); | |
299 | } | |
300 | ||
301 | int ff_cbs_read_unsigned(CodedBitstreamContext *ctx, BitstreamContext *bc, | |
302 | int width, const char *name, uint32_t *write_to, | |
303 | uint32_t range_min, uint32_t range_max) | |
304 | { | |
305 | uint32_t value; | |
306 | int position; | |
307 | ||
308 | av_assert0(width <= 32); | |
309 | ||
310 | if (ctx->trace_enable) | |
311 | position = bitstream_tell(bc); | |
312 | ||
313 | value = bitstream_read(bc, width); | |
314 | ||
315 | if (ctx->trace_enable) { | |
316 | char bits[33]; | |
317 | int i; | |
318 | for (i = 0; i < width; i++) | |
319 | bits[i] = value >> (width - i - 1) & 1 ? '1' : '0'; | |
320 | bits[i] = 0; | |
321 | ||
322 | ff_cbs_trace_syntax_element(ctx, position, name, bits, value); | |
323 | } | |
324 | ||
325 | if (value < range_min || value > range_max) { | |
326 | av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " | |
327 | "%"PRIu32", but must be in [%"PRIu32",%"PRIu32"].\n", | |
328 | name, value, range_min, range_max); | |
329 | return AVERROR_INVALIDDATA; | |
330 | } | |
331 | ||
332 | *write_to = value; | |
333 | return 0; | |
334 | } | |
335 | ||
336 | int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc, | |
337 | int width, const char *name, uint32_t value, | |
338 | uint32_t range_min, uint32_t range_max) | |
339 | { | |
340 | av_assert0(width <= 32); | |
341 | ||
342 | if (value < range_min || value > range_max) { | |
343 | av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " | |
344 | "%"PRIu32", but must be in [%"PRIu32",%"PRIu32"].\n", | |
345 | name, value, range_min, range_max); | |
346 | return AVERROR_INVALIDDATA; | |
347 | } | |
348 | ||
349 | if (put_bits_left(pbc) < width) | |
350 | return AVERROR(ENOSPC); | |
351 | ||
352 | if (ctx->trace_enable) { | |
353 | char bits[33]; | |
354 | int i; | |
355 | for (i = 0; i < width; i++) | |
356 | bits[i] = value >> (width - i - 1) & 1 ? '1' : '0'; | |
357 | bits[i] = 0; | |
358 | ||
359 | ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), name, bits, value); | |
360 | } | |
361 | ||
362 | if (width < 32) | |
363 | put_bits(pbc, width, value); | |
364 | else | |
365 | put_bits32(pbc, value); | |
366 | ||
367 | return 0; | |
368 | } | |
369 | ||
370 | ||
371 | static int cbs_insert_unit(CodedBitstreamContext *ctx, | |
372 | CodedBitstreamFragment *frag, | |
373 | int position) | |
374 | { | |
375 | CodedBitstreamUnit *units; | |
376 | ||
377 | units = av_malloc_array(frag->nb_units + 1, sizeof(*units)); | |
378 | if (!units) | |
379 | return AVERROR(ENOMEM); | |
380 | ||
381 | if (position > 0) | |
382 | memcpy(units, frag->units, position * sizeof(*units)); | |
383 | if (position < frag->nb_units) | |
384 | memcpy(units + position + 1, frag->units + position, | |
385 | (frag->nb_units - position) * sizeof(*units)); | |
386 | ||
387 | memset(units + position, 0, sizeof(*units)); | |
388 | ||
389 | av_freep(&frag->units); | |
390 | frag->units = units; | |
391 | ++frag->nb_units; | |
392 | ||
393 | return 0; | |
394 | } | |
395 | ||
396 | int ff_cbs_insert_unit_content(CodedBitstreamContext *ctx, | |
397 | CodedBitstreamFragment *frag, | |
398 | int position, uint32_t type, | |
399 | void *content) | |
400 | { | |
401 | int err; | |
402 | ||
403 | if (position == -1) | |
404 | position = frag->nb_units; | |
405 | av_assert0(position >= 0 && position <= frag->nb_units); | |
406 | ||
407 | err = cbs_insert_unit(ctx, frag, position); | |
408 | if (err < 0) | |
409 | return err; | |
410 | ||
411 | frag->units[position].type = type; | |
412 | frag->units[position].content = content; | |
413 | frag->units[position].content_external = 1; | |
414 | ||
415 | return 0; | |
416 | } | |
417 | ||
418 | int ff_cbs_insert_unit_data(CodedBitstreamContext *ctx, | |
419 | CodedBitstreamFragment *frag, | |
420 | int position, uint32_t type, | |
421 | uint8_t *data, size_t data_size) | |
422 | { | |
423 | int err; | |
424 | ||
425 | if (position == -1) | |
426 | position = frag->nb_units; | |
427 | av_assert0(position >= 0 && position <= frag->nb_units); | |
428 | ||
429 | err = cbs_insert_unit(ctx, frag, position); | |
430 | if (err < 0) | |
431 | return err; | |
432 | ||
433 | frag->units[position].type = type; | |
434 | frag->units[position].data = data; | |
435 | frag->units[position].data_size = data_size; | |
436 | ||
437 | return 0; | |
438 | } | |
439 | ||
440 | int ff_cbs_delete_unit(CodedBitstreamContext *ctx, | |
441 | CodedBitstreamFragment *frag, | |
442 | int position) | |
443 | { | |
444 | if (position < 0 || position >= frag->nb_units) | |
445 | return AVERROR(EINVAL); | |
446 | ||
447 | cbs_unit_uninit(ctx, &frag->units[position]); | |
448 | ||
449 | --frag->nb_units; | |
450 | ||
451 | if (frag->nb_units == 0) { | |
452 | av_freep(&frag->units); | |
453 | ||
454 | } else { | |
455 | memmove(frag->units + position, | |
456 | frag->units + position + 1, | |
457 | (frag->nb_units - position) * sizeof(*frag->units)); | |
458 | ||
459 | // Don't bother reallocating the unit array. | |
460 | } | |
461 | ||
462 | return 0; | |
463 | } |