21
21
* along with this program. If not, see <http://www.gnu.org/licenses/>.
22
22
*/
23
23
24
+ #if defined(__linux__ )
25
+ #define _GNU_SOURCE
26
+ #include <sched.h>
27
+ #elif defined(__APPLE__ ) || defined(__MACH__ ) || defined(__FreeBSD__ ) || defined(__OpenBSD__ ) || defined(__NetBSD__ ) || defined(__DragonFly__ )
28
+ #include <sys/types.h>
29
+ #include <sys/sysctl.h>
30
+ #endif
31
+
24
32
#include <errno.h>
25
33
#include <signal.h>
26
34
#include <string.h>
59
67
#if LIBFLAC_ENABLED == 1
60
68
#include "FLAC/metadata.h"
61
69
#include "FLAC/stream_encoder.h"
62
- #define GETOPT_STRING "d:a:b:fl:vx:r:ph"
70
+ # if defined(FLAC_API_VERSION_CURRENT ) && FLAC_API_VERSION_CURRENT >= 14
71
+ # define GETOPT_STRING "d:a:b:c:fl:vx:r:ph"
72
+ static const char * const _FLAC_StreamEncoderSetNumThreadsStatusString [] = {
73
+ "FLAC__STREAM_ENCODER_SET_NUM_THREADS_OK" ,
74
+ "FLAC__STREAM_ENCODER_SET_NUM_THREADS_NOT_COMPILED_WITH_MULTITHREADING_ENABLED" ,
75
+ "FLAC__STREAM_ENCODER_SET_NUM_THREADS_ALREADY_INITIALIZED" ,
76
+ "FLAC__STREAM_ENCODER_SET_NUM_THREADS_TOO_MANY_THREADS"
77
+ };
78
+ # else
79
+ # define GETOPT_STRING "d:a:b:fl:vx:r:ph"
80
+ # endif
63
81
#else
64
82
#define GETOPT_STRING "d:a:b:x:r:ph"
65
83
#endif
@@ -87,6 +105,7 @@ typedef struct {
87
105
#if LIBFLAC_ENABLED == 1
88
106
uint32_t flac_level ;
89
107
bool flac_verify ;
108
+ uint32_t flac_threads ;
90
109
#endif
91
110
} filewriter_ctx_t ;
92
111
@@ -111,6 +130,9 @@ void usage(void)
111
130
"\t[-f compress ADC output as FLAC]\n"
112
131
"\t[-l LEVEL set flac compression level (default: 1)]\n"
113
132
"\t[-v enable verification of flac encoder output]\n"
133
+ #if defined(FLAC_API_VERSION_CURRENT ) && FLAC_API_VERSION_CURRENT >= 14
134
+ "\t[-c number of encoding threads per file (default: auto)]\n"
135
+ #endif
114
136
#endif
115
137
);
116
138
exit (1 );
@@ -189,6 +211,7 @@ int flac_file_writer(void *ctx)
189
211
filewriter_ctx_t * file_ctx = ctx ;
190
212
size_t len = BUFFER_READ_SIZE ;
191
213
void * buf ;
214
+ uint32_t ret ;
192
215
FLAC__bool ok = true;
193
216
FLAC__StreamEncoder * encoder = NULL ;
194
217
FLAC__StreamEncoderInitStatus init_status ;
@@ -211,7 +234,12 @@ int flac_file_writer(void *ctx)
211
234
do_exit = 1 ;
212
235
return 0 ;
213
236
}
214
-
237
+ #if defined(FLAC_API_VERSION_CURRENT ) && FLAC_API_VERSION_CURRENT >= 14
238
+ ret = FLAC__stream_encoder_set_num_threads (encoder , file_ctx -> flac_threads );
239
+ if (ret != FLAC__STREAM_ENCODER_SET_NUM_THREADS_OK ) {
240
+ fprintf (stderr , "ERROR: failed to set FLAC threads: %s\n" , _FLAC_StreamEncoderSetNumThreadsStatusString [ret ]);
241
+ }
242
+ #endif
215
243
if ((seektable = FLAC__metadata_object_new (FLAC__METADATA_TYPE_SEEKTABLE )) == NULL
216
244
|| FLAC__metadata_object_seektable_template_append_spaced_points (seektable , 1 <<18 , (uint64_t )1 <<41 ) != true
217
245
|| FLAC__stream_encoder_set_metadata (encoder , & seektable , 1 ) != true) {
@@ -252,10 +280,12 @@ int flac_file_writer(void *ctx)
252
280
}
253
281
FLAC__metadata_object_seektable_template_sort (seektable , false);
254
282
/* bug in libflac, fix seektable manually */
283
+ #if !defined(FLAC_API_VERSION_CURRENT ) || FLAC_API_VERSION_CURRENT < 14
255
284
for (int i = seektable -> data .seek_table .num_points - 1 ; i >=0 ; i -- ) {
256
285
if (seektable -> data .seek_table .points [i ].stream_offset != 0 ) break ;
257
286
seektable -> data .seek_table .points [i ].sample_number = 0xFFFFFFFFFFFFFFFF ;
258
287
}
288
+ #endif
259
289
ok = FLAC__stream_encoder_finish (encoder );
260
290
if (!ok ) {
261
291
fprintf (stderr , "ERROR: FLAC encoder did not finish correctly: %s\n" , FLAC__StreamEncoderStateString [FLAC__stream_encoder_get_state (encoder )]);
@@ -274,6 +304,55 @@ void print_hsdaoh_message(int msg_type, int msg, void *additional, void *ctx)
274
304
new_line = 1 ;
275
305
}
276
306
307
+ #if LIBFLAC_ENABLED == 1 && defined(FLAC_API_VERSION_CURRENT ) && FLAC_API_VERSION_CURRENT >= 14
308
+ uint32_t get_num_cores () {
309
+ uint32_t numberOfCores = 0 ;
310
+ #if defined(_WIN32 ) || defined(_WIN64 )
311
+ DWORD_PTR processAffinityMask ;
312
+ DWORD_PTR systemAffinityMask ;
313
+ if (GetProcessAffinityMask (GetCurrentProcess (), & processAffinityMask , & systemAffinityMask )) {
314
+ while (processAffinityMask ) {
315
+ numberOfCores += processAffinityMask & 1 ;
316
+ processAffinityMask >>= 1 ;
317
+ }
318
+ return numberOfCores ;
319
+ } else {
320
+ // Handle error
321
+ SYSTEM_INFO sysInfo ;
322
+ fprintf (stderr , "GetProcessAffinityMask failed with error to get number of cores: %lu, fallback to GetSystemInfo\n" , GetLastError ());
323
+ GetSystemInfo (& sysInfo );
324
+ return sysInfo .dwNumberOfProcessors ;
325
+ }
326
+ #elif defined(__linux__ )
327
+ cpu_set_t mask ;
328
+ if (sched_getaffinity (0 , sizeof (cpu_set_t ), & mask ) == 0 ) {
329
+ return CPU_COUNT (& mask );
330
+ } else {
331
+ // Handle error
332
+ fprintf (stderr , "sched_getaffinity failed to get number of cores, fallback to sysconf\n" );
333
+ // cores in deep-sleep are not counted with _SC_NPROCESSORS_ONLN, therefore using _CONF instead
334
+ return sysconf (_SC_NPROCESSORS_CONF );
335
+ }
336
+ #elif defined(__APPLE__ ) || defined(__MACH__ ) || defined(__FreeBSD__ ) || defined(__OpenBSD__ ) || defined(__NetBSD__ ) || defined(__DragonFly__ )
337
+ size_t size = sizeof (numberOfCores );
338
+ #if defined(__APPLE__ ) || defined(__MACH__ )
339
+ if (sysctlbyname ("hw.logicalcpu" , & numberOfCores , & size , NULL , 0 ) == 0 ) {
340
+ #else
341
+ if (sysctlbyname ("hw.ncpu" , & numberOfCores , & size , NULL , 0 ) == 0 ) {
342
+ #endif
343
+ return numberOfCores ;
344
+ } else {
345
+ // Handle error
346
+ fprintf (stderr , "failed to get number of cores\n" );
347
+ return 0 ;
348
+ }
349
+ #else
350
+ #warning "No code to get number of cores on this platform!"
351
+ return 0 ;
352
+ #endif
353
+ }
354
+ #endif
355
+
277
356
int main (int argc , char * * argv )
278
357
{
279
358
//set pipe mode to binary in windows
@@ -288,6 +367,7 @@ int main(int argc, char **argv)
288
367
#if LIBFLAC_ENABLED == 1
289
368
int flac_level = 1 ;
290
369
bool flac_verify = false;
370
+ uint32_t flac_threads = 0 ;
291
371
#endif
292
372
thrd_start_t output_thread_func = raw_file_writer ;
293
373
capture_ctx_t cap_ctx ;
@@ -342,6 +422,11 @@ int main(int argc, char **argv)
342
422
output_names [1 ] = optarg ;
343
423
break ;
344
424
#if LIBFLAC_ENABLED == 1
425
+ #if defined(FLAC_API_VERSION_CURRENT ) && FLAC_API_VERSION_CURRENT >= 14
426
+ case 'c' :
427
+ flac_threads = (uint32_t )atoi (optarg );
428
+ break ;
429
+ #endif
345
430
case 'f' :
346
431
output_thread_func = flac_file_writer ;
347
432
out_size = 4 ;
@@ -374,6 +459,17 @@ int main(int argc, char **argv)
374
459
usage ();
375
460
}
376
461
462
+ #if LIBFLAC_ENABLED == 1 && defined(FLAC_API_VERSION_CURRENT ) && FLAC_API_VERSION_CURRENT >= 14
463
+ if (flac_threads == 0 ) {
464
+ int out_cnt = ((output_names [0 ] == NULL ) ? 0 : 1 ) + ((output_names [1 ] == NULL ) ? 0 : 1 );
465
+ flac_threads = get_num_cores ();
466
+ fprintf (stderr ,"Detected %d cores in the system available to the process\n" ,flac_threads );
467
+ flac_threads = (flac_threads - 2 - out_cnt ) / out_cnt ;
468
+ if (flac_threads == 0 ) flac_threads = 1 ;
469
+ if (flac_threads > 128 ) flac_threads = 128 ;
470
+ }
471
+ #endif
472
+
377
473
#ifndef _WIN32
378
474
sigact .sa_handler = sighandler ;
379
475
sigemptyset (& sigact .sa_mask );
@@ -408,6 +504,7 @@ int main(int argc, char **argv)
408
504
#if LIBFLAC_ENABLED == 1
409
505
thread_out_ctx [i ].flac_level = flac_level ;
410
506
thread_out_ctx [i ].flac_verify = flac_verify ;
507
+ thread_out_ctx [i ].flac_threads = flac_threads ;
411
508
#endif
412
509
outbuffer_name [3 ] = (char )(i + 48 );
413
510
rb_init (& thread_out_ctx [i ].rb , outbuffer_name , BUFFER_TOTAL_SIZE );
0 commit comments