Coverage Report

Created: 2026-05-16 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/svt-av1/Source/Lib/Codec/firstpass.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2016, 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
12
#include <limits.h>
13
#include <math.h>
14
#include <stdio.h>
15
16
#include "aom_dsp_rtcd.h"
17
#include "definitions.h"
18
#include "rc_process.h"
19
#include "sequence_control_set.h"
20
#include "pcs.h"
21
#include "firstpass.h"
22
#include "svt_log.h"
23
#include "md_process.h"
24
#include "coding_loop.h"
25
#include "pd_process.h"
26
#include "md_config_process.h"
27
#include "mv.h"
28
#ifdef ARCH_X86_64
29
#include <xmmintrin.h>
30
#endif
31
#include "motion_estimation.h"
32
#include "pd_results.h"
33
34
#undef _MM_HINT_T2
35
#define _MM_HINT_T2 1
36
37
#define OUTPUT_FPF 0
38
39
#define INTRA_MODE_PENALTY 1024
40
#define NEW_MV_MODE_PENALTY 32
41
#define DARK_THRESH 64
42
43
#define NCOUNT_INTRA_THRESH 8192
44
#define NCOUNT_INTRA_FACTOR 3
45
46
0
#define STATS_CAPABILITY_INIT 100
47
//1.5 times larger than request.
48
0
#define STATS_CAPABILITY_GROW(s) (s * 3 / 2)
49
50
0
static EbErrorType realloc_stats_out(SequenceControlSet* scs, FirstPassStatsOut* out, uint64_t frame_number) {
51
0
    if (frame_number < out->size) {
52
0
        return EB_ErrorNone;
53
0
    }
54
55
0
    if ((int64_t)frame_number >= (int64_t)out->capability - 1) {
56
0
        size_t capability = (int64_t)frame_number >= (int64_t)STATS_CAPABILITY_INIT - 1
57
0
            ? STATS_CAPABILITY_GROW(frame_number)
58
0
            : STATS_CAPABILITY_INIT;
59
0
        if (scs->lap_rc) {
60
            //store the data points before re-allocation
61
0
            uint64_t stats_in_start_offset = 0;
62
0
            uint64_t stats_in_offset       = 0;
63
0
            uint64_t stats_in_end_offset   = 0;
64
0
            if (frame_number) {
65
0
                stats_in_start_offset = scs->twopass.stats_buf_ctx->stats_in_start - out->stat;
66
0
                stats_in_offset       = scs->twopass.stats_in - out->stat;
67
0
                stats_in_end_offset   = scs->twopass.stats_buf_ctx->stats_in_end_write - out->stat;
68
0
            }
69
0
            EB_REALLOC_ARRAY(out->stat, capability);
70
            // restore the pointers after re-allocation is done
71
0
            scs->twopass.stats_buf_ctx->stats_in_start     = out->stat + stats_in_start_offset;
72
0
            scs->twopass.stats_in                          = out->stat + stats_in_offset;
73
0
            scs->twopass.stats_buf_ctx->stats_in_end_write = out->stat + stats_in_end_offset;
74
0
        } else {
75
0
            EB_REALLOC_ARRAY(out->stat, capability);
76
0
        }
77
0
        out->capability = capability;
78
0
    }
79
0
    out->size = frame_number + 1;
80
0
    return EB_ErrorNone;
81
0
}
82
83
static AOM_INLINE void output_stats(SequenceControlSet* scs, const FIRSTPASS_STATS* stats, uint64_t frame_number) {
84
    FirstPassStatsOut* stats_out = &scs->enc_ctx->stats_out;
85
    svt_block_on_mutex(scs->enc_ctx->stat_file_mutex);
86
    if (realloc_stats_out(scs, stats_out, frame_number) != EB_ErrorNone) {
87
        SVT_ERROR("realloc_stats_out request %d entries failed failed\n", frame_number);
88
    } else {
89
        stats_out->stat[frame_number] = *stats;
90
    }
91
92
    // TEMP debug code
93
#if OUTPUT_FPF
94
    {
95
        FILE* fpfile;
96
        if (frame_number == 0) {
97
            fpfile = fopen("firstpass.stt", "w");
98
        } else {
99
            fpfile = fopen("firstpass.stt", "a");
100
        }
101
        fprintf(fpfile,
102
                "%12.0lf %12.4lf %12.0lf %12.0lf %12.0lf %12.4lf %12.4lf"
103
                "%12.4lf %12.4lf %12.4lf %12.4lf %12.4lf %12.4lf %12.4lf %12.4lf"
104
                "%12.4lf %12.4lf %12.0lf %12.4lf %12.4lf %12.4lf %12.4lf\n",
105
                stats->frame,
106
                stats->weight,
107
                stats->intra_error,
108
                stats->coded_error,
109
                stats->sr_coded_error,
110
                stats->pcnt_inter,
111
                stats->pcnt_motion,
112
                stats->pcnt_second_ref,
113
                stats->pcnt_neutral,
114
                stats->intra_skip_pct,
115
                stats->inactive_zone_rows,
116
                stats->inactive_zone_cols,
117
                stats->MVr,
118
                stats->mvr_abs,
119
                stats->MVc,
120
                stats->mvc_abs,
121
                stats->MVrv,
122
                stats->MVcv,
123
                stats->mv_in_out_count,
124
                stats->new_mv_count,
125
                stats->count,
126
                stats->duration);
127
        fclose(fpfile);
128
    }
129
#endif
130
    svt_release_mutex(scs->enc_ctx->stat_file_mutex);
131
}
132
133
948
void svt_av1_twopass_zero_stats(FIRSTPASS_STATS* section) {
134
948
    section->frame       = 0.0;
135
948
    section->coded_error = 0.0;
136
948
    section->count       = 0.0;
137
948
    section->duration    = 1.0;
138
948
    memset(&section->stat_struct, 0, sizeof(StatStruct));
139
948
}
140
141
0
void svt_av1_accumulate_stats(FIRSTPASS_STATS* section, const FIRSTPASS_STATS* frame) {
142
0
    section->frame += frame->frame;
143
0
    section->coded_error += frame->coded_error;
144
0
    section->count += frame->count;
145
0
    section->duration += frame->duration;
146
0
}
147
148
0
void svt_av1_end_first_pass(PictureParentControlSet* pcs) {
149
0
    SequenceControlSet* scs     = pcs->scs;
150
0
    TWO_PASS*           twopass = &scs->twopass;
151
152
0
    if (twopass->stats_buf_ctx->total_stats) {
153
        // add the total to the end of the file
154
0
        svt_block_on_mutex(twopass->stats_buf_ctx->stats_in_write_mutex);
155
156
0
        FIRSTPASS_STATS total_stats = *twopass->stats_buf_ctx->total_stats;
157
0
        output_stats(scs, &total_stats, pcs->picture_number + 1);
158
159
0
        svt_release_mutex(twopass->stats_buf_ctx->stats_in_write_mutex);
160
0
    }
161
0
}
162
163
// Updates the first pass stats of this frame.
164
// Input:
165
//   stats: stats accumulated for this frame.
166
//   frame_number: current frame number.
167
//   ts_duration: Duration of the frame / collection of frames.
168
// Updates:
169
//   twopass->total_stats: the accumulated stats.
170
//   twopass->stats_buf_ctx->stats_in_end: the pointer to the current stats,
171
//                                         update its value and its position
172
//                                         in the buffer.
173
void update_firstpass_stats(PictureParentControlSet* pcs, const int frame_number, const double ts_duration,
174
0
                            StatStruct* stat_struct) {
175
0
    SequenceControlSet* scs     = pcs->scs;
176
0
    TWO_PASS*           twopass = &scs->twopass;
177
178
0
    svt_block_on_mutex(twopass->stats_buf_ctx->stats_in_write_mutex);
179
180
0
    FIRSTPASS_STATS* this_frame_stats = twopass->stats_buf_ctx->stats_in_end_write;
181
0
    FIRSTPASS_STATS  fps;
182
0
    fps.frame       = frame_number;
183
0
    fps.coded_error = 0;
184
0
    fps.count       = 1.0;
185
    // TODO(paulwilkins):  Handle the case when duration is set to 0, or
186
    // something less than the full time between subsequent values of
187
    // cpi->source_time_stamp.
188
0
    fps.duration = (double)ts_duration;
189
0
    memset(&fps.stat_struct, 0, sizeof(StatStruct));
190
0
    fps.stat_struct.poc                  = stat_struct->poc;
191
0
    fps.stat_struct.qindex               = stat_struct->qindex;
192
0
    fps.stat_struct.total_num_bits       = stat_struct->total_num_bits;
193
0
    fps.stat_struct.temporal_layer_index = stat_struct->temporal_layer_index;
194
0
    fps.stat_struct.worst_qindex         = stat_struct->worst_qindex;
195
    // We will store the stats inside the persistent twopass struct (and NOT the
196
    // local variable 'fps'), and then cpi->output_pkt_list will point to it.
197
0
    *this_frame_stats = fps;
198
0
    output_stats(scs, &fps, pcs->picture_number);
199
0
    if (twopass->stats_buf_ctx->total_stats != NULL && scs->static_config.pass == ENC_FIRST_PASS) {
200
0
        svt_av1_accumulate_stats(twopass->stats_buf_ctx->total_stats, &fps);
201
0
    }
202
    /*In the case of two pass, first pass uses it as a circular buffer,
203
   * when LAP is enabled it is used as a linear buffer*/
204
0
    twopass->stats_buf_ctx->stats_in_end_write++;
205
0
    if (scs->static_config.pass == ENC_FIRST_PASS &&
206
0
        (twopass->stats_buf_ctx->stats_in_end_write >= twopass->stats_buf_ctx->stats_in_buf_end)) {
207
0
        twopass->stats_buf_ctx->stats_in_end_write = twopass->stats_buf_ctx->stats_in_start;
208
0
    }
209
0
    svt_release_mutex(twopass->stats_buf_ctx->stats_in_write_mutex);
210
0
}
211
212
0
void first_pass_frame_end_one_pass(PictureParentControlSet* pcs) {
213
0
    SequenceControlSet* scs     = pcs->scs;
214
0
    TWO_PASS*           twopass = &scs->twopass;
215
216
0
    svt_block_on_mutex(twopass->stats_buf_ctx->stats_in_write_mutex);
217
0
    FIRSTPASS_STATS* this_frame_stats = twopass->stats_buf_ctx->stats_in_end_write;
218
0
    FIRSTPASS_STATS  fps;
219
0
    memset(&fps, 0, sizeof(FIRSTPASS_STATS));
220
0
    memset(&fps.stat_struct, 0, sizeof(StatStruct));
221
0
    fps.frame    = (double)pcs->picture_number;
222
0
    fps.count    = 1.0;
223
0
    fps.duration = (double)pcs->ts_duration;
224
225
    // We will store the stats inside the persistent twopass struct (and NOT the
226
    // local variable 'fps'), and then cpi->output_pkt_list will point to it.
227
0
    *this_frame_stats = fps;
228
0
    output_stats(scs, &fps, pcs->picture_number);
229
    /*In the case of two pass, first pass uses it as a circular buffer,
230
   * when LAP is enabled it is used as a linear buffer*/
231
0
    twopass->stats_buf_ctx->stats_in_end_write++;
232
0
    svt_release_mutex(twopass->stats_buf_ctx->stats_in_write_mutex);
233
0
}