1 /*
2 * time status related function source file
3 *
4 * Copyright (c) 1999 Mark Taylor
5 * 2010 Robert Hegemann
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
21 */
22
23 /* $Id: timestatus.c,v 1.60 2011/05/07 16:05:17 rbrito Exp $ */
24
25 #ifdef HAVE_CONFIG_H
26 # include <config.h>
27 #endif
28
29
30 #if 1
31 # define SPEED_CHAR "x" /* character x */
32 # define SPEED_MULT 1.
33 #else
34 # define SPEED_CHAR "%%"
35 # define SPEED_MULT 100.
36 #endif
37
38 #include <assert.h>
39 #include <time.h>
40 #include <string.h>
41 #include <stdlib.h>
42
43 #include "lame.h"
44 #include "main.h"
45 #include "lametime.h"
46 #include "timestatus.h"
47 #include "brhist.h"
48 #include "console.h"
49
50 #ifdef WITH_DMALLOC
51 #include <dmalloc.h>
52 #endif
53
54 typedef struct time_status_struct {
55 double last_time; /* result of last call to clock */
56 double elapsed_time; /* total time */
57 double estimated_time; /* estimated total duration time [s] */
58 double speed_index; /* speed relative to realtime coding [100%] */
59 } timestatus_t;
60
61 static struct EncoderProgress {
62 timestatus_t real_time;
63 timestatus_t proc_time;
64 double last_time;
65 int last_frame_num;
66 int time_status_init;
67 } global_encoder_progress;
68
69
70 /*
71 * Calculates from the input (see below) the following values:
72 * - total estimated time
73 * - a speed index
74 */
75
76 static void
ts_calc_times(timestatus_t * const tstime,const int sample_freq,const int frameNum,const int totalframes,const int framesize)77 ts_calc_times(timestatus_t * const tstime, /* tstime->elapsed_time: elapsed time */
78 const int sample_freq, /* sample frequency [Hz/kHz] */
79 const int frameNum, /* Number of the current Frame */
80 const int totalframes, /* total umber of Frames */
81 const int framesize)
82 { /* Size of a frame [bps/kbps] */
83 assert(sample_freq >= 8000 && sample_freq <= 48000);
84
85 if (frameNum > 0 && tstime->elapsed_time > 0) {
86 tstime->estimated_time = tstime->elapsed_time * totalframes / frameNum;
87 tstime->speed_index = framesize * frameNum / (sample_freq * tstime->elapsed_time);
88 }
89 else {
90 tstime->estimated_time = 0.;
91 tstime->speed_index = 0.;
92 }
93 }
94
95 /* Decomposes a given number of seconds into a easy to read hh:mm:ss format
96 * padded with an additional character
97 */
98
99 static void
ts_time_decompose(const double x,const char padded_char)100 ts_time_decompose(const double x, const char padded_char)
101 {
102 const unsigned long time_in_sec = (unsigned long)x;
103 const unsigned long hour = time_in_sec / 3600;
104 const unsigned int min = time_in_sec / 60 % 60;
105 const unsigned int sec = time_in_sec % 60;
106
107 if (hour == 0)
108 console_printf(" %2u:%02u%c", min, sec, padded_char);
109 else if (hour < 100)
110 console_printf("%2lu:%02u:%02u%c", hour, min, sec, padded_char);
111 else
112 console_printf("%6lu h%c", hour, padded_char);
113 }
114
115 static void
timestatus(const lame_global_flags * const gfp)116 timestatus(const lame_global_flags * const gfp)
117 {
118 timestatus_t* real_time = &global_encoder_progress.real_time;
119 timestatus_t* proc_time = &global_encoder_progress.proc_time;
120 int percent;
121 double tmx, delta;
122 int samp_rate = lame_get_out_samplerate(gfp)
123 , frameNum = lame_get_frameNum(gfp)
124 , totalframes = lame_get_totalframes(gfp)
125 , framesize = lame_get_framesize(gfp)
126 ;
127
128 if (totalframes < frameNum) {
129 totalframes = frameNum;
130 }
131 if (global_encoder_progress.time_status_init == 0) {
132 real_time->last_time = GetRealTime();
133 proc_time->last_time = GetCPUTime();
134 real_time->elapsed_time = 0;
135 proc_time->elapsed_time = 0;
136 }
137
138 /* we need rollover protection for GetCPUTime, and maybe GetRealTime(): */
139 tmx = GetRealTime();
140 delta = tmx - real_time->last_time;
141 if (delta < 0)
142 delta = 0; /* ignore, clock has rolled over */
143 real_time->elapsed_time += delta;
144 real_time->last_time = tmx;
145
146
147 tmx = GetCPUTime();
148 delta = tmx - proc_time->last_time;
149 if (delta < 0)
150 delta = 0; /* ignore, clock has rolled over */
151 proc_time->elapsed_time += delta;
152 proc_time->last_time = tmx;
153
154 if (global_encoder_progress.time_status_init == 0) {
155 console_printf("\r"
156 " Frame | CPU time/estim | REAL time/estim | play/CPU | ETA \n"
157 " 0/ ( 0%%)| 0:00/ : | 0:00/ : | "
158 SPEED_CHAR "| : \r"
159 /* , Console_IO.str_clreoln, Console_IO.str_clreoln */ );
160 global_encoder_progress.time_status_init = 1;
161 return;
162 }
163
164 ts_calc_times(real_time, samp_rate, frameNum, totalframes, framesize);
165 ts_calc_times(proc_time, samp_rate, frameNum, totalframes, framesize);
166
167 if (frameNum < totalframes) {
168 percent = (int) (100. * frameNum / totalframes + 0.5);
169 }
170 else {
171 percent = 100;
172 }
173
174 console_printf("\r%6i/%-6i", frameNum, totalframes);
175 console_printf(percent < 100 ? " (%2d%%)|" : "(%3.3d%%)|", percent);
176 ts_time_decompose(proc_time->elapsed_time, '/');
177 ts_time_decompose(proc_time->estimated_time, '|');
178 ts_time_decompose(real_time->elapsed_time, '/');
179 ts_time_decompose(real_time->estimated_time, '|');
180 console_printf(proc_time->speed_index <= 1. ?
181 "%9.4f" SPEED_CHAR "|" : "%#9.5g" SPEED_CHAR "|",
182 SPEED_MULT * proc_time->speed_index);
183 ts_time_decompose((real_time->estimated_time - real_time->elapsed_time), ' ');
184 }
185
186 static void
timestatus_finish(void)187 timestatus_finish(void)
188 {
189 console_printf("\n");
190 }
191
192
193 static void
brhist_init_package(lame_global_flags const * gf)194 brhist_init_package(lame_global_flags const* gf)
195 {
196 if (global_ui_config.brhist) {
197 if (brhist_init(gf, lame_get_VBR_min_bitrate_kbps(gf), lame_get_VBR_max_bitrate_kbps(gf))) {
198 /* fail to initialize */
199 global_ui_config.brhist = 0;
200 }
201 }
202 else {
203 brhist_init(gf, 128, 128); /* Dirty hack */
204 }
205 }
206
207
208 void
encoder_progress_begin(lame_global_flags const * gf,char const * inPath,char const * outPath)209 encoder_progress_begin( lame_global_flags const* gf
210 , char const* inPath
211 , char const* outPath
212 )
213 {
214 brhist_init_package(gf);
215 global_encoder_progress.time_status_init = 0;
216 global_encoder_progress.last_time = 0;
217 global_encoder_progress.last_frame_num = 0;
218 if (global_ui_config.silent < 9) {
219 char* i_file = 0;
220 char* o_file = 0;
221 #if defined( _WIN32 ) && !defined(__MINGW32__)
222 inPath = i_file = utf8ToLocal8Bit(inPath);
223 outPath = o_file = utf8ToConsole8Bit(outPath);
224 #endif
225 lame_print_config(gf); /* print useful information about options being used */
226
227 console_printf("Encoding %s%s to %s\n",
228 strcmp(inPath, "-") ? inPath : "<stdin>",
229 strlen(inPath) + strlen(outPath) < 66 ? "" : "\n ",
230 strcmp(outPath, "-") ? outPath : "<stdout>");
231
232 free(i_file);
233 free(o_file);
234
235 console_printf("Encoding as %g kHz ", 1.e-3 * lame_get_out_samplerate(gf));
236
237 {
238 static const char *mode_names[2][4] = {
239 {"stereo", "j-stereo", "dual-ch", "single-ch"},
240 {"stereo", "force-ms", "dual-ch", "single-ch"}
241 };
242 switch (lame_get_VBR(gf)) {
243 case vbr_rh:
244 console_printf("%s MPEG-%u%s Layer III VBR(q=%g) qval=%i\n",
245 mode_names[lame_get_force_ms(gf)][lame_get_mode(gf)],
246 2 - lame_get_version(gf),
247 lame_get_out_samplerate(gf) < 16000 ? ".5" : "",
248 lame_get_VBR_quality(gf),
249 lame_get_quality(gf));
250 break;
251 case vbr_mt:
252 case vbr_mtrh:
253 console_printf("%s MPEG-%u%s Layer III VBR(q=%g)\n",
254 mode_names[lame_get_force_ms(gf)][lame_get_mode(gf)],
255 2 - lame_get_version(gf),
256 lame_get_out_samplerate(gf) < 16000 ? ".5" : "",
257 lame_get_VBR_quality(gf));
258 break;
259 case vbr_abr:
260 console_printf("%s MPEG-%u%s Layer III (%gx) average %d kbps qval=%i\n",
261 mode_names[lame_get_force_ms(gf)][lame_get_mode(gf)],
262 2 - lame_get_version(gf),
263 lame_get_out_samplerate(gf) < 16000 ? ".5" : "",
264 0.1 * (int) (10. * lame_get_compression_ratio(gf) + 0.5),
265 lame_get_VBR_mean_bitrate_kbps(gf),
266 lame_get_quality(gf));
267 break;
268 default:
269 console_printf("%s MPEG-%u%s Layer III (%gx) %3d kbps qval=%i\n",
270 mode_names[lame_get_force_ms(gf)][lame_get_mode(gf)],
271 2 - lame_get_version(gf),
272 lame_get_out_samplerate(gf) < 16000 ? ".5" : "",
273 0.1 * (int) (10. * lame_get_compression_ratio(gf) + 0.5),
274 lame_get_brate(gf),
275 lame_get_quality(gf));
276 break;
277 }
278 }
279
280 if (global_ui_config.silent <= -10) {
281 lame_print_internals(gf);
282 }
283 }
284 }
285
286 void
encoder_progress(lame_global_flags const * gf)287 encoder_progress( lame_global_flags const* gf )
288 {
289 if (global_ui_config.silent <= 0) {
290 int const frames = lame_get_frameNum(gf);
291 int const frames_diff = frames - global_encoder_progress.last_frame_num;
292 if (global_ui_config.update_interval <= 0) { /* most likely --disptime x not used */
293 if (frames_diff < 100 && frames_diff != 0) { /* true, most of the time */
294 return;
295 }
296 global_encoder_progress.last_frame_num = (frames/100)*100;
297 }
298 else {
299 if (frames != 0 && frames != 9) {
300 double const act = GetRealTime();
301 double const dif = act - global_encoder_progress.last_time;
302 if (dif >= 0 && dif < global_ui_config.update_interval) {
303 return;
304 }
305 }
306 global_encoder_progress.last_time = GetRealTime(); /* from now! disp_time seconds */
307 }
308 if (global_ui_config.brhist) {
309 brhist_jump_back();
310 }
311 timestatus(gf);
312 if (global_ui_config.brhist) {
313 brhist_disp(gf);
314 }
315 console_flush();
316 }
317 }
318
319 void
encoder_progress_end(lame_global_flags const * gf)320 encoder_progress_end( lame_global_flags const* gf )
321 {
322 if (global_ui_config.silent <= 0) {
323 if (global_ui_config.brhist) {
324 brhist_jump_back();
325 }
326 timestatus(gf);
327 if (global_ui_config.brhist) {
328 brhist_disp(gf);
329 }
330 timestatus_finish();
331 }
332 }
333
334
335 /* these functions are used in get_audio.c */
336 static struct DecoderProgress {
337 int last_mode_ext;
338 int frames_total;
339 int frame_ctr;
340 int framesize;
341 unsigned long samples;
342 } global_decoder_progress;
343
344 static
calcEndPadding(unsigned long samples,int pcm_samples_per_frame)345 unsigned long calcEndPadding(unsigned long samples, int pcm_samples_per_frame)
346 {
347 unsigned long end_padding;
348 samples += 576;
349 end_padding = pcm_samples_per_frame - (samples % pcm_samples_per_frame);
350 if (end_padding < 576)
351 end_padding += pcm_samples_per_frame;
352 return end_padding;
353 }
354
355 static
calcNumBlocks(unsigned long samples,int pcm_samples_per_frame)356 unsigned long calcNumBlocks(unsigned long samples, int pcm_samples_per_frame)
357 {
358 unsigned long end_padding;
359 samples += 576;
360 end_padding = pcm_samples_per_frame - (samples % pcm_samples_per_frame);
361 if (end_padding < 576)
362 end_padding += pcm_samples_per_frame;
363 return (samples + end_padding) / pcm_samples_per_frame;
364 }
365
366 DecoderProgress
decoder_progress_init(unsigned long n,int framesize)367 decoder_progress_init(unsigned long n, int framesize)
368 {
369 DecoderProgress dp = &global_decoder_progress;
370 dp->last_mode_ext =0;
371 dp->frames_total = 0;
372 dp->frame_ctr = 0;
373 dp->framesize = framesize;
374 dp->samples = 0;
375 if (n != (0ul-1ul)) {
376 if (framesize == 576 || framesize == 1152) {
377 dp->frames_total = calcNumBlocks(n, framesize);
378 dp->samples = 576 + calcEndPadding(n, framesize);
379 }
380 else if (framesize > 0) {
381 dp->frames_total = n / framesize;
382 }
383 else {
384 dp->frames_total = n;
385 }
386 }
387 return dp;
388 }
389
390 static void
addSamples(DecoderProgress dp,int iread)391 addSamples(DecoderProgress dp, int iread)
392 {
393 dp->samples += iread;
394 dp->frame_ctr += dp->samples / dp->framesize;
395 dp->samples %= dp->framesize;
396 if (dp->frames_total < dp->frame_ctr) {
397 dp->frames_total = dp->frame_ctr;
398 }
399 }
400
401 void
decoder_progress(DecoderProgress dp,const mp3data_struct * mp3data,int iread)402 decoder_progress(DecoderProgress dp, const mp3data_struct * mp3data, int iread)
403 {
404 addSamples(dp, iread);
405
406 console_printf("\rFrame#%6i/%-6i %3i kbps",
407 dp->frame_ctr, dp->frames_total, mp3data->bitrate);
408
409 /* Programmed with a single frame hold delay */
410 /* Attention: static data */
411
412 /* MP2 Playback is still buggy. */
413 /* "'00' subbands 4-31 in intensity_stereo, bound==4" */
414 /* is this really intensity_stereo or is it MS stereo? */
415
416 if (mp3data->mode == JOINT_STEREO) {
417 int curr = mp3data->mode_ext;
418 int last = dp->last_mode_ext;
419 console_printf(" %s %c",
420 curr & 2 ? last & 2 ? " MS " : "LMSR" : last & 2 ? "LMSR" : "L R",
421 curr & 1 ? last & 1 ? 'I' : 'i' : last & 1 ? 'i' : ' ');
422 dp->last_mode_ext = curr;
423 }
424 else {
425 console_printf(" ");
426 dp->last_mode_ext = 0;
427 }
428 /* console_printf ("%s", Console_IO.str_clreoln ); */
429 console_printf(" \b\b\b\b\b\b\b\b");
430 console_flush();
431 }
432
433 void
decoder_progress_finish(DecoderProgress dp)434 decoder_progress_finish(DecoderProgress dp)
435 {
436 (void) dp;
437 console_printf("\n");
438 }
439