• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * This file is part of FFmpeg.
3  *
4  * FFmpeg 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  * FFmpeg 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 FFmpeg; 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/buffer.h"
25 #include "libavutil/common.h"
26 
27 #include "cbs.h"
28 #include "cbs_internal.h"
29 
30 
31 static const CodedBitstreamType *cbs_type_table[] = {
32 #if CONFIG_CBS_AV1
33     &ff_cbs_type_av1,
34 #endif
35 #if CONFIG_CBS_H264
36     &ff_cbs_type_h264,
37 #endif
38 #if CONFIG_CBS_H265
39     &ff_cbs_type_h265,
40 #endif
41 #if CONFIG_CBS_JPEG
42     &ff_cbs_type_jpeg,
43 #endif
44 #if CONFIG_CBS_MPEG2
45     &ff_cbs_type_mpeg2,
46 #endif
47 #if CONFIG_CBS_VP9
48     &ff_cbs_type_vp9,
49 #endif
50 };
51 
52 const enum AVCodecID ff_cbs_all_codec_ids[] = {
53 #if CONFIG_CBS_AV1
54     AV_CODEC_ID_AV1,
55 #endif
56 #if CONFIG_CBS_H264
57     AV_CODEC_ID_H264,
58 #endif
59 #if CONFIG_CBS_H265
60     AV_CODEC_ID_H265,
61 #endif
62 #if CONFIG_CBS_JPEG
63     AV_CODEC_ID_MJPEG,
64 #endif
65 #if CONFIG_CBS_MPEG2
66     AV_CODEC_ID_MPEG2VIDEO,
67 #endif
68 #if CONFIG_CBS_VP9
69     AV_CODEC_ID_VP9,
70 #endif
71     AV_CODEC_ID_NONE
72 };
73 
ff_cbs_init(CodedBitstreamContext ** ctx_ptr,enum AVCodecID codec_id,void * log_ctx)74 int ff_cbs_init(CodedBitstreamContext **ctx_ptr,
75                 enum AVCodecID codec_id, void *log_ctx)
76 {
77     CodedBitstreamContext *ctx;
78     const CodedBitstreamType *type;
79     int i;
80 
81     type = NULL;
82     for (i = 0; i < FF_ARRAY_ELEMS(cbs_type_table); i++) {
83         if (cbs_type_table[i]->codec_id == codec_id) {
84             type = cbs_type_table[i];
85             break;
86         }
87     }
88     if (!type)
89         return AVERROR(EINVAL);
90 
91     ctx = av_mallocz(sizeof(*ctx));
92     if (!ctx)
93         return AVERROR(ENOMEM);
94 
95     ctx->log_ctx = log_ctx;
96     ctx->codec   = type;
97 
98     if (type->priv_data_size) {
99         ctx->priv_data = av_mallocz(ctx->codec->priv_data_size);
100         if (!ctx->priv_data) {
101             av_freep(&ctx);
102             return AVERROR(ENOMEM);
103         }
104     }
105 
106     ctx->decompose_unit_types = NULL;
107 
108     ctx->trace_enable = 0;
109     ctx->trace_level  = AV_LOG_TRACE;
110 
111     *ctx_ptr = ctx;
112     return 0;
113 }
114 
ff_cbs_close(CodedBitstreamContext ** ctx_ptr)115 void ff_cbs_close(CodedBitstreamContext **ctx_ptr)
116 {
117     CodedBitstreamContext *ctx = *ctx_ptr;
118 
119     if (!ctx)
120         return;
121 
122     if (ctx->codec && ctx->codec->close)
123         ctx->codec->close(ctx);
124 
125     av_freep(&ctx->write_buffer);
126     av_freep(&ctx->priv_data);
127     av_freep(ctx_ptr);
128 }
129 
cbs_unit_uninit(CodedBitstreamContext * ctx,CodedBitstreamUnit * unit)130 static void cbs_unit_uninit(CodedBitstreamContext *ctx,
131                             CodedBitstreamUnit *unit)
132 {
133     av_buffer_unref(&unit->content_ref);
134     unit->content = NULL;
135 
136     av_buffer_unref(&unit->data_ref);
137     unit->data             = NULL;
138     unit->data_size        = 0;
139     unit->data_bit_padding = 0;
140 }
141 
ff_cbs_fragment_reset(CodedBitstreamContext * ctx,CodedBitstreamFragment * frag)142 void ff_cbs_fragment_reset(CodedBitstreamContext *ctx,
143                            CodedBitstreamFragment *frag)
144 {
145     int i;
146 
147     for (i = 0; i < frag->nb_units; i++)
148         cbs_unit_uninit(ctx, &frag->units[i]);
149     frag->nb_units = 0;
150 
151     av_buffer_unref(&frag->data_ref);
152     frag->data             = NULL;
153     frag->data_size        = 0;
154     frag->data_bit_padding = 0;
155 }
156 
ff_cbs_fragment_free(CodedBitstreamContext * ctx,CodedBitstreamFragment * frag)157 void ff_cbs_fragment_free(CodedBitstreamContext *ctx,
158                           CodedBitstreamFragment *frag)
159 {
160     ff_cbs_fragment_reset(ctx, frag);
161 
162     av_freep(&frag->units);
163     frag->nb_units_allocated = 0;
164 }
165 
cbs_read_fragment_content(CodedBitstreamContext * ctx,CodedBitstreamFragment * frag)166 static int cbs_read_fragment_content(CodedBitstreamContext *ctx,
167                                      CodedBitstreamFragment *frag)
168 {
169     int err, i, j;
170 
171     for (i = 0; i < frag->nb_units; i++) {
172         CodedBitstreamUnit *unit = &frag->units[i];
173 
174         if (ctx->decompose_unit_types) {
175             for (j = 0; j < ctx->nb_decompose_unit_types; j++) {
176                 if (ctx->decompose_unit_types[j] == unit->type)
177                     break;
178             }
179             if (j >= ctx->nb_decompose_unit_types)
180                 continue;
181         }
182 
183         av_buffer_unref(&unit->content_ref);
184         unit->content = NULL;
185 
186         av_assert0(unit->data && unit->data_ref);
187 
188         err = ctx->codec->read_unit(ctx, unit);
189         if (err == AVERROR(ENOSYS)) {
190             av_log(ctx->log_ctx, AV_LOG_VERBOSE,
191                    "Decomposition unimplemented for unit %d "
192                    "(type %"PRIu32").\n", i, unit->type);
193         } else if (err < 0) {
194             av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to read unit %d "
195                    "(type %"PRIu32").\n", i, unit->type);
196             return err;
197         }
198     }
199 
200     return 0;
201 }
202 
cbs_fill_fragment_data(CodedBitstreamContext * ctx,CodedBitstreamFragment * frag,const uint8_t * data,size_t size)203 static int cbs_fill_fragment_data(CodedBitstreamContext *ctx,
204                                   CodedBitstreamFragment *frag,
205                                   const uint8_t *data, size_t size)
206 {
207     av_assert0(!frag->data && !frag->data_ref);
208 
209     frag->data_ref =
210         av_buffer_alloc(size + AV_INPUT_BUFFER_PADDING_SIZE);
211     if (!frag->data_ref)
212         return AVERROR(ENOMEM);
213 
214     frag->data      = frag->data_ref->data;
215     frag->data_size = size;
216 
217     memcpy(frag->data, data, size);
218     memset(frag->data + size, 0,
219            AV_INPUT_BUFFER_PADDING_SIZE);
220 
221     return 0;
222 }
223 
ff_cbs_read_extradata(CodedBitstreamContext * ctx,CodedBitstreamFragment * frag,const AVCodecParameters * par)224 int ff_cbs_read_extradata(CodedBitstreamContext *ctx,
225                           CodedBitstreamFragment *frag,
226                           const AVCodecParameters *par)
227 {
228     int err;
229 
230     err = cbs_fill_fragment_data(ctx, frag, par->extradata,
231                                  par->extradata_size);
232     if (err < 0)
233         return err;
234 
235     err = ctx->codec->split_fragment(ctx, frag, 1);
236     if (err < 0)
237         return err;
238 
239     return cbs_read_fragment_content(ctx, frag);
240 }
241 
ff_cbs_read_packet(CodedBitstreamContext * ctx,CodedBitstreamFragment * frag,const AVPacket * pkt)242 int ff_cbs_read_packet(CodedBitstreamContext *ctx,
243                        CodedBitstreamFragment *frag,
244                        const AVPacket *pkt)
245 {
246     int err;
247 
248     if (pkt->buf) {
249         frag->data_ref = av_buffer_ref(pkt->buf);
250         if (!frag->data_ref)
251             return AVERROR(ENOMEM);
252 
253         frag->data      = pkt->data;
254         frag->data_size = pkt->size;
255 
256     } else {
257         err = cbs_fill_fragment_data(ctx, frag, pkt->data, pkt->size);
258         if (err < 0)
259             return err;
260     }
261 
262     err = ctx->codec->split_fragment(ctx, frag, 0);
263     if (err < 0)
264         return err;
265 
266     return cbs_read_fragment_content(ctx, frag);
267 }
268 
ff_cbs_read(CodedBitstreamContext * ctx,CodedBitstreamFragment * frag,const uint8_t * data,size_t size)269 int ff_cbs_read(CodedBitstreamContext *ctx,
270                 CodedBitstreamFragment *frag,
271                 const uint8_t *data, size_t size)
272 {
273     int err;
274 
275     err = cbs_fill_fragment_data(ctx, frag, data, size);
276     if (err < 0)
277         return err;
278 
279     err = ctx->codec->split_fragment(ctx, frag, 0);
280     if (err < 0)
281         return err;
282 
283     return cbs_read_fragment_content(ctx, frag);
284 }
285 
cbs_write_unit_data(CodedBitstreamContext * ctx,CodedBitstreamUnit * unit)286 static int cbs_write_unit_data(CodedBitstreamContext *ctx,
287                                CodedBitstreamUnit *unit)
288 {
289     PutBitContext pbc;
290     int ret;
291 
292     if (!ctx->write_buffer) {
293         // Initial write buffer size is 1MB.
294         ctx->write_buffer_size = 1024 * 1024;
295 
296     reallocate_and_try_again:
297         ret = av_reallocp(&ctx->write_buffer, ctx->write_buffer_size);
298         if (ret < 0) {
299             av_log(ctx->log_ctx, AV_LOG_ERROR, "Unable to allocate a "
300                    "sufficiently large write buffer (last attempt "
301                    "%"SIZE_SPECIFIER" bytes).\n", ctx->write_buffer_size);
302             return ret;
303         }
304     }
305 
306     init_put_bits(&pbc, ctx->write_buffer, ctx->write_buffer_size);
307 
308     ret = ctx->codec->write_unit(ctx, unit, &pbc);
309     if (ret < 0) {
310         if (ret == AVERROR(ENOSPC)) {
311             // Overflow.
312             if (ctx->write_buffer_size == INT_MAX / 8)
313                 return AVERROR(ENOMEM);
314             ctx->write_buffer_size = FFMIN(2 * ctx->write_buffer_size, INT_MAX / 8);
315             goto reallocate_and_try_again;
316         }
317         // Write failed for some other reason.
318         return ret;
319     }
320 
321     // Overflow but we didn't notice.
322     av_assert0(put_bits_count(&pbc) <= 8 * ctx->write_buffer_size);
323 
324     if (put_bits_count(&pbc) % 8)
325         unit->data_bit_padding = 8 - put_bits_count(&pbc) % 8;
326     else
327         unit->data_bit_padding = 0;
328 
329     flush_put_bits(&pbc);
330 
331     ret = ff_cbs_alloc_unit_data(ctx, unit, put_bits_count(&pbc) / 8);
332     if (ret < 0)
333         return ret;
334 
335     memcpy(unit->data, ctx->write_buffer, unit->data_size);
336 
337     return 0;
338 }
339 
ff_cbs_write_fragment_data(CodedBitstreamContext * ctx,CodedBitstreamFragment * frag)340 int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx,
341                                CodedBitstreamFragment *frag)
342 {
343     int err, i;
344 
345     for (i = 0; i < frag->nb_units; i++) {
346         CodedBitstreamUnit *unit = &frag->units[i];
347 
348         if (!unit->content)
349             continue;
350 
351         av_buffer_unref(&unit->data_ref);
352         unit->data = NULL;
353 
354         err = cbs_write_unit_data(ctx, unit);
355         if (err < 0) {
356             av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to write unit %d "
357                    "(type %"PRIu32").\n", i, unit->type);
358             return err;
359         }
360         av_assert0(unit->data && unit->data_ref);
361     }
362 
363     av_buffer_unref(&frag->data_ref);
364     frag->data = NULL;
365 
366     err = ctx->codec->assemble_fragment(ctx, frag);
367     if (err < 0) {
368         av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to assemble fragment.\n");
369         return err;
370     }
371     av_assert0(frag->data && frag->data_ref);
372 
373     return 0;
374 }
375 
ff_cbs_write_extradata(CodedBitstreamContext * ctx,AVCodecParameters * par,CodedBitstreamFragment * frag)376 int ff_cbs_write_extradata(CodedBitstreamContext *ctx,
377                            AVCodecParameters *par,
378                            CodedBitstreamFragment *frag)
379 {
380     int err;
381 
382     err = ff_cbs_write_fragment_data(ctx, frag);
383     if (err < 0)
384         return err;
385 
386     av_freep(&par->extradata);
387 
388     par->extradata = av_malloc(frag->data_size +
389                                AV_INPUT_BUFFER_PADDING_SIZE);
390     if (!par->extradata)
391         return AVERROR(ENOMEM);
392 
393     memcpy(par->extradata, frag->data, frag->data_size);
394     memset(par->extradata + frag->data_size, 0,
395            AV_INPUT_BUFFER_PADDING_SIZE);
396     par->extradata_size = frag->data_size;
397 
398     return 0;
399 }
400 
ff_cbs_write_packet(CodedBitstreamContext * ctx,AVPacket * pkt,CodedBitstreamFragment * frag)401 int ff_cbs_write_packet(CodedBitstreamContext *ctx,
402                         AVPacket *pkt,
403                         CodedBitstreamFragment *frag)
404 {
405     AVBufferRef *buf;
406     int err;
407 
408     err = ff_cbs_write_fragment_data(ctx, frag);
409     if (err < 0)
410         return err;
411 
412     buf = av_buffer_ref(frag->data_ref);
413     if (!buf)
414         return AVERROR(ENOMEM);
415 
416     av_buffer_unref(&pkt->buf);
417 
418     pkt->buf  = buf;
419     pkt->data = frag->data;
420     pkt->size = frag->data_size;
421 
422     return 0;
423 }
424 
425 
ff_cbs_trace_header(CodedBitstreamContext * ctx,const char * name)426 void ff_cbs_trace_header(CodedBitstreamContext *ctx,
427                          const char *name)
428 {
429     if (!ctx->trace_enable)
430         return;
431 
432     av_log(ctx->log_ctx, ctx->trace_level, "%s\n", name);
433 }
434 
ff_cbs_trace_syntax_element(CodedBitstreamContext * ctx,int position,const char * str,const int * subscripts,const char * bits,int64_t value)435 void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, int position,
436                                  const char *str, const int *subscripts,
437                                  const char *bits, int64_t value)
438 {
439     char name[256];
440     size_t name_len, bits_len;
441     int pad, subs, i, j, k, n;
442 
443     if (!ctx->trace_enable)
444         return;
445 
446     av_assert0(value >= INT_MIN && value <= UINT32_MAX);
447 
448     subs = subscripts ? subscripts[0] : 0;
449     n = 0;
450     for (i = j = 0; str[i];) {
451         if (str[i] == '[') {
452             if (n < subs) {
453                 ++n;
454                 k = snprintf(name + j, sizeof(name) - j, "[%d", subscripts[n]);
455                 av_assert0(k > 0 && j + k < sizeof(name));
456                 j += k;
457                 for (++i; str[i] && str[i] != ']'; i++);
458                 av_assert0(str[i] == ']');
459             } else {
460                 while (str[i] && str[i] != ']')
461                     name[j++] = str[i++];
462                 av_assert0(str[i] == ']');
463             }
464         } else {
465             av_assert0(j + 1 < sizeof(name));
466             name[j++] = str[i++];
467         }
468     }
469     av_assert0(j + 1 < sizeof(name));
470     name[j] = 0;
471     av_assert0(n == subs);
472 
473     name_len = strlen(name);
474     bits_len = strlen(bits);
475 
476     if (name_len + bits_len > 60)
477         pad = bits_len + 2;
478     else
479         pad = 61 - name_len;
480 
481     av_log(ctx->log_ctx, ctx->trace_level, "%-10d  %s%*s = %"PRId64"\n",
482            position, name, pad, bits, value);
483 }
484 
ff_cbs_read_unsigned(CodedBitstreamContext * ctx,GetBitContext * gbc,int width,const char * name,const int * subscripts,uint32_t * write_to,uint32_t range_min,uint32_t range_max)485 int ff_cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc,
486                          int width, const char *name,
487                          const int *subscripts, uint32_t *write_to,
488                          uint32_t range_min, uint32_t range_max)
489 {
490     uint32_t value;
491     int position;
492 
493     av_assert0(width > 0 && width <= 32);
494 
495     if (get_bits_left(gbc) < width) {
496         av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid value at "
497                "%s: bitstream ended.\n", name);
498         return AVERROR_INVALIDDATA;
499     }
500 
501     if (ctx->trace_enable)
502         position = get_bits_count(gbc);
503 
504     value = get_bits_long(gbc, width);
505 
506     if (ctx->trace_enable) {
507         char bits[33];
508         int i;
509         for (i = 0; i < width; i++)
510             bits[i] = value >> (width - i - 1) & 1 ? '1' : '0';
511         bits[i] = 0;
512 
513         ff_cbs_trace_syntax_element(ctx, position, name, subscripts,
514                                     bits, value);
515     }
516 
517     if (value < range_min || value > range_max) {
518         av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
519                "%"PRIu32", but must be in [%"PRIu32",%"PRIu32"].\n",
520                name, value, range_min, range_max);
521         return AVERROR_INVALIDDATA;
522     }
523 
524     *write_to = value;
525     return 0;
526 }
527 
ff_cbs_write_unsigned(CodedBitstreamContext * ctx,PutBitContext * pbc,int width,const char * name,const int * subscripts,uint32_t value,uint32_t range_min,uint32_t range_max)528 int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc,
529                           int width, const char *name,
530                           const int *subscripts, uint32_t value,
531                           uint32_t range_min, uint32_t range_max)
532 {
533     av_assert0(width > 0 && width <= 32);
534 
535     if (value < range_min || value > range_max) {
536         av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
537                "%"PRIu32", but must be in [%"PRIu32",%"PRIu32"].\n",
538                name, value, range_min, range_max);
539         return AVERROR_INVALIDDATA;
540     }
541 
542     if (put_bits_left(pbc) < width)
543         return AVERROR(ENOSPC);
544 
545     if (ctx->trace_enable) {
546         char bits[33];
547         int i;
548         for (i = 0; i < width; i++)
549             bits[i] = value >> (width - i - 1) & 1 ? '1' : '0';
550         bits[i] = 0;
551 
552         ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
553                                     name, subscripts, bits, value);
554     }
555 
556     if (width < 32)
557         put_bits(pbc, width, value);
558     else
559         put_bits32(pbc, value);
560 
561     return 0;
562 }
563 
ff_cbs_read_signed(CodedBitstreamContext * ctx,GetBitContext * gbc,int width,const char * name,const int * subscripts,int32_t * write_to,int32_t range_min,int32_t range_max)564 int ff_cbs_read_signed(CodedBitstreamContext *ctx, GetBitContext *gbc,
565                        int width, const char *name,
566                        const int *subscripts, int32_t *write_to,
567                        int32_t range_min, int32_t range_max)
568 {
569     int32_t value;
570     int position;
571 
572     av_assert0(width > 0 && width <= 32);
573 
574     if (get_bits_left(gbc) < width) {
575         av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid value at "
576                "%s: bitstream ended.\n", name);
577         return AVERROR_INVALIDDATA;
578     }
579 
580     if (ctx->trace_enable)
581         position = get_bits_count(gbc);
582 
583     value = get_sbits_long(gbc, width);
584 
585     if (ctx->trace_enable) {
586         char bits[33];
587         int i;
588         for (i = 0; i < width; i++)
589             bits[i] = value & (1U << (width - i - 1)) ? '1' : '0';
590         bits[i] = 0;
591 
592         ff_cbs_trace_syntax_element(ctx, position, name, subscripts,
593                                     bits, value);
594     }
595 
596     if (value < range_min || value > range_max) {
597         av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
598                "%"PRId32", but must be in [%"PRId32",%"PRId32"].\n",
599                name, value, range_min, range_max);
600         return AVERROR_INVALIDDATA;
601     }
602 
603     *write_to = value;
604     return 0;
605 }
606 
ff_cbs_write_signed(CodedBitstreamContext * ctx,PutBitContext * pbc,int width,const char * name,const int * subscripts,int32_t value,int32_t range_min,int32_t range_max)607 int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc,
608                         int width, const char *name,
609                         const int *subscripts, int32_t value,
610                         int32_t range_min, int32_t range_max)
611 {
612     av_assert0(width > 0 && width <= 32);
613 
614     if (value < range_min || value > range_max) {
615         av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
616                "%"PRId32", but must be in [%"PRId32",%"PRId32"].\n",
617                name, value, range_min, range_max);
618         return AVERROR_INVALIDDATA;
619     }
620 
621     if (put_bits_left(pbc) < width)
622         return AVERROR(ENOSPC);
623 
624     if (ctx->trace_enable) {
625         char bits[33];
626         int i;
627         for (i = 0; i < width; i++)
628             bits[i] = value & (1U << (width - i - 1)) ? '1' : '0';
629         bits[i] = 0;
630 
631         ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
632                                     name, subscripts, bits, value);
633     }
634 
635     if (width < 32)
636         put_sbits(pbc, width, value);
637     else
638         put_bits32(pbc, value);
639 
640     return 0;
641 }
642 
643 
ff_cbs_alloc_unit_content(CodedBitstreamContext * ctx,CodedBitstreamUnit * unit,size_t size,void (* free)(void * opaque,uint8_t * data))644 int ff_cbs_alloc_unit_content(CodedBitstreamContext *ctx,
645                               CodedBitstreamUnit *unit,
646                               size_t size,
647                               void (*free)(void *opaque, uint8_t *data))
648 {
649     av_assert0(!unit->content && !unit->content_ref);
650 
651     unit->content = av_mallocz(size);
652     if (!unit->content)
653         return AVERROR(ENOMEM);
654 
655     unit->content_ref = av_buffer_create(unit->content, size,
656                                          free, NULL, 0);
657     if (!unit->content_ref) {
658         av_freep(&unit->content);
659         return AVERROR(ENOMEM);
660     }
661 
662     return 0;
663 }
664 
ff_cbs_alloc_unit_data(CodedBitstreamContext * ctx,CodedBitstreamUnit * unit,size_t size)665 int ff_cbs_alloc_unit_data(CodedBitstreamContext *ctx,
666                            CodedBitstreamUnit *unit,
667                            size_t size)
668 {
669     av_assert0(!unit->data && !unit->data_ref);
670 
671     unit->data_ref = av_buffer_alloc(size + AV_INPUT_BUFFER_PADDING_SIZE);
672     if (!unit->data_ref)
673         return AVERROR(ENOMEM);
674 
675     unit->data      = unit->data_ref->data;
676     unit->data_size = size;
677 
678     memset(unit->data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
679 
680     return 0;
681 }
682 
cbs_insert_unit(CodedBitstreamContext * ctx,CodedBitstreamFragment * frag,int position)683 static int cbs_insert_unit(CodedBitstreamContext *ctx,
684                            CodedBitstreamFragment *frag,
685                            int position)
686 {
687     CodedBitstreamUnit *units;
688 
689     if (frag->nb_units < frag->nb_units_allocated) {
690         units = frag->units;
691 
692         if (position < frag->nb_units)
693             memmove(units + position + 1, units + position,
694                     (frag->nb_units - position) * sizeof(*units));
695     } else {
696         units = av_malloc_array(frag->nb_units*2 + 1, sizeof(*units));
697         if (!units)
698             return AVERROR(ENOMEM);
699 
700         frag->nb_units_allocated = 2*frag->nb_units_allocated + 1;
701 
702         if (position > 0)
703             memcpy(units, frag->units, position * sizeof(*units));
704 
705         if (position < frag->nb_units)
706             memcpy(units + position + 1, frag->units + position,
707                    (frag->nb_units - position) * sizeof(*units));
708     }
709 
710     memset(units + position, 0, sizeof(*units));
711 
712     if (units != frag->units) {
713         av_free(frag->units);
714         frag->units = units;
715     }
716 
717     ++frag->nb_units;
718 
719     return 0;
720 }
721 
ff_cbs_insert_unit_content(CodedBitstreamContext * ctx,CodedBitstreamFragment * frag,int position,CodedBitstreamUnitType type,void * content,AVBufferRef * content_buf)722 int ff_cbs_insert_unit_content(CodedBitstreamContext *ctx,
723                                CodedBitstreamFragment *frag,
724                                int position,
725                                CodedBitstreamUnitType type,
726                                void *content,
727                                AVBufferRef *content_buf)
728 {
729     CodedBitstreamUnit *unit;
730     AVBufferRef *content_ref;
731     int err;
732 
733     if (position == -1)
734         position = frag->nb_units;
735     av_assert0(position >= 0 && position <= frag->nb_units);
736 
737     if (content_buf) {
738         content_ref = av_buffer_ref(content_buf);
739         if (!content_ref)
740             return AVERROR(ENOMEM);
741     } else {
742         content_ref = NULL;
743     }
744 
745     err = cbs_insert_unit(ctx, frag, position);
746     if (err < 0) {
747         av_buffer_unref(&content_ref);
748         return err;
749     }
750 
751     unit = &frag->units[position];
752     unit->type        = type;
753     unit->content     = content;
754     unit->content_ref = content_ref;
755 
756     return 0;
757 }
758 
ff_cbs_insert_unit_data(CodedBitstreamContext * ctx,CodedBitstreamFragment * frag,int position,CodedBitstreamUnitType type,uint8_t * data,size_t data_size,AVBufferRef * data_buf)759 int ff_cbs_insert_unit_data(CodedBitstreamContext *ctx,
760                             CodedBitstreamFragment *frag,
761                             int position,
762                             CodedBitstreamUnitType type,
763                             uint8_t *data, size_t data_size,
764                             AVBufferRef *data_buf)
765 {
766     CodedBitstreamUnit *unit;
767     AVBufferRef *data_ref;
768     int err;
769 
770     if (position == -1)
771         position = frag->nb_units;
772     av_assert0(position >= 0 && position <= frag->nb_units);
773 
774     if (data_buf)
775         data_ref = av_buffer_ref(data_buf);
776     else
777         data_ref = av_buffer_create(data, data_size, NULL, NULL, 0);
778     if (!data_ref) {
779         if (!data_buf)
780             av_free(data);
781         return AVERROR(ENOMEM);
782     }
783 
784     err = cbs_insert_unit(ctx, frag, position);
785     if (err < 0) {
786         av_buffer_unref(&data_ref);
787         return err;
788     }
789 
790     unit = &frag->units[position];
791     unit->type      = type;
792     unit->data      = data;
793     unit->data_size = data_size;
794     unit->data_ref  = data_ref;
795 
796     return 0;
797 }
798 
ff_cbs_delete_unit(CodedBitstreamContext * ctx,CodedBitstreamFragment * frag,int position)799 void ff_cbs_delete_unit(CodedBitstreamContext *ctx,
800                         CodedBitstreamFragment *frag,
801                         int position)
802 {
803     av_assert0(0 <= position && position < frag->nb_units
804                              && "Unit to be deleted not in fragment.");
805 
806     cbs_unit_uninit(ctx, &frag->units[position]);
807 
808     --frag->nb_units;
809 
810     if (frag->nb_units > 0)
811         memmove(frag->units + position,
812                 frag->units + position + 1,
813                 (frag->nb_units - position) * sizeof(*frag->units));
814 }
815