1/* 2 * Bitrate histogram source file 3 * 4 * Copyright (c) 2000 Mark Taylor 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Library General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library 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 * Library General Public License for more details. 15 * 16 * You should have received a copy of the GNU Library General Public 17 * License along with this library; if not, write to the 18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 * Boston, MA 02111-1307, USA. 20 */ 21 22/* $Id$ */ 23 24#ifdef HAVE_CONFIG_H 25#include <config.h> 26#endif 27 28/* basic #define's */ 29 30#ifndef BRHIST_WIDTH 31# define BRHIST_WIDTH 14 32#endif 33#ifndef BRHIST_RES 34# define BRHIST_RES 14 35#endif 36 37 38/* #includes */ 39 40#ifdef STDC_HEADERS 41# include <stdio.h> 42# include <stdlib.h> 43# include <string.h> 44#endif 45 46#include "brhist.h" 47#include "console.h" 48 49#ifdef WITH_DMALLOC 50#include <dmalloc.h> 51#endif 52 53 54/* Structure holding all data related to the Console I/O 55 * may be this should be a more global frontend structure. So it 56 * makes sense to print all files instead with 57 * printf ( "blah\n") with printf ( "blah%s\n", Console_IO.str_clreoln ); 58 */ 59 60extern Console_IO_t Console_IO; 61 62static struct brhist_struct { 63 int vbr_bitrate_min_index; 64 int vbr_bitrate_max_index; 65 int kbps[BRHIST_WIDTH]; 66 int hist_printed_lines; 67 char bar_asterisk[512 + 1]; /* buffer filled up with a lot of '*' to print a bar */ 68 char bar_percent[512 + 1]; /* buffer filled up with a lot of '%' to print a bar */ 69 char bar_coded[512 + 1]; /* buffer filled up with a lot of ' ' to print a bar */ 70 char bar_space[512 + 1]; /* buffer filled up with a lot of ' ' to print a bar */ 71} brhist; 72 73static int 74calculate_index(const int *const array, const int len, const int value) 75{ 76 int i; 77 78 for (i = 0; i < len; i++) 79 if (array[i] == value) 80 return i; 81 return -1; 82} 83 84int 85brhist_init(const lame_global_flags * gf, const int bitrate_kbps_min, const int bitrate_kbps_max) 86{ 87 brhist.hist_printed_lines = 0; 88 89 /* initialize histogramming data structure */ 90 lame_bitrate_kbps(gf, brhist.kbps); 91 brhist.vbr_bitrate_min_index = calculate_index(brhist.kbps, BRHIST_WIDTH, bitrate_kbps_min); 92 brhist.vbr_bitrate_max_index = calculate_index(brhist.kbps, BRHIST_WIDTH, bitrate_kbps_max); 93 94 if (brhist.vbr_bitrate_min_index >= BRHIST_WIDTH || 95 brhist.vbr_bitrate_max_index >= BRHIST_WIDTH) { 96 error_printf("lame internal error: VBR min %d kbps or VBR max %d kbps not allowed.\n", 97 bitrate_kbps_min, bitrate_kbps_max); 98 return -1; 99 } 100 101 memset(brhist.bar_asterisk, '*', sizeof(brhist.bar_asterisk) - 1); 102 memset(brhist.bar_percent, '%', sizeof(brhist.bar_percent) - 1); 103 memset(brhist.bar_space, '-', sizeof(brhist.bar_space) - 1); 104 memset(brhist.bar_coded, '-', sizeof(brhist.bar_space) - 1); 105 106 return 0; 107} 108 109static int 110digits(unsigned number) 111{ 112 int ret = 1; 113 114 if (number >= 100000000) { 115 ret += 8; 116 number /= 100000000; 117 } 118 if (number >= 10000) { 119 ret += 4; 120 number /= 10000; 121 } 122 if (number >= 100) { 123 ret += 2; 124 number /= 100; 125 } 126 if (number >= 10) { 127 ret += 1; 128 } 129 130 return ret; 131} 132 133 134static void 135brhist_disp_line(int i, int br_hist_TOT, int br_hist_LR, int full, int frames) 136{ 137 char brppt[14]; /* [%] and max. 10 characters for kbps */ 138 int barlen_TOT; 139 int barlen_LR; 140 int res = digits(frames) + 3 + 4 + 1; 141 142 if (full != 0) { 143 /* some problems when br_hist_TOT \approx br_hist_LR: You can't see that there are still MS frames */ 144 barlen_TOT = (br_hist_TOT * (Console_IO.disp_width - res) + full - 1) / full; /* round up */ 145 barlen_LR = (br_hist_LR * (Console_IO.disp_width - res) + full - 1) / full; /* round up */ 146 } 147 else { 148 barlen_TOT = barlen_LR = 0; 149 } 150 151 sprintf(brppt, " [%*i]", digits(frames), br_hist_TOT); 152 153 if (Console_IO.str_clreoln[0]) /* ClearEndOfLine available */ 154 console_printf("\n%3d%s %.*s%.*s%s", 155 brhist.kbps[i], brppt, 156 barlen_LR, brhist.bar_percent, 157 barlen_TOT - barlen_LR, brhist.bar_asterisk, Console_IO.str_clreoln); 158 else 159 console_printf("\n%3d%s %.*s%.*s%*s", 160 brhist.kbps[i], brppt, 161 barlen_LR, brhist.bar_percent, 162 barlen_TOT - barlen_LR, brhist.bar_asterisk, 163 Console_IO.disp_width - res - barlen_TOT, ""); 164 165 brhist.hist_printed_lines++; 166} 167 168 169 170static void 171progress_line(const lame_global_flags * gf, int full, int frames) 172{ 173 char rst[20] = "\0"; 174 int barlen_TOT = 0, barlen_COD = 0, barlen_RST = 0; 175 int res = 1; 176 float time_in_sec = 0; 177 unsigned int hour, min, sec; 178 int fsize = lame_get_framesize(gf); 179 int srate = lame_get_out_samplerate(gf); 180 181 if (full < frames) { 182 full = frames; 183 } 184 if (srate > 0) { 185 time_in_sec = (float)(full - frames); 186 time_in_sec *= fsize; 187 time_in_sec /= srate; 188 } 189 hour = (unsigned int)(time_in_sec / 3600); 190 time_in_sec -= hour * 3600; 191 min = (unsigned int)(time_in_sec / 60); 192 time_in_sec -= min * 60; 193 sec = (unsigned int)time_in_sec; 194 if (full != 0) { 195 if (hour > 0) { 196 sprintf(rst, "%*u:%02u:%02u", digits(hour), hour, min, sec); 197 res += digits(hour) + 1 + 5; 198 } 199 else { 200 sprintf(rst, "%02u:%02u", min, sec); 201 res += 5; 202 } 203 /* some problems when br_hist_TOT \approx br_hist_LR: You can't see that there are still MS frames */ 204 barlen_TOT = (full * (Console_IO.disp_width - res) + full - 1) / full; /* round up */ 205 barlen_COD = (frames * (Console_IO.disp_width - res) + full - 1) / full; /* round up */ 206 barlen_RST = barlen_TOT - barlen_COD; 207 if (barlen_RST == 0) { 208 sprintf(rst, "%.*s", res - 1, brhist.bar_coded); 209 } 210 } 211 else { 212 barlen_TOT = barlen_COD = barlen_RST = 0; 213 } 214 if (Console_IO.str_clreoln[0]) { /* ClearEndOfLine available */ 215 console_printf("\n%.*s%s%.*s%s", 216 barlen_COD, brhist.bar_coded, 217 rst, barlen_RST, brhist.bar_space, Console_IO.str_clreoln); 218 } 219 else { 220 console_printf("\n%.*s%s%.*s%*s", 221 barlen_COD, brhist.bar_coded, 222 rst, barlen_RST, brhist.bar_space, Console_IO.disp_width - res - barlen_TOT, 223 ""); 224 } 225 brhist.hist_printed_lines++; 226} 227 228 229static int 230stats_value(double x) 231{ 232 if (x > 0.0) { 233 console_printf(" %5.1f", x); 234 return 6; 235 } 236 return 0; 237} 238 239static int 240stats_head(double x, const char *txt) 241{ 242 if (x > 0.0) { 243 console_printf(txt); 244 return 6; 245 } 246 return 0; 247} 248 249 250static void 251stats_line(double *stat) 252{ 253 int n = 1; 254 console_printf("\n kbps "); 255 n += 12; 256 n += stats_head(stat[1], " mono"); 257 n += stats_head(stat[2], " IS "); 258 n += stats_head(stat[3], " LR "); 259 n += stats_head(stat[4], " MS "); 260 console_printf(" %% "); 261 n += 6; 262 n += stats_head(stat[5], " long "); 263 n += stats_head(stat[6], "switch"); 264 n += stats_head(stat[7], " short"); 265 n += stats_head(stat[8], " mixed"); 266 n += console_printf(" %%"); 267 if (Console_IO.str_clreoln[0]) { /* ClearEndOfLine available */ 268 console_printf("%s", Console_IO.str_clreoln); 269 } 270 else { 271 console_printf("%*s", Console_IO.disp_width - n, ""); 272 } 273 brhist.hist_printed_lines++; 274 275 n = 1; 276 console_printf("\n %5.1f ", stat[0]); 277 n += 12; 278 n += stats_value(stat[1]); 279 n += stats_value(stat[2]); 280 n += stats_value(stat[3]); 281 n += stats_value(stat[4]); 282 console_printf(" "); 283 n += 6; 284 n += stats_value(stat[5]); 285 n += stats_value(stat[6]); 286 n += stats_value(stat[7]); 287 n += stats_value(stat[8]); 288 if (Console_IO.str_clreoln[0]) { /* ClearEndOfLine available */ 289 console_printf("%s", Console_IO.str_clreoln); 290 } 291 else { 292 console_printf("%*s", Console_IO.disp_width - n, ""); 293 } 294 brhist.hist_printed_lines++; 295} 296 297 298/* Yes, not very good */ 299#define LR 0 300#define MS 2 301 302void 303brhist_disp(const lame_global_flags * gf) 304{ 305 int i, lines_used = 0; 306 int br_hist[BRHIST_WIDTH]; /* how often a frame size was used */ 307 int br_sm_hist[BRHIST_WIDTH][4]; /* how often a special frame size/stereo mode commbination was used */ 308 int st_mode[4]; 309 int bl_type[6]; 310 int frames; /* total number of encoded frames */ 311 int most_often; /* usage count of the most often used frame size, but not smaller than Console_IO.disp_width-BRHIST_RES (makes this sense?) and 1 */ 312 double sum = 0.; 313 314 double stat[9] = { 0 }; 315 int st_frames = 0; 316 317 318 brhist.hist_printed_lines = 0; /* printed number of lines for the brhist functionality, used to skip back the right number of lines */ 319 320 lame_bitrate_stereo_mode_hist(gf, br_sm_hist); 321 lame_bitrate_hist(gf, br_hist); 322 lame_stereo_mode_hist(gf, st_mode); 323 lame_block_type_hist(gf, bl_type); 324 325 frames = most_often = 0; 326 for (i = 0; i < BRHIST_WIDTH; i++) { 327 frames += br_hist[i]; 328 sum += br_hist[i] * brhist.kbps[i]; 329 if (most_often < br_hist[i]) 330 most_often = br_hist[i]; 331 if (br_hist[i]) 332 ++lines_used; 333 } 334 335 for (i = 0; i < BRHIST_WIDTH; i++) { 336 int show = br_hist[i]; 337 show = show && (lines_used > 1); 338 if (show || (i >= brhist.vbr_bitrate_min_index && i <= brhist.vbr_bitrate_max_index)) 339 brhist_disp_line(i, br_hist[i], br_sm_hist[i][LR], most_often, frames); 340 } 341 for (i = 0; i < 4; i++) { 342 st_frames += st_mode[i]; 343 } 344 if (frames > 0) { 345 stat[0] = sum / frames; 346 stat[1] = 100. * (frames - st_frames) / frames; 347 } 348 if (st_frames > 0) { 349 stat[2] = 0.0; 350 stat[3] = 100. * st_mode[LR] / st_frames; 351 stat[4] = 100. * st_mode[MS] / st_frames; 352 } 353 if (bl_type[5] > 0) { 354 stat[5] = 100. * bl_type[0] / bl_type[5]; 355 stat[6] = 100. * (bl_type[1] + bl_type[3]) / bl_type[5]; 356 stat[7] = 100. * bl_type[2] / bl_type[5]; 357 stat[8] = 100. * bl_type[4] / bl_type[5]; 358 } 359 progress_line(gf, lame_get_totalframes(gf), frames); 360 stats_line(stat); 361} 362 363void 364brhist_jump_back(void) 365{ 366 console_up(brhist.hist_printed_lines); 367 brhist.hist_printed_lines = 0; 368} 369 370/* 371 * 1) 372 * 373 * Taken from Termcap_Manual.html: 374 * 375 * With the Unix version of termcap, you must allocate space for the description yourself and pass 376 * the address of the space as the argument buffer. There is no way you can tell how much space is 377 * needed, so the convention is to allocate a buffer 2048 characters long and assume that is 378 * enough. (Formerly the convention was to allocate 1024 characters and assume that was enough. 379 * But one day, for one kind of terminal, that was not enough.) 380 */ 381 382 383