GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/libavfilter/dnn/dnn_backend_native_layer_pad.c Lines: 118 156 75.6 %
Date: 2020-08-14 10:39:37 Branches: 53 82 64.6 %

Line Branch Exec Source
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"
23
#include "dnn_backend_native_layer_pad.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
30
static int before_get_buddy(int given, int paddings, LayerPadModeParam mode)
53
{
54
30
    if (mode == LPMP_SYMMETRIC) {
55
29
        return (2 * paddings - 1 - given);
56
1
    } else if (mode == LPMP_REFLECT) {
57
1
        return (2 * paddings - given);
58
    } else {
59
        av_assert0(!"should not reach here");
60
        return 0;
61
    }
62
}
63
64
23
static int after_get_buddy(int given, int border, LayerPadModeParam mode)
65
{
66
23
    if (mode == LPMP_SYMMETRIC) {
67
21
        int offset = given - border;
68
21
        return (border - 1 - offset);
69
2
    } else if (mode == LPMP_REFLECT) {
70
2
        int offset = given - border;
71
2
        return (border - 2 - offset);
72
    } else {
73
        av_assert0(!"should not reach here");
74
        return 0;
75
    }
76
}
77
78
3
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
3
    const LayerPadParams *params = (const LayerPadParams *)parameters;
85
86
    // suppose format is <N, H, W, C>
87
3
    int32_t input_operand_index = input_operand_indexes[0];
88
3
    int number = operands[input_operand_index].dims[0];
89
3
    int height = operands[input_operand_index].dims[1];
90
3
    int width = operands[input_operand_index].dims[2];
91
3
    int channel = operands[input_operand_index].dims[3];
92
3
    const float *input = operands[input_operand_index].data;
93
94
3
    int new_number = number + params->paddings[0][0] + params->paddings[0][1];
95
3
    int new_height = height + params->paddings[1][0] + params->paddings[1][1];
96
3
    int new_width = width + params->paddings[2][0] + params->paddings[2][1];
97
3
    int new_channel = channel + params->paddings[3][0] + params->paddings[3][1];
98
99
3
    int c_stride = channel;
100
3
    int wc_stride = c_stride * width;
101
3
    int hwc_stride = wc_stride * height;
102
103
3
    int new_c_stride = new_channel;
104
3
    int new_wc_stride = new_c_stride * new_width;
105
3
    int new_hwc_stride = new_wc_stride * new_height;
106
107
3
    DnnOperand *output_operand = &operands[output_operand_index];
108
3
    output_operand->dims[0] = new_number;
109
3
    output_operand->dims[1] = new_height;
110
3
    output_operand->dims[2] = new_width;
111
3
    output_operand->dims[3] = new_channel;
112
3
    output_operand->data_type = operands[input_operand_index].data_type;
113
3
    output_operand->length = calculate_operand_data_length(output_operand);
114
3
    if (output_operand->length <= 0)
115
        return -1;
116
3
    output_operand->data = av_realloc(output_operand->data, output_operand->length);
117
3
    if (!output_operand->data)
118
        return -1;
119
3
    output = output_operand->data;
120
121
    // copy the original data
122
8
    for (int n = 0; n < number; n++) {
123
17
        for (int h = 0; h < height; h++) {
124
44
            for (int w = 0; w < width; w++) {
125
32
                const float *src = input + n * hwc_stride + h * wc_stride + w * c_stride;
126
32
                float *dst = output + (n + params->paddings[0][0]) * new_hwc_stride
127
32
                                    + (h + params->paddings[1][0]) * new_wc_stride
128
32
                                    + (w + params->paddings[2][0]) * new_c_stride
129
32
                                    + params->paddings[3][0];
130
32
                memcpy(dst, src, channel * sizeof(float));
131
            }
132
        }
133
    }
134
135
    // handle the first dimension
136
3
    before_paddings = params->paddings[0][0];
137
3
    after_paddings = params->paddings[0][1];
