FFmpeg
dnn_backend_native_layer_pad.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019 Guo Yejun
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include <string.h>
22 #include "libavutil/avassert.h"
24 
25 int dnn_load_layer_pad(Layer *layer, AVIOContext *model_file_context, int file_size, int operands_num)
26 {
27  LayerPadParams *params;
28  int dnn_size = 0;
29  params = av_malloc(sizeof(*params));
30  if (!params)
31  return 0;
32 
33  params->mode = (int32_t)avio_rl32(model_file_context);
34  dnn_size += 4;
35  for (int i = 0; i < 4; ++i) {
36  params->paddings[i][0] = avio_rl32(model_file_context);
37  params->paddings[i][1] = avio_rl32(model_file_context);
38  dnn_size += 8;
39  }
40  layer->input_operand_indexes[0] = (int32_t)avio_rl32(model_file_context);
41  layer->output_operand_index = (int32_t)avio_rl32(model_file_context);
42  dnn_size += 8;
43  layer->params = params;
44 
45  if (layer->input_operand_indexes[0] >= operands_num || layer->output_operand_index >= operands_num) {
46  return 0;
47  }
48 
49  return dnn_size;
50 }
51 
52 static int before_get_buddy(int given, int paddings, LayerPadModeParam mode)
53 {
54  if (mode == LPMP_SYMMETRIC) {
55  return (2 * paddings - 1 - given);
56  } else if (mode == LPMP_REFLECT) {
57  return (2 * paddings - given);
58  } else {
59  av_assert0(!"should not reach here");
60  return 0;
61  }
62 }
63 
64 static int after_get_buddy(int given, int border, LayerPadModeParam mode)
65 {
66  if (mode == LPMP_SYMMETRIC) {
67  int offset = given - border;
68  return (border - 1 - offset);
69  } else if (mode == LPMP_REFLECT) {
70  int offset = given - border;
71  return (border - 2 - offset);
72  } else {
73  av_assert0(!"should not reach here");
74  return 0;
75  }
76 }
77 
78 int dnn_execute_layer_pad(DnnOperand *operands, const int32_t *input_operand_indexes,
79  int32_t output_operand_index, const void *parameters)
80 {
81  int32_t before_paddings;
82  int32_t after_paddings;
83  float* output;
84  const LayerPadParams *params = (const LayerPadParams *)parameters;
85 
86  // suppose format is <N, H, W, C>
87  int32_t input_operand_index = input_operand_indexes[0];
88  int number = operands[input_operand_index].dims[0];
89  int height = operands[input_operand_index].dims[1];
90  int width = operands[input_operand_index].dims[2];
91  int channel = operands[input_operand_index].dims[3];
92  const float *input = operands[input_operand_index].data;
93 
94  int new_number = number + params->paddings[0][0] + params->paddings[0][1];
95  int new_height = height + params->paddings[1][0] + params->paddings[1][1];
96  int new_width = width + params->paddings[2][0] + params->paddings[2][1];
97  int new_channel = channel + params->paddings[3][0] + params->paddings[3][1];
98 
99  int c_stride = channel;
100  int wc_stride = c_stride * width;
101  int hwc_stride = wc_stride * height;
102 
103  int new_c_stride = new_channel;
104  int new_wc_stride = new_c_stride * new_width;
105  int new_hwc_stride = new_wc_stride * new_height;
106 
107  DnnOperand *output_operand = &operands[output_operand_index];
108  output_operand->dims[0] = new_number;
109  output_operand->dims[1] = new_height;
110  output_operand->dims[2] = new_width;
111  output_operand->dims[3] = new_channel;
112  output_operand->data_type = operands[input_operand_index].data_type;
113  output_operand->length = calculate_operand_data_length(output_operand);
114  if (output_operand->length <= 0)
115  return -1;
116  output_operand->data = av_realloc(output_operand->data, output_operand->length);
117  if (!output_operand->data)
118  return -1;
119  output = output_operand->data;
120 
121  // copy the original data
122  for (int n = 0; n < number; n++) {
123  for (int h = 0; h < height; h++) {
124  for (int w = 0; w < width; w++) {
125  const float *src = input + n * hwc_stride + h * wc_stride + w * c_stride;
126  float *dst = output + (n + params->paddings[0][0]) * new_hwc_stride
127  + (h + params->paddings[1][0]) * new_wc_stride
128  + (w + params->paddings[2][0]) * new_c_stride
129  + params->paddings[3][0];
130  memcpy(dst, src, channel * sizeof(float));
131  }
132  }
133  }
134 
135  // handle the first dimension
136  before_paddings = params->paddings[0][0];
137  after_paddings = params->paddings[0][1];
138  for (int n = 0; n < before_paddings; n++) {
139  float *dst = output + n * new_hwc_stride;
140  if (params->mode == LPMP_CONSTANT) {
141  for (int i = 0; i < new_hwc_stride; i++) {
142  dst[i] = params->constant_values;
143  }
144  }
145  else {
146  int buddy = before_get_buddy(n, before_paddings, params->mode);
147  float *src = output + buddy * new_hwc_stride;
148  memcpy(dst, src, new_hwc_stride * sizeof(float));
149  }
150  }
151  for (int n = 0; n < after_paddings; n++) {
152  int given = number + before_paddings + n;
153  float *dst = output + given * new_hwc_stride;
154  if (params->mode == LPMP_CONSTANT) {
155  for (int i = 0; i < new_hwc_stride; i++) {
156  dst[i] = params->constant_values;
157  }
158  } else {
159  int buddy = after_get_buddy(given, number + before_paddings, params->mode);
160  float *src = output + buddy * new_hwc_stride;
161  memcpy(dst, src, new_hwc_stride * sizeof(float));
162  }
163  }
164 
165  // handle the second dimension
166  before_paddings = params->paddings[1][0];
167  after_paddings = params->paddings[1][1];
168  for (int n = 0; n < new_number; n++) {
169  float *start = output + n * new_hwc_stride;
170  for (int h = 0; h < before_paddings; h++) {
171  float *dst = start + h * new_wc_stride;
172  if (params->mode == LPMP_CONSTANT) {
173  for (int i = 0; i < new_wc_stride; i++) {
174  dst[i] = params->constant_values;
175  }
176  } else {
177  int buddy = before_get_buddy(h, before_paddings, params->mode);
178  float *src = start + buddy * new_wc_stride;
179  memcpy(dst, src, new_wc_stride * sizeof(float));
180  }
181  }
182  for (int h = 0; h < after_paddings; h++) {
183  int given = height + before_paddings + h;
184  float *dst = start + given * new_wc_stride;
185  if (params->mode == LPMP_CONSTANT) {
186  for (int i = 0; i < new_wc_stride; i++) {
187  dst[i] = params->constant_values;
188  }
189  } else {
190  int buddy = after_get_buddy(given, height + before_paddings, params->mode);
191  float *src = start + buddy * new_wc_stride;
192  memcpy(dst, src, new_wc_stride * sizeof(float));
193  }
194  }
195  }
196 
197  // handle the third dimension
198  before_paddings = params->paddings[2][0];
199  after_paddings = params->paddings[2][1];
200  for (int n = 0; n < new_number; n++) {
201  for (int h = 0; h < new_height; h++) {
202  float *start = output + n * new_hwc_stride + h * new_wc_stride;
203  for (int w = 0; w < before_paddings; w++) {
204  float *dst = start + w * new_c_stride;
205  if (params->mode == LPMP_CONSTANT) {
206  for (int i = 0; i < new_c_stride; i++) {
207  dst[i] = params->constant_values;
208  }
209  } else {
210  int buddy = before_get_buddy(w, before_paddings, params->mode);
211  float *src = start + buddy * new_c_stride;
212  memcpy(dst, src, new_c_stride * sizeof(float));
213  }
214  }
215  for (int w = 0; w < after_paddings; w++) {
216  int given = width + before_paddings + w;
217  float *dst = start + given * new_c_stride;
218  if (params->mode == LPMP_CONSTANT) {
219  for (int i = 0; i < new_c_stride; i++) {
220  dst[i] = params->constant_values;
221  }
222  } else {
223  int buddy = after_get_buddy(given, width + before_paddings, params->mode);
224  float *src = start + buddy * new_c_stride;
225  memcpy(dst, src, new_c_stride * sizeof(float));
226  }
227  }
228  }
229  }
230 
231  // handle the fourth dimension
232  before_paddings = params->paddings[3][0];
233  after_paddings = params->paddings[3][1];
234  for (int n = 0; n < new_number; n++) {
235  for (int h = 0; h < new_height; h++) {
236  for (int w = 0; w < new_width; w++) {
237  float *start = output + n * new_hwc_stride + h * new_wc_stride + w * new_c_stride;
238  for (int c = 0; c < before_paddings; c++) {
239  float *dst = start + c;
240  if (params->mode == LPMP_CONSTANT) {
241  *dst = params->constant_values;
242  } else {
243  int buddy = before_get_buddy(c, before_paddings, params->mode);
244  float *src = start + buddy;
245  *dst = *src;
246  }
247  }
248  for (int c = 0; c < after_paddings; c++) {
249  int given = channel + before_paddings + c;
250  float *dst = start + given;
251  if (params->mode == LPMP_CONSTANT) {
252  *dst = params->constant_values;
253  } else {
254  int buddy = after_get_buddy(given, channel + before_paddings, params->mode);
255  float *src = start + buddy;
256  *dst = *src;
257  }
258  }
259  }
260  }
261  }
262 
263  return 0;
264 }
calculate_operand_data_length
int32_t calculate_operand_data_length(const DnnOperand *oprd)
Definition: dnn_backend_native.c:297
before_get_buddy
static int before_get_buddy(int given, int paddings, LayerPadModeParam mode)
Definition: dnn_backend_native_layer_pad.c:52
dnn_load_layer_pad
int dnn_load_layer_pad(Layer *layer, AVIOContext *model_file_context, int file_size, int operands_num)
Definition: dnn_backend_native_layer_pad.c:25
output
filter_frame For filters that do not use the this method is called when a frame is pushed to the filter s input It can be called at any time except in a reentrant way If the input frame is enough to produce output
Definition: filter_design.txt:225
w
uint8_t w
Definition: llviddspenc.c:38
LayerPadModeParam
LayerPadModeParam
Definition: dnn_backend_native_layer_pad.h:31
LPMP_REFLECT
@ LPMP_REFLECT
Definition: dnn_backend_native_layer_pad.h:31
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:31
dnn_backend_native_layer_pad.h
avassert.h
LayerPadParams::mode
LayerPadModeParam mode
Definition: dnn_backend_native_layer_pad.h:35
width
#define width
DnnOperand::data
void * data
data pointer with data length in bytes.
Definition: dnn_backend_native.h:98
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
DnnOperand::data_type
DNNDataType data_type
support different kinds of data type such as float, half float, int8 etc, first support float now.
Definition: dnn_backend_native.h:79
LayerPadParams
Definition: dnn_backend_native_layer_pad.h:33
int32_t
int32_t
Definition: audio_convert.c:194
dnn_execute_layer_pad
int dnn_execute_layer_pad(DnnOperand *operands, const int32_t *input_operand_indexes, int32_t output_operand_index, const void *parameters)
Definition: dnn_backend_native_layer_pad.c:78
Layer::params
void * params
Definition: dnn_backend_native.h:60
DnnOperand::dims
int32_t dims[4]
there are two memory layouts, NHWC or NCHW, so we use dims, dims[0] is Number.
Definition: dnn_backend_native.h:68
src
#define src
Definition: vp8dsp.c:254
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
LPMP_SYMMETRIC
@ LPMP_SYMMETRIC
Definition: dnn_backend_native_layer_pad.h:31
DnnOperand::length
int32_t length
Definition: dnn_backend_native.h:99
avio_rl32
unsigned int avio_rl32(AVIOContext *s)
Definition: aviobuf.c:747
AVIOContext
Bytestream IO Context.
Definition: avio.h:161
Layer::output_operand_index
int32_t output_operand_index
Definition: dnn_backend_native.h:59
LPMP_CONSTANT
@ LPMP_CONSTANT
Definition: dnn_backend_native_layer_pad.h:31
Layer
Definition: dnn_backend_native.h:51
Layer::input_operand_indexes
int32_t input_operand_indexes[4]
a layer can have multiple inputs and one output.
Definition: dnn_backend_native.h:58
height
#define height
offset
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf offset
Definition: writing_filters.txt:86
input
and forward the test the status of outputs and forward it to the corresponding return FFERROR_NOT_READY If the filters stores internally one or a few frame for some input
Definition: filter_design.txt:172
av_realloc
void * av_realloc(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory.
Definition: mem.c:134
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
LayerPadParams::paddings
int32_t paddings[4][2]
Definition: dnn_backend_native_layer_pad.h:34
DnnOperand
Definition: dnn_backend_native.h:63
mode
mode
Definition: ebur128.h:83
after_get_buddy
static int after_get_buddy(int given, int border, LayerPadModeParam mode)
Definition: dnn_backend_native_layer_pad.c:64
LayerPadParams::constant_values
float constant_values
Definition: dnn_backend_native_layer_pad.h:36
h
h
Definition: vp9dsp_template.c:2038
channel
channel
Definition: ebur128.h:39