• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2018, Alliance for Open Media. All rights reserved
3  *
4  * This source code is subject to the terms of the BSD 2 Clause License and
5  * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6  * was not distributed with this source code in the LICENSE file, you can
7  * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8  * Media Patent License 1.0 was not distributed with this source code in the
9  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10  */
11 #include <assert.h>
12 
13 #include "av1/common/obu_util.h"
14 
15 #include "aom_dsp/bitreader_buffer.h"
16 
read_obu_size(const uint8_t * data,size_t bytes_available,size_t * const obu_size,size_t * const length_field_size)17 static aom_codec_err_t read_obu_size(const uint8_t *data,
18                                      size_t bytes_available,
19                                      size_t *const obu_size,
20                                      size_t *const length_field_size) {
21   uint64_t u_obu_size = 0;
22   if (aom_uleb_decode(data, bytes_available, &u_obu_size, length_field_size) !=
23       0) {
24     return AOM_CODEC_CORRUPT_FRAME;
25   }
26 
27   if (u_obu_size > UINT32_MAX) return AOM_CODEC_CORRUPT_FRAME;
28   *obu_size = (size_t)u_obu_size;
29   return AOM_CODEC_OK;
30 }
31 
32 // Parses OBU header and stores values in 'header'.
read_obu_header(struct aom_read_bit_buffer * rb,int is_annexb,ObuHeader * header)33 static aom_codec_err_t read_obu_header(struct aom_read_bit_buffer *rb,
34                                        int is_annexb, ObuHeader *header) {
35   if (!rb || !header) return AOM_CODEC_INVALID_PARAM;
36 
37   const ptrdiff_t bit_buffer_byte_length = rb->bit_buffer_end - rb->bit_buffer;
38   if (bit_buffer_byte_length < 1) return AOM_CODEC_CORRUPT_FRAME;
39 
40   header->size = 1;
41 
42   if (aom_rb_read_bit(rb) != 0) {
43     // Forbidden bit. Must not be set.
44     return AOM_CODEC_CORRUPT_FRAME;
45   }
46 
47   header->type = (OBU_TYPE)aom_rb_read_literal(rb, 4);
48   header->has_extension = aom_rb_read_bit(rb);
49   header->has_size_field = aom_rb_read_bit(rb);
50 
51   if (!header->has_size_field && !is_annexb) {
52     // section 5 obu streams must have obu_size field set.
53     return AOM_CODEC_UNSUP_BITSTREAM;
54   }
55 
56   // obu_reserved_1bit must be set to 0. The value is ignored by a decoder.
57   aom_rb_read_bit(rb);
58 
59   if (header->has_extension) {
60     if (bit_buffer_byte_length == 1) return AOM_CODEC_CORRUPT_FRAME;
61 
62     header->size += 1;
63     header->temporal_layer_id = aom_rb_read_literal(rb, 3);
64     header->spatial_layer_id = aom_rb_read_literal(rb, 2);
65     // extension_header_reserved_3bits must be set to 0. The value is ignored by
66     // a decoder.
67     aom_rb_read_literal(rb, 3);
68   } else {
69     header->temporal_layer_id = 0;
70     header->spatial_layer_id = 0;
71   }
72 
73   return AOM_CODEC_OK;
74 }
75 
aom_read_obu_header(uint8_t * buffer,size_t buffer_length,size_t * consumed,ObuHeader * header,int is_annexb)76 aom_codec_err_t aom_read_obu_header(uint8_t *buffer, size_t buffer_length,
77                                     size_t *consumed, ObuHeader *header,
78                                     int is_annexb) {
79   if (buffer_length < 1 || !consumed || !header) return AOM_CODEC_INVALID_PARAM;
80 
81   // TODO(tomfinegan): Set the error handler here and throughout this file, and
82   // confirm parsing work done via aom_read_bit_buffer is successful.
83   struct aom_read_bit_buffer rb = { buffer, buffer + buffer_length, 0, NULL,
84                                     NULL };
85   aom_codec_err_t parse_result = read_obu_header(&rb, is_annexb, header);
86   if (parse_result == AOM_CODEC_OK) *consumed = header->size;
87   return parse_result;
88 }
89 
aom_read_obu_header_and_size(const uint8_t * data,size_t bytes_available,int is_annexb,ObuHeader * obu_header,size_t * const payload_size,size_t * const bytes_read)90 aom_codec_err_t aom_read_obu_header_and_size(const uint8_t *data,
91                                              size_t bytes_available,
92                                              int is_annexb,
93                                              ObuHeader *obu_header,
94                                              size_t *const payload_size,
95                                              size_t *const bytes_read) {
96   size_t length_field_size_obu = 0;
97   size_t length_field_size_payload = 0;
98   size_t obu_size = 0;
99   aom_codec_err_t status;
100 
101   if (is_annexb) {
102     // Size field comes before the OBU header, and includes the OBU header
103     status =
104         read_obu_size(data, bytes_available, &obu_size, &length_field_size_obu);
105 
106     if (status != AOM_CODEC_OK) return status;
107   }
108 
109   struct aom_read_bit_buffer rb = { data + length_field_size_obu,
110                                     data + bytes_available, 0, NULL, NULL };
111 
112   status = read_obu_header(&rb, is_annexb, obu_header);
113   if (status != AOM_CODEC_OK) return status;
114 
115   if (!obu_header->has_size_field) {
116     assert(is_annexb);
117     // Derive the payload size from the data we've already read
118     if (obu_size < obu_header->size) return AOM_CODEC_CORRUPT_FRAME;
119 
120     *payload_size = obu_size - obu_header->size;
121   } else {
122     // Size field comes after the OBU header, and is just the payload size
123     status = read_obu_size(
124         data + length_field_size_obu + obu_header->size,
125         bytes_available - length_field_size_obu - obu_header->size,
126         payload_size, &length_field_size_payload);
127     if (status != AOM_CODEC_OK) return status;
128   }
129 
130   *bytes_read =
131       length_field_size_obu + obu_header->size + length_field_size_payload;
132   return AOM_CODEC_OK;
133 }
134