Line data Source code
1 : /*
2 : * Copyright(c) 2019 Intel Corporation
3 : * SPDX - License - Identifier: BSD - 2 - Clause - Patent
4 : */
5 :
6 : // main.cpp
7 : // -Contructs the following resources needed during the encoding process
8 : // -memory
9 : // -threads
10 : // -semaphores
11 : // -semaphores
12 : // -Configures the encoder
13 : // -Calls the encoder via the API
14 : // -Destructs the resources
15 :
16 : /***************************************
17 : * Includes
18 : ***************************************/
19 : #include <stdio.h>
20 : #include <stdlib.h>
21 : #include <signal.h>
22 : #include <stdint.h>
23 : #include "EbAppConfig.h"
24 : #include "EbAppContext.h"
25 : #include "EbTime.h"
26 : #ifdef _WIN32
27 : #include <Windows.h>
28 : #include <io.h> /* _setmode() */
29 : #include <fcntl.h> /* _O_BINARY */
30 : #else
31 : #include <pthread.h>
32 : #include <semaphore.h>
33 : #include <time.h>
34 : #include <errno.h>
35 : #endif
36 :
37 : /***************************************
38 : * External Functions
39 : ***************************************/
40 : extern AppExitConditionType ProcessInputBuffer(
41 : EbConfig *config,
42 : EbAppContext *appCallBack);
43 :
44 : extern AppExitConditionType ProcessOutputReconBuffer(
45 : EbConfig *config,
46 : EbAppContext *appCallBack);
47 :
48 : extern AppExitConditionType ProcessOutputStreamBuffer(
49 : EbConfig *config,
50 : EbAppContext *appCallBack,
51 : uint8_t pic_send_done);
52 :
53 : volatile int32_t keepRunning = 1;
54 :
55 0 : void EventHandler(int32_t dummy) {
56 : (void)dummy;
57 0 : keepRunning = 0;
58 :
59 : // restore default signal handler
60 0 : signal(SIGINT, SIG_DFL);
61 0 : }
62 :
63 0 : void AssignAppThreadGroup(uint8_t target_socket) {
64 : #ifdef _WIN32
65 : if (GetActiveProcessorGroupCount() == 2) {
66 : GROUP_AFFINITY group_affinity;
67 : GetThreadGroupAffinity(GetCurrentThread(), &group_affinity);
68 : group_affinity.Group = target_socket;
69 : SetThreadGroupAffinity(GetCurrentThread(), &group_affinity, NULL);
70 : }
71 : #else
72 : (void)target_socket;
73 0 : return;
74 : #endif
75 : }
76 :
77 : double get_psnr(double sse, double max);
78 :
79 : /***************************************
80 : * Encoder App Main
81 : ***************************************/
82 2 : int32_t main(int32_t argc, char* argv[])
83 : {
84 : #ifdef _WIN32
85 : _setmode(_fileno(stdin), _O_BINARY);
86 : _setmode(_fileno(stdout), _O_BINARY);
87 : #endif
88 : // GLOBAL VARIABLES
89 2 : EbErrorType return_error = EB_ErrorNone; // Error Handling
90 2 : AppExitConditionType exitCondition = APP_ExitConditionNone; // Processing loop exit condition
91 :
92 : EbErrorType return_errors[MAX_CHANNEL_NUMBER]; // Error Handling
93 : AppExitConditionType exitConditions[MAX_CHANNEL_NUMBER]; // Processing loop exit condition
94 : AppExitConditionType exitConditionsOutput[MAX_CHANNEL_NUMBER]; // Processing loop exit condition
95 : AppExitConditionType exitConditionsRecon[MAX_CHANNEL_NUMBER]; // Processing loop exit condition
96 : AppExitConditionType exitConditionsInput[MAX_CHANNEL_NUMBER]; // Processing loop exit condition
97 :
98 : EbBool channelActive[MAX_CHANNEL_NUMBER];
99 :
100 : EbConfig *configs[MAX_CHANNEL_NUMBER]; // Encoder Configuration
101 :
102 2 : uint32_t num_channels = 0;
103 2 : uint32_t instanceCount=0;
104 : EbAppContext *appCallbacks[MAX_CHANNEL_NUMBER]; // Instances App callback data
105 2 : signal(SIGINT, EventHandler);
106 2 : printf("-------------------------------------------\n");
107 2 : printf("SVT-AV1 Encoder\n");
108 2 : if (!get_help(argc, argv)) {
109 : // Get num_channels
110 2 : num_channels = get_number_of_channels(argc, argv);
111 2 : if (num_channels == 0)
112 0 : return EB_ErrorBadParameter;
113 : // Initialize config
114 4 : for (instanceCount = 0; instanceCount < num_channels; ++instanceCount) {
115 2 : configs[instanceCount] = (EbConfig*)malloc(sizeof(EbConfig));
116 2 : if (!configs[instanceCount]) {
117 0 : while(instanceCount-- > 0)
118 0 : free(configs[instanceCount]);
119 0 : return EB_ErrorInsufficientResources;
120 : }
121 2 : eb_config_ctor(configs[instanceCount]);
122 2 : return_errors[instanceCount] = EB_ErrorNone;
123 : }
124 :
125 : // Initialize appCallback
126 4 : for (instanceCount = 0; instanceCount < num_channels; ++instanceCount) {
127 2 : appCallbacks[instanceCount] = (EbAppContext*)malloc(sizeof(EbAppContext));
128 2 : if (!appCallbacks[instanceCount]) {
129 0 : while(instanceCount-- > 0)
130 0 : free(appCallbacks[instanceCount]);
131 0 : return EB_ErrorInsufficientResources;
132 : }
133 : }
134 :
135 14 : for (instanceCount = 0; instanceCount < MAX_CHANNEL_NUMBER; ++instanceCount) {
136 12 : exitConditions[instanceCount] = APP_ExitConditionError; // Processing loop exit condition
137 12 : exitConditionsOutput[instanceCount] = APP_ExitConditionError; // Processing loop exit condition
138 12 : exitConditionsRecon[instanceCount] = APP_ExitConditionError; // Processing loop exit condition
139 12 : exitConditionsInput[instanceCount] = APP_ExitConditionError; // Processing loop exit condition
140 12 : channelActive[instanceCount] = EB_FALSE;
141 : }
142 :
143 : // Read all configuration files.
144 2 : return_error = read_command_line(argc, argv, configs, num_channels, return_errors);
145 :
146 : // Process any command line options, including the configuration file
147 :
148 2 : if (return_error == EB_ErrorNone) {
149 : // Set main thread affinity
150 2 : if (configs[0]->target_socket != -1)
151 0 : AssignAppThreadGroup(configs[0]->target_socket);
152 :
153 : // Init the Encoder
154 4 : for (instanceCount = 0; instanceCount < num_channels; ++instanceCount) {
155 2 : if (return_errors[instanceCount] == EB_ErrorNone) {
156 2 : configs[instanceCount]->active_channel_count = num_channels;
157 2 : configs[instanceCount]->channel_id = instanceCount;
158 :
159 2 : StartTime((uint64_t*)&configs[instanceCount]->performance_context.lib_start_time[0], (uint64_t*)&configs[instanceCount]->performance_context.lib_start_time[1]);
160 :
161 2 : return_errors[instanceCount] = init_encoder(configs[instanceCount], appCallbacks[instanceCount], instanceCount);
162 2 : return_error = (EbErrorType)(return_error | return_errors[instanceCount]);
163 : }
164 : else
165 0 : channelActive[instanceCount] = EB_FALSE;
166 : }
167 :
168 : {
169 : // Start the Encoder
170 4 : for (instanceCount = 0; instanceCount < num_channels; ++instanceCount) {
171 2 : if (return_errors[instanceCount] == EB_ErrorNone) {
172 2 : return_error = (EbErrorType)(return_error & return_errors[instanceCount]);
173 2 : exitConditions[instanceCount] = APP_ExitConditionNone;
174 2 : exitConditionsOutput[instanceCount] = APP_ExitConditionNone;
175 2 : exitConditionsRecon[instanceCount] = configs[instanceCount]->recon_file ? APP_ExitConditionNone : APP_ExitConditionError;
176 2 : exitConditionsInput[instanceCount] = APP_ExitConditionNone;
177 2 : channelActive[instanceCount] = EB_TRUE;
178 2 : StartTime((uint64_t*)&configs[instanceCount]->performance_context.encode_start_time[0], (uint64_t*)&configs[instanceCount]->performance_context.encode_start_time[1]);
179 : }
180 : else {
181 0 : exitConditions[instanceCount] = APP_ExitConditionError;
182 0 : exitConditionsOutput[instanceCount] = APP_ExitConditionError;
183 0 : exitConditionsRecon[instanceCount] = APP_ExitConditionError;
184 0 : exitConditionsInput[instanceCount] = APP_ExitConditionError;
185 : }
186 :
187 : #if DISPLAY_MEMORY
188 : EB_APP_MEMORY();
189 : #endif
190 : }
191 2 : printf("Encoding ");
192 2 : fflush(stdout);
193 :
194 240 : while (exitCondition == APP_ExitConditionNone) {
195 238 : exitCondition = APP_ExitConditionFinished;
196 476 : for (instanceCount = 0; instanceCount < num_channels; ++instanceCount) {
197 238 : if (channelActive[instanceCount] == EB_TRUE) {
198 238 : if (exitConditionsInput[instanceCount] == APP_ExitConditionNone)
199 120 : exitConditionsInput[instanceCount] = ProcessInputBuffer(
200 : configs[instanceCount],
201 : appCallbacks[instanceCount]);
202 238 : if (exitConditionsRecon[instanceCount] == APP_ExitConditionNone)
203 0 : exitConditionsRecon[instanceCount] = ProcessOutputReconBuffer(
204 : configs[instanceCount],
205 : appCallbacks[instanceCount]);
206 238 : if (exitConditionsOutput[instanceCount] == APP_ExitConditionNone)
207 238 : exitConditionsOutput[instanceCount] = ProcessOutputStreamBuffer(
208 : configs[instanceCount],
209 : appCallbacks[instanceCount],
210 238 : (exitConditionsInput[instanceCount] == APP_ExitConditionNone) || (exitConditionsRecon[instanceCount] == APP_ExitConditionNone)? 0 : 1);
211 238 : if (((exitConditionsRecon[instanceCount] == APP_ExitConditionFinished || !configs[instanceCount]->recon_file) && exitConditionsOutput[instanceCount] == APP_ExitConditionFinished && exitConditionsInput[instanceCount] == APP_ExitConditionFinished)||
212 236 : ((exitConditionsRecon[instanceCount] == APP_ExitConditionError && configs[instanceCount]->recon_file) || exitConditionsOutput[instanceCount] == APP_ExitConditionError || exitConditionsInput[instanceCount] == APP_ExitConditionError)){
213 2 : channelActive[instanceCount] = EB_FALSE;
214 2 : if (configs[instanceCount]->recon_file)
215 0 : exitConditions[instanceCount] = (AppExitConditionType)(exitConditionsRecon[instanceCount] | exitConditionsOutput[instanceCount] | exitConditionsInput[instanceCount]);
216 : else
217 2 : exitConditions[instanceCount] = (AppExitConditionType)(exitConditionsOutput[instanceCount] | exitConditionsInput[instanceCount]);
218 : }
219 : }
220 : }
221 : // check if all channels are inactive
222 476 : for (instanceCount = 0; instanceCount < num_channels; ++instanceCount) {
223 238 : if (channelActive[instanceCount] == EB_TRUE)
224 236 : exitCondition = APP_ExitConditionNone;
225 : }
226 : }
227 :
228 4 : for (instanceCount = 0; instanceCount < num_channels; ++instanceCount) {
229 2 : if (exitConditions[instanceCount] == APP_ExitConditionFinished && return_errors[instanceCount] == EB_ErrorNone) {
230 : double frame_rate;
231 2 : uint64_t frame_count = (uint32_t)configs[instanceCount]->performance_context.frame_count;
232 2 : uint32_t max_luma_value = (configs[instanceCount]->encoder_bit_depth == 8) ? 255 : 1023;
233 2 : double max_luma_sse = (double)max_luma_value*max_luma_value *
234 2 : (configs[instanceCount]->source_width*configs[instanceCount]->source_height);
235 2 : double max_chroma_sse = (double)max_luma_value*max_luma_value *
236 2 : (configs[instanceCount]->source_width/2*configs[instanceCount]->source_height/2);
237 :
238 2 : if ((configs[instanceCount]->frame_rate_numerator != 0 && configs[instanceCount]->frame_rate_denominator != 0) || configs[instanceCount]->frame_rate != 0) {
239 2 : if (configs[instanceCount]->frame_rate_numerator && configs[instanceCount]->frame_rate_denominator && (configs[instanceCount]->frame_rate_numerator != 0 && configs[instanceCount]->frame_rate_denominator != 0))
240 2 : frame_rate = ((double)configs[instanceCount]->frame_rate_numerator) / ((double)configs[instanceCount]->frame_rate_denominator);
241 0 : else if (configs[instanceCount]->frame_rate > 1000) {
242 : // Correct for 16-bit fixed-point fractional precision
243 0 : frame_rate = ((double)configs[instanceCount]->frame_rate) / (1 << 16);
244 : }
245 : else
246 0 : frame_rate = (double)configs[instanceCount]->frame_rate;
247 :
248 2 : if (configs[instanceCount]->stat_report) {
249 0 : if (configs[instanceCount]->stat_file) {
250 0 : fprintf(configs[instanceCount]->stat_file, "\nSUMMARY ---------------------------------------------------------------------\n");
251 :
252 : // Interlaced Video
253 0 : if (configs[instanceCount]->interlaced_video || configs[instanceCount]->separate_fields)
254 0 : fprintf(configs[instanceCount]->stat_file, "Total Fields\tAverage QP \tY-PSNR \tU-PSNR \tV-PSNR \tBitrate\n");
255 : else {
256 0 : fprintf(configs[instanceCount]->stat_file, "\n\t\t\t\t\t\t\tAverage PSNR (using per-frame PSNR)\t\t|\tOverall PSNR (using per-frame MSE)\n");
257 0 : fprintf(configs[instanceCount]->stat_file, "Total Frames\tAverage QP \tY-PSNR \tU-PSNR \tV-PSNR\t\t| \tY-PSNR \tU-PSNR \tV-PSNR \t|\tBitrate\n");
258 : }
259 0 : fprintf(configs[instanceCount]->stat_file, "%10ld \t %2.2f \t%3.2f dB\t%3.2f dB\t%3.2f dB \t|\t%3.2f dB\t%3.2f dB\t%3.2f dB \t|\t%.2f kbps\n",
260 : (long int)frame_count,
261 0 : (float)configs[instanceCount]->performance_context.sum_qp / frame_count,
262 0 : (float)configs[instanceCount]->performance_context.sum_luma_psnr / frame_count,
263 0 : (float)configs[instanceCount]->performance_context.sum_cb_psnr / frame_count,
264 0 : (float)configs[instanceCount]->performance_context.sum_cr_psnr / frame_count,
265 0 : (float)(get_psnr((configs[instanceCount]->performance_context.sum_luma_sse / frame_count) , max_luma_sse)),
266 0 : (float)(get_psnr((configs[instanceCount]->performance_context.sum_cb_sse / frame_count) , max_chroma_sse)),
267 0 : (float)(get_psnr((configs[instanceCount]->performance_context.sum_cr_sse / frame_count) , max_chroma_sse)),
268 0 : ((double)(configs[instanceCount]->performance_context.byte_count << 3) * frame_rate / (configs[instanceCount]->frames_encoded * 1000)));
269 : }
270 : }
271 :
272 2 : printf("\nSUMMARY --------------------------------- Channel %u --------------------------------\n", instanceCount + 1);
273 : {
274 2 : if (configs[instanceCount]->interlaced_video || configs[instanceCount]->separate_fields)
275 0 : printf("Total Fields\t\tFrame Rate\t\tByte Count\t\tBitrate\n");
276 : else
277 2 : printf("Total Frames\t\tFrame Rate\t\tByte Count\t\tBitrate\n");
278 2 : printf("%12d\t\t%4.2f fps\t\t%10.0f\t\t%5.2f kbps\n",
279 : (int32_t)frame_count,
280 : (double)frame_rate,
281 2 : (double)configs[instanceCount]->performance_context.byte_count,
282 2 : ((double)(configs[instanceCount]->performance_context.byte_count << 3) * frame_rate / (configs[instanceCount]->frames_encoded * 1000)));
283 : }
284 :
285 2 : if (configs[instanceCount]->stat_report) {
286 0 : printf("\n\t\t\t\tAverage PSNR (using per-frame PSNR)\t\t\t|\t\tOverall PSNR (using per-frame MSE)\n");
287 0 : printf("Average QP\t\tY-PSNR\t\t\tU-PSNR\t\t\tV-PSNR\t\t|\tY-PSNR\t\t\tU-PSNR\t\t\tV-PSNR\t\n");
288 0 : printf("%11.2f\t\t%4.2f dB\t\t%4.2f dB\t\t%4.2f dB\t|\t%4.2f dB\t\t%4.2f dB\t\t%4.2f dB\n",
289 0 : (float)configs[instanceCount]->performance_context.sum_qp / frame_count,
290 0 : (float)configs[instanceCount]->performance_context.sum_luma_psnr / frame_count,
291 0 : (float)configs[instanceCount]->performance_context.sum_cb_psnr / frame_count,
292 0 : (float)configs[instanceCount]->performance_context.sum_cr_psnr / frame_count,
293 0 : (float)(get_psnr((configs[instanceCount]->performance_context.sum_luma_sse / frame_count), max_luma_sse)),
294 0 : (float)(get_psnr((configs[instanceCount]->performance_context.sum_cb_sse / frame_count), max_chroma_sse)),
295 0 : (float)(get_psnr((configs[instanceCount]->performance_context.sum_cr_sse / frame_count), max_chroma_sse)));
296 : }
297 :
298 2 : fflush(stdout);
299 : }
300 : }
301 : }
302 2 : printf("\n");
303 2 : fflush(stdout);
304 : }
305 4 : for (instanceCount = 0; instanceCount < num_channels; ++instanceCount) {
306 2 : if (exitConditions[instanceCount] == APP_ExitConditionFinished && return_errors[instanceCount] == EB_ErrorNone) {
307 2 : if (configs[instanceCount]->stop_encoder == EB_FALSE) {
308 : // Interlaced Video
309 2 : if (configs[instanceCount]->interlaced_video || configs[instanceCount]->separate_fields) {
310 0 : printf("\nChannel %u\nAverage Speed:\t\t%.0f fields per sec\nTotal Encoding Time:\t\t%.0f ms\nTotal Execution Time:\t\t%.2f ms\nAverage Latency:\t%.0f ms\nMax Latency:\t\t%u ms\n",
311 0 : (uint32_t)(instanceCount + 1),
312 0 : configs[instanceCount]->performance_context.average_speed,
313 0 : configs[instanceCount]->performance_context.total_encode_time * 1000,
314 0 : configs[instanceCount]->performance_context.total_execution_time * 1000,
315 0 : configs[instanceCount]->performance_context.average_latency,
316 0 : (uint32_t)(configs[instanceCount]->performance_context.max_latency));
317 : }
318 : else {
319 2 : printf("\nChannel %u\nAverage Speed:\t\t%.3f fps\nTotal Encoding Time:\t%.0f ms\nTotal Execution Time:\t%.0f ms\nAverage Latency:\t%.0f ms\nMax Latency:\t\t%u ms\n",
320 2 : (uint32_t)(instanceCount + 1),
321 2 : configs[instanceCount]->performance_context.average_speed,
322 2 : configs[instanceCount]->performance_context.total_encode_time * 1000,
323 2 : configs[instanceCount]->performance_context.total_execution_time * 1000,
324 2 : configs[instanceCount]->performance_context.average_latency,
325 2 : (uint32_t)(configs[instanceCount]->performance_context.max_latency));
326 : }
327 : }
328 : else
329 0 : printf("\nChannel %u Encoding Interrupted\n", (uint32_t)(instanceCount + 1));
330 : }
331 0 : else if (return_errors[instanceCount] == EB_ErrorInsufficientResources)
332 0 : printf("Could not allocate enough memory for channel %u\n", instanceCount + 1);
333 : else
334 0 : printf("Error encoding at channel %u! Check error log file for more details ... \n", instanceCount + 1);
335 : }
336 : // DeInit Encoder
337 4 : for (instanceCount = num_channels; instanceCount > 0; --instanceCount) {
338 2 : if (return_errors[instanceCount - 1] == EB_ErrorNone)
339 2 : return_errors[instanceCount - 1] = de_init_encoder(appCallbacks[instanceCount - 1], instanceCount - 1);
340 : }
341 : }
342 : else {
343 0 : printf("Error in configuration, could not begin encoding! ... \n");
344 0 : printf("Run %s -help for a list of options\n", argv[0]);
345 : }
346 : // Destruct the App memory variables
347 4 : for (instanceCount = 0; instanceCount < num_channels; ++instanceCount) {
348 2 : eb_config_dtor(configs[instanceCount]);
349 2 : if (configs[instanceCount])
350 2 : free(configs[instanceCount]);
351 2 : if (appCallbacks[instanceCount])
352 2 : free(appCallbacks[instanceCount]);
353 : }
354 :
355 2 : printf("Encoder finished\n");
356 : }
357 :
358 2 : return (return_error == 0) ? 0 : 1;
359 : }
|