GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/libavfilter/dnn/dnn_backend_native_layer_pad.c Lines: 118 158 74.7 %
Date: 2020-10-23 17:01:47 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, NativeContext *ctx)
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
        av_log(ctx, AV_LOG_ERROR, "The output data length overflow\n");
116
        return DNN_ERROR;
117
    }
118
3
    output_operand->data = av_realloc(output_operand->data, output_operand->length);
119
3
    if (!output_operand->data) {
120
        av_log(ctx, AV_LOG_ERROR, "Failed to reallocate memory for output\n");
121
        return DNN_ERROR;
122
    }
123
3
    output = output_operand->data;
124
125
    // copy the original data
126
8
    for (int n = 0; n < number; n++) {
127
17
        for (int h = 0; h < height; h++) {
128
44
            for (int w = 0; w < width; w++) {
129
32
                const float *src = input + n * hwc_stride + h * wc_stride + w * c_stride;
130
32
                float *dst = output + (n + params->paddings[0][0]) * new_hwc_stride
131
32
                                    + (h + params->paddings[1][0]) * new_wc_stride
132
32
                                    + (w + params->paddings[2][0]) * new_c_stride
133
32
                                    + params->paddings[3][0];
134
32
                memcpy(dst, src, channel * sizeof(float));
135
            }
136
        }
137
    }
138
139
    // handle the first dimension
140
3
    before_paddings = params->paddings[0][0];
141
3
    after_paddings = params->paddings[0][1];
142
4
    for (int n = 0; n < before_paddings; n++) {
143
1
        float *dst = output + n * new_hwc_stride;
144
1
        if (params->mode == LPMP_CONSTANT) {
145
            for (int i = 0; i < new_hwc_stride; i++) {
146
                dst[i] = params->constant_values;
147
            }
148
        }
149
        else {
150
1
            int buddy = before_get_buddy(n, before_paddings, params->mode);
151
1
            float *src = output + buddy * new_hwc_stride;
152
1
            memcpy(dst, src, new_hwc_stride * sizeof(float));
153
        }
154
    }
155
5
    for (int n = 0; n < after_paddings; n++) {
156
2
        int given = number + before_paddings + n;
157
2
        float *dst = output + given * new_hwc_stride;
158
2
        if (params->mode == LPMP_CONSTANT) {
159
            for (int i = 0; i < new_hwc_stride; i++) {
160
                dst[i] = params->constant_values;
161
            }
162
        } else {
163
2
            int buddy = after_get_buddy(given, number + before_paddings, params->mode);
164
2
            float *src = output + buddy * new_hwc_stride;
165
2
            memcpy(dst, src, new_hwc_stride * sizeof(float));
166
        }
167
    }
168
169
    // handle the second dimension
170
3
    before_paddings = params->paddings[1][0];
171
3
    after_paddings = params->paddings[1][1];
172
11
    for (int n = 0; n < new_number; n++) {
173
8
        float *start = output + n * new_hwc_stride;
174
11
        for (int h = 0; h < before_paddings; h++) {
175
3
            float *dst = start + h * new_wc_stride;
176
3
            if (params->mode == LPMP_CONSTANT) {
177
13
                for (int i = 0; i < new_wc_stride; i++) {
178
12
                    dst[i] = params->constant_values;
179
                }
180
            } else {
181
2
                int buddy = before_get_buddy(h, before_paddings, params->mode);
182
2
                float *src = start + buddy * new_wc_stride;
183
2
                memcpy(dst, src, new_wc_stride * sizeof(float));
184
            }
185
        }
186
11
        for (int h = 0; h < after_paddings; h++) {
187
3
            int given = height + before_paddings + h;
188
3
            float *dst = start + given * new_wc_stride;
189
3
            if (params->mode == LPMP_CONSTANT) {
190
                for (int i = 0; i < new_wc_stride; i++) {
191
                    dst[i] = params->constant_values;
192
                }
193
            } else {
194
3
                int buddy = after_get_buddy(given, height + before_paddings, params->mode);
195
3
                float *src = start + buddy * new_wc_stride;
196
3
                memcpy(dst, src, new_wc_stride * sizeof(float));
197
            }
198
        }
199
    }
200
201
    // handle the third dimension
202
3
    before_paddings = params->paddings[2][0];
203
3
    after_paddings = params->paddings[2][1];
204
11
    for (int n = 0; n < new_number; n++) {
205
32
        for (int h = 0; h < new_height; h++) {
206
24
            float *start = output + n * new_hwc_stride + h * new_wc_stride;
207
51
            for (int w = 0; w < before_paddings; w++) {
208
27
                float *dst = start + w * new_c_stride;
209
27
                if (params->mode == LPMP_CONSTANT) {
210
                    for (int i = 0; i < new_c_stride; i++) {
211
                        dst[i] = params->constant_values;
212
                    }
213
                } else {
214
27
                    int buddy = before_get_buddy(w, before_paddings, params->mode);
215
27
                    float *src = start + buddy * new_c_stride;
216
27
                    memcpy(dst, src, new_c_stride * sizeof(float));
217
                }
218
            }
219
42
            for (int w = 0; w < after_paddings; w++) {
220
18
                int given = width + before_paddings + w;
221
18
                float *dst = start + given * new_c_stride;
222
18
                if (params->mode == LPMP_CONSTANT) {
223
                    for (int i = 0; i < new_c_stride; i++) {
224
                        dst[i] = params->constant_values;
225
                    }
226
                } else {
227
18
                    int buddy = after_get_buddy(given, width + before_paddings, params->mode);
228
18
                    float *src = start + buddy * new_c_stride;
229
18
                    memcpy(dst, src, new_c_stride * sizeof(float));
230
                }
231
            }
232
        }
233
    }
234
235
    // handle the fourth dimension
236
3
    before_paddings = params->paddings[3][0];
237
3
    after_paddings = params->paddings[3][1];
238
11
    for (int n = 0; n < new_number; n++) {
239
32
        for (int h = 0; h < new_height; h++) {
240
135
            for (int w = 0; w < new_width; w++) {
241
111
                float *start = output + n * new_hwc_stride + h * new_wc_stride + w * new_c_stride;
242
117
                for (int c = 0; c < before_paddings; c++) {
243
6
                    float *dst = start + c;
244
6
                    if (params->mode == LPMP_CONSTANT) {
245
6
                        *dst = params->constant_values;
246
                    } else {
247
                        int buddy = before_get_buddy(c, before_paddings, params->mode);
248
                        float *src = start + buddy;
249
                        *dst = *src;
250
                    }
251
                }
252
123
                for (int c = 0; c < after_paddings; c++) {
253
12
                    int given = channel + before_paddings + c;
254
12
                    float *dst = start + given;
255
12
                    if (params->mode == LPMP_CONSTANT) {
256
12
                        *dst = params->constant_values;
257
                    } else {
258
                        int buddy = after_get_buddy(given, channel + before_paddings, params->mode);
259
                        float *src = start + buddy;
260
                        *dst = *src;
261
                    }
262
                }
263
            }
264
        }
265
    }
266
267
3
    return 0;
268
}