138
4
    for (int n = 0; n < before_paddings; n++) {
139
1
        float *dst = output + n * new_hwc_stride;
140
1
        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
1
            int buddy = before_get_buddy(n, before_paddings, params->mode);
147
1
            float *src = output + buddy * new_hwc_stride;
148
1
            memcpy(dst, src, new_hwc_stride * sizeof(float));
149
        }
150
    }
151
5
    for (int n = 0; n < after_paddings; n++) {
152
2
        int given = number + before_paddings + n;
153
2
        float *dst = output + given * new_hwc_stride;
154
2
        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
2
            int buddy = after_get_buddy(given, number + before_paddings, params->mode);
160
2
            float *src = output + buddy * new_hwc_stride;
161
2
            memcpy(dst, src, new_hwc_stride * sizeof(float));
162
        }
163
    }
164
165
    // handle the second dimension
166
3
    before_paddings = params->paddings[1][0];
167
3
    after_paddings = params->paddings[1][1];
168
11
    for (int n = 0; n < new_number; n++) {
169
8
        float *start = output + n * new_hwc_stride;
170
11
        for (int h = 0; h < before_paddings; h++) {
171
3
            float *dst = start + h * new_wc_stride;
172
3
            if (params->mode == LPMP_CONSTANT) {
173
13
                for (int i = 0; i < new_wc_stride; i++) {
174
12
                    dst[i] = params->constant_values;
175
                }
176
            } else {
177
2
                int buddy = before_get_buddy(h, before_paddings, params->mode);
178
2
                float *src = start + buddy * new_wc_stride;
179
2
                memcpy(dst, src, new_wc_stride * sizeof(float));
180
            }
181
        }
182
11
        for (int h = 0; h < after_paddings; h++) {
183
3
            int given = height + before_paddings + h;
184
3
            float *dst = start + given * new_wc_stride;
185
3
            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
3
                int buddy = after_get_buddy(given, height + before_paddings, params->mode);
191
3
                float *src = start + buddy * new_wc_stride;
192
3
                memcpy(dst, src, new_wc_stride * sizeof(float));
193
            }
194
        }
195
    }
196
197
    // handle the third dimension
198
3
    before_paddings = params->paddings[2][0];
199
3
    after_paddings = params->paddings[2][1];
200
11
    for (int n = 0; n < new_number; n++) {
201
32
        for (int h = 0; h < new_height; h++) {
202
24
            float *start = output + n * new_hwc_stride + h * new_wc_stride;
203
51
            for (int w = 0; w < before_paddings; w++) {
204
27
                float *dst = start + w * new_c_stride;
205
27
                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
27
                    int buddy = before_get_buddy(w, before_paddings, params->mode);
211
27
                    float *src = start + buddy * new_c_stride;
212
27
                    memcpy(dst, src, new_c_stride * sizeof(float));
213
                }
214
            }
215
42
            for (int w = 0; w < after_paddings; w++) {
216
18
                int given = width + before_paddings + w;
217
18
                float *dst = start + given * new_c_stride;
218
18
                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
18
                    int buddy = after_get_buddy(given, width + before_paddings, params->mode);
224
18
                    float *src = start + buddy * new_c_stride;
225
18
                    memcpy(dst, src, new_c_stride * sizeof(float));
226
                }
227
            }
228
        }
229
    }
230
231
    // handle the fourth dimension
232
3
    before_paddings = params->paddings[3][0];
233
3
    after_paddings = params->paddings[3][1];
234
11
    for (int n = 0; n < new_number; n++) {
235
32
        for (int h = 0; h < new_height; h++) {
236
135
            for (int w = 0; w < new_width; w++) {
237
111
                float *start = output + n * new_hwc_stride + h * new_wc_stride + w * new_c_stride;
238
117
                for (int c = 0; c < before_paddings; c++) {
239
6
                    float *dst = start + c;
240
6
                    if (params->mode == LPMP_CONSTANT) {
241
6
                        *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
123
                for (int c = 0; c < after_paddings; c++) {
249
12
                    int given = channel + before_paddings + c;
250
12
                    float *dst = start + given;
251
12
                    if (params->mode == LPMP_CONSTANT) {
252
12
                        *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
3
    return 0;
264
}