1 /*
2 * This file is part of cyanrip.
3 *
4 * cyanrip is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * cyanrip is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with cyanrip; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include <stdarg.h>
20 #include <time.h>
21 #include <pthread.h>
22
23 #include <libavutil/avutil.h>
24
25 #include "cyanrip_encode.h"
26 #include "cyanrip_log.h"
27 #include "accurip.h"
28
29 #define CLOG(FORMAT, DICT, TAG) \
30 if (dict_get(DICT, TAG)) \
31 cyanrip_log(ctx, 0, FORMAT, dict_get(DICT, TAG)); \
32
print_offsets(cyanrip_ctx * ctx,cyanrip_track * t)33 static void print_offsets(cyanrip_ctx *ctx, cyanrip_track *t)
34 {
35 if (t->pregap_lsn != CDIO_INVALID_LSN)
36 cyanrip_log(ctx, 0, " Pregap LSN: %i\n", t->pregap_lsn);
37
38 if (t->frames_before_disc_start)
39 cyanrip_log(ctx, 0, " Silent frames: %i prepended\n", t->frames_before_disc_start);
40 cyanrip_log(ctx, 0, " Start LSN: %i\n", t->start_lsn_sig);
41 if (t->start_lsn != t->start_lsn_sig)
42 cyanrip_log(ctx, 0, " Offset start: %i\n", t->start_lsn);
43
44 cyanrip_log(ctx, 0, " End LSN: %i\n", t->end_lsn_sig);
45 if (t->end_lsn != t->end_lsn_sig)
46 cyanrip_log(ctx, 0, " Offset end: %i\n", t->end_lsn);
47 if (t->frames_after_disc_end)
48 cyanrip_log(ctx, 0, " Silent frames: %i appended\n", t->frames_after_disc_end);
49 }
50
cyanrip_log_track_end(cyanrip_ctx * ctx,cyanrip_track * t)51 void cyanrip_log_track_end(cyanrip_ctx *ctx, cyanrip_track *t)
52 {
53 char length[16];
54 cyanrip_samples_to_duration(t->nb_samples, length);
55
56 if (t->track_is_data) {
57 cyanrip_log(ctx, 0, " Data bytes: %i (%.2f Mib)\n",
58 t->frames*CDIO_CD_FRAMESIZE_RAW,
59 t->frames*CDIO_CD_FRAMESIZE_RAW / (1024.0 * 1024.0));
60 cyanrip_log(ctx, 0, " Frames: %u\n", t->end_lsn_sig - t->start_lsn_sig + 1);
61 print_offsets(ctx, t);
62 cyanrip_log(ctx, 0, "\n");
63 return;
64 }
65
66 cyanrip_log(ctx, 0, " File(s):\n");
67 for (int f = 0; f < ctx->settings.outputs_num; f++) {
68 char *path = crip_get_path(ctx, CRIP_PATH_TRACK, 0,
69 &crip_fmt_info[ctx->settings.outputs[f]],
70 t);
71 cyanrip_log(ctx, 0, " %s\n", path);
72 av_free(path);
73 }
74
75 cyanrip_log(ctx, 0, " Metadata:\n", length);
76
77 const AVDictionaryEntry *d = NULL;
78 while ((d = av_dict_get(t->meta, "", d, AV_DICT_IGNORE_SUFFIX)))
79 cyanrip_log(ctx, 0, " %s: %s\n", d->key, d->value);
80
81 if (t->preemphasis)
82 cyanrip_log(ctx, 0, " Preemphasis: present, deemphasis required\n");
83 if (t->art.source_url || ctx->nb_cover_arts) {
84 const char *codec_name = NULL;
85 CRIPArt *art = &t->art;
86 if (!art->source_url) {
87 int i;
88 for (i = 0; i < ctx->nb_cover_arts; i++)
89 if (!strcmp(dict_get(ctx->cover_arts[i].meta, "title"), "Front"))
90 break;
91 art = &ctx->cover_arts[i == ctx->nb_cover_arts ? 0 : i];
92 }
93
94 if (art->pkt && art->params) {
95 const AVCodecDescriptor *cd = avcodec_descriptor_get(art->params->codec_id);
96 if (cd)
97 codec_name = cd->long_name;
98 else
99 codec_name = avcodec_get_name(art->params->codec_id);
100 }
101
102 cyanrip_log(ctx, 0, " Cover art: %s\n",
103 codec_name ? codec_name :
104 (t->art.source_url ? art->source_url : dict_get(art->meta, "title")));
105 }
106 cyanrip_log(ctx, 0, " Duration: %s\n", length);
107 cyanrip_log(ctx, 0, " Samples: %u\n", t->nb_samples);
108 cyanrip_log(ctx, 0, " Frames: %u\n", t->end_lsn_sig - t->start_lsn_sig + 1);
109
110 print_offsets(ctx, t);
111
112 int has_ar = t->ar_db_status == CYANRIP_ACCUDB_FOUND;
113
114 if (!ctx->settings.disable_accurip) {
115 cyanrip_log(ctx, 0, " Accurip: %s", has_ar ? "found" : "not found");
116 if (has_ar)
117 cyanrip_log(ctx, 0, " (max confidence: %i)\n", t->ar_db_max_confidence);
118 else
119 cyanrip_log(ctx, 0, "\n");
120 }
121
122 if (t->computed_crcs) {
123 cyanrip_log(ctx, 0, " EAC CRC32: %08X\n", t->eac_crc);
124
125 int match_v1 = has_ar ? crip_find_ar(t, t->acurip_checksum_v1, 0) : 0;
126 int match_v2 = has_ar ? crip_find_ar(t, t->acurip_checksum_v2, 0) : 0;
127
128 cyanrip_log(ctx, 0, " Accurip v1: %08X", t->acurip_checksum_v1);
129 if (has_ar && match_v1 > 0)
130 cyanrip_log(ctx, 0, " (accurately ripped, confidence %i)\n", match_v1);
131 else if (has_ar && (match_v2 < 1))
132 cyanrip_log(ctx, 0, " (not found in the Accurip database)\n");
133 else
134 cyanrip_log(ctx, 0, "\n");
135
136 cyanrip_log(ctx, 0, " Accurip v2: %08X", t->acurip_checksum_v2);
137 if (has_ar && (match_v2 > 0))
138 cyanrip_log(ctx, 0, " (accurately ripped, confidence %i)\n", match_v2);
139 else if (has_ar && (match_v1 < 0))
140 cyanrip_log(ctx, 0, " (not found in the Accurip database)\n");
141 else
142 cyanrip_log(ctx, 0, "\n");
143
144 if (!has_ar || ((match_v1 < 0) && (match_v2 < 0))) {
145 int match_450 = has_ar ? crip_find_ar(t, t->acurip_checksum_v1_450, 1) : 0;
146 cyanrip_log(ctx, 0, " Accurip v1 450: %08X", t->acurip_checksum_v1_450);
147 if (has_ar && (match_450 > (3*(t->ar_db_max_confidence+1)/4)) && (t->acurip_checksum_v1_450 == 0x0))
148 cyanrip_log(ctx, 0, " (match found, confidence %i, but a checksum of 0 is meaningless)\n",
149 match_450, t->ar_db_max_confidence);
150 else if (has_ar && (match_450 > (3*(t->ar_db_max_confidence+1)/4)))
151 cyanrip_log(ctx, 0, " (matches Accurip DB, confidence %i, track is partially accurately ripped)\n",
152 match_450, t->ar_db_max_confidence);
153 else if (has_ar)
154 cyanrip_log(ctx, 0, " (not found in the Accurip database)\n");
155 else
156 cyanrip_log(ctx, 0, "\n");
157 }
158 }
159
160 cyanrip_log(ctx, 0, "\n");
161 }
162
cyanrip_log_start_report(cyanrip_ctx * ctx)163 void cyanrip_log_start_report(cyanrip_ctx *ctx)
164 {
165 cyanrip_log(ctx, 0, "cyanrip %s (%s)\n", PROJECT_VERSION_STRING, vcstag);
166 cyanrip_log(ctx, 0, "System device: %s\n", ctx->settings.dev_path);
167 if (ctx->drive->drive_model)
168 cyanrip_log(ctx, 0, "Device model: %s\n", ctx->drive->drive_model);
169 cyanrip_log(ctx, 0, "Offset: %c%i %s\n", ctx->settings.offset >= 0 ? '+' : '-', abs(ctx->settings.offset),
170 abs(ctx->settings.offset) == 1 ? "sample" : "samples");
171 cyanrip_log(ctx, 0, "%s%c%i %s\n",
172 ctx->settings.over_under_read_frames < 0 ? "Underread: " : "Overread: ",
173 ctx->settings.over_under_read_frames >= 0 ? '+' : '-',
174 abs(ctx->settings.over_under_read_frames),
175 abs(ctx->settings.over_under_read_frames) == 1 ? "frame" : "frames");
176 cyanrip_log(ctx, 0, "%s%s\n",
177 ctx->settings.over_under_read_frames < 0 ? "Underread mode: " : "Overread mode: ",
178 ctx->settings.overread_leadinout ? "read in lead-in/lead-out" : "fill with silence in lead-in/lead-out");
179 if (ctx->settings.speed && (ctx->mcap & CDIO_DRIVE_CAP_MISC_SELECT_SPEED))
180 cyanrip_log(ctx, 0, "Speed: %ix\n", ctx->settings.speed);
181 else
182 cyanrip_log(ctx, 0, "Speed: default (%s)\n",
183 (ctx->mcap & CDIO_DRIVE_CAP_MISC_SELECT_SPEED) ? "changeable" : "unchangeable");
184 cyanrip_log(ctx, 0, "C2 errors: %s by drive\n", (ctx->rcap & CDIO_DRIVE_CAP_READ_C2_ERRS) ?
185 "supported" : "unsupported");
186 if (ctx->settings.paranoia_level == crip_max_paranoia_level)
187 cyanrip_log(ctx, 0, "Paranoia level: %s\n", "max");
188 else if (ctx->settings.paranoia_level == 0)
189 cyanrip_log(ctx, 0, "Paranoia level: %s\n", "none");
190 else
191 cyanrip_log(ctx, 0, "Paranoia level: %i\n", ctx->settings.paranoia_level);
192 cyanrip_log(ctx, 0, "Frame retries: %i\n", ctx->settings.frame_max_retries);
193 cyanrip_log(ctx, 0, "HDCD decoding: %s\n", ctx->settings.decode_hdcd ? "enabled" : "disabled");
194
195 cyanrip_log(ctx, 0, "Album Art: %s", ctx->nb_cover_arts == 0 ? "none" : "");
196 for (int i = 0; i < ctx->nb_cover_arts; i++) {
197 const char *title = dict_get(ctx->cover_arts[i].meta, "title");
198 const char *source = dict_get(ctx->cover_arts[i].meta, "source");
199 cyanrip_log(ctx, 0, "%s%s%s%s%s", title,
200 source ? " (From: " : "",
201 source ? source : "",
202 source ? ")" : "",
203 i != (ctx->nb_cover_arts - 1) ? ", " : "");
204 }
205 cyanrip_log(ctx, 0, "\n");
206
207 cyanrip_log(ctx, 0, "Outputs: ");
208 for (int i = 0; i < ctx->settings.outputs_num; i++)
209 cyanrip_log(ctx, 0, "%s%s", cyanrip_fmt_desc(ctx->settings.outputs[i]), i != (ctx->settings.outputs_num - 1) ? ", " : "");
210 cyanrip_log(ctx, 0, "\n");
211 CLOG("Disc number: %s\n", ctx->meta, "disc");
212 CLOG("Total discs: %s\n", ctx->meta, "totaldiscs");
213 cyanrip_log(ctx, 0, "Disc tracks: %i\n", ctx->nb_cd_tracks);
214 cyanrip_log(ctx, 0, "Tracks to rip: %s", (ctx->settings.rip_indices_count == -1) ? "all" : !ctx->settings.rip_indices_count ? "none" : "");
215 if (ctx->settings.rip_indices_count != -1) {
216 for (int i = 0; i < ctx->settings.rip_indices_count; i++)
217 cyanrip_log(ctx, 0, "%i%s", ctx->settings.rip_indices[i], i != (ctx->settings.rip_indices_count - 1) ? ", " : "");
218 }
219 cyanrip_log(ctx, 0, "\n");
220
221 char duration[16];
222 cyanrip_frames_to_duration(ctx->duration_frames, duration);
223
224 CLOG("DiscID: %s\n", ctx->meta, "discid")
225 CLOG("Release ID: %s\n", ctx->meta, "release_id")
226 CLOG("CDDB ID: %s\n", ctx->meta, "cddb")
227 CLOG("Disc MCN: %s\n", ctx->meta, "disc_mcn")
228 CLOG("Album: %s\n", ctx->meta, "album")
229 CLOG("Album artist: %s\n", ctx->meta, "album_artist")
230
231 cyanrip_log(ctx, 0, "AccurateRip: %s\n", ctx->ar_db_status == CYANRIP_ACCUDB_ERROR ? "error" :
232 ctx->ar_db_status == CYANRIP_ACCUDB_NOT_FOUND ? "not found" :
233 ctx->ar_db_status == CYANRIP_ACCUDB_FOUND ? "found" :
234 ctx->ar_db_status == CYANRIP_ACCUDB_MISMATCH ? "mismatch" :
235 "disabled");
236
237 cyanrip_log(ctx, 0, "Total time: %s\n", duration);
238
239 cyanrip_log(ctx, 0, "\n");
240 }
241
cyanrip_log_finish_report(cyanrip_ctx * ctx)242 void cyanrip_log_finish_report(cyanrip_ctx *ctx)
243 {
244 char t_s[64];
245 time_t t_c = time(NULL);
246 struct tm *t_l = localtime(&t_c);
247 strftime(t_s, sizeof(t_s), "%Y-%m-%dT%H:%M:%S", t_l);
248
249 if (ctx->ar_db_status == CYANRIP_ACCUDB_FOUND) {
250 int accurip_verified = 0;
251 int accurip_partial = 0;
252 for (int i = 0; i < ctx->nb_tracks; i++) {
253 cyanrip_track *t = &ctx->tracks[i];
254 if (t->ar_db_status == CYANRIP_ACCUDB_FOUND) {
255 if ((crip_find_ar(t, t->acurip_checksum_v1, 0) > 0) ||
256 (crip_find_ar(t, t->acurip_checksum_v2, 0) > 0))
257 accurip_verified++;
258 else if (crip_find_ar(t, t->acurip_checksum_v1_450, 1) > (3*(t->ar_db_max_confidence+1)/4) &&
259 t->acurip_checksum_v1_450)
260 accurip_partial++;
261 }
262 }
263 cyanrip_log(ctx, 0, "Tracks ripped accurately: %i/%i\n", accurip_verified, ctx->nb_tracks);
264 if (accurip_partial)
265 cyanrip_log(ctx, 0, "Tracks ripped partially accurately: %i/%i\n",
266 accurip_partial, ctx->nb_tracks - accurip_verified);
267 cyanrip_log(ctx, 0, "\n");
268 }
269
270 cyanrip_log(ctx, 0, "Paranoia status counts:\n");
271
272 #define PCHECK(PROP) \
273 if (paranoia_status[PARANOIA_CB_ ## PROP]) { \
274 const char *pstr = " " #PROP ": "; \
275 cyanrip_log(ctx, 0, "%s", pstr); \
276 int padding = strlen(" FIXUP_DROPPED: ") - strlen(pstr); \
277 for (int i = 0; i < padding; i++) \
278 cyanrip_log(ctx, 0, " "); \
279 cyanrip_log(ctx, 0, "%lu\n", paranoia_status[PARANOIA_CB_ ## PROP]); \
280 }
281
282 PCHECK(READ)
283 PCHECK(VERIFY)
284 PCHECK(FIXUP_EDGE)
285 PCHECK(FIXUP_ATOM)
286 PCHECK(SCRATCH)
287 PCHECK(REPAIR)
288 PCHECK(SKIP)
289 PCHECK(DRIFT)
290 PCHECK(BACKOFF)
291 PCHECK(OVERLAP)
292 PCHECK(FIXUP_DROPPED)
293 PCHECK(FIXUP_DUPED)
294 PCHECK(READERR)
295 PCHECK(CACHEERR)
296 PCHECK(WROTE)
297 PCHECK(FINISHED)
298 cyanrip_log(ctx, 0, "\n");
299
300 #undef PCHECK
301
302 cyanrip_log(ctx, 0, "Ripping errors: %i\n", ctx->total_error_count);
303 cyanrip_log(ctx, 0, "Ripping finished at %s\n", t_s);
304 }
305
cyanrip_log_init(cyanrip_ctx * ctx)306 int cyanrip_log_init(cyanrip_ctx *ctx)
307 {
308 for (int i = 0; i < ctx->settings.outputs_num; i++) {
309 char *logfile = crip_get_path(ctx, CRIP_PATH_LOG, 1,
310 &crip_fmt_info[ctx->settings.outputs[i]],
311 NULL);
312
313 ctx->logfile[i] = av_fopen_utf8(logfile, "w");
314
315 if (!ctx->logfile) {
316 cyanrip_log(ctx, 0, "Error opening log file \"%s\" to write to!\n", logfile);
317 av_freep(&logfile);
318 return 1;
319 }
320
321 av_freep(&logfile);
322 }
323
324 return 0;
325 }
326
cyanrip_log_end(cyanrip_ctx * ctx)327 void cyanrip_log_end(cyanrip_ctx *ctx)
328 {
329 for (int i = 0; i < ctx->settings.outputs_num; i++) {
330 if (!ctx->logfile[i])
331 continue;
332
333 fclose(ctx->logfile[i]);
334 ctx->logfile[i] = NULL;
335 }
336 }
337
338 static cyanrip_ctx *av_global_ctx = NULL;
339 static int av_log_indent = 0;
340 static int av_max_log_level = AV_LOG_QUIET;
341 static pthread_mutex_t log_lock = PTHREAD_MUTEX_INITIALIZER;
342
av_log_capture(void * ptr,int lvl,const char * format,va_list args)343 static void av_log_capture(void *ptr, int lvl, const char *format,
344 va_list args)
345 {
346 pthread_mutex_lock(&log_lock);
347
348 if (lvl > av_max_log_level)
349 goto end;
350
351 if (av_global_ctx) {
352 for (int i = 0; i < av_global_ctx->settings.outputs_num; i++) {
353 if (!av_global_ctx->logfile[i])
354 continue;
355
356 for (int j = 0; j < av_log_indent; j++)
357 fprintf(av_global_ctx->logfile[i], " ");
358
359 va_list args2;
360 va_copy(args2, args);
361 vfprintf(av_global_ctx->logfile[i], format, args2);
362 va_end(args2);
363 }
364 }
365
366 for (int i = 0; i < av_log_indent; i++)
367 printf(" ");
368
369 vprintf(format, args);
370
371 end:
372 pthread_mutex_unlock(&log_lock);
373 }
374
cyanrip_set_av_log_capture(cyanrip_ctx * ctx,int enable,int indent,int max_av_lvl)375 void cyanrip_set_av_log_capture(cyanrip_ctx *ctx, int enable,
376 int indent, int max_av_lvl)
377 {
378 pthread_mutex_lock(&log_lock);
379
380 if (enable) {
381 av_global_ctx = ctx;
382 av_max_log_level = max_av_lvl;
383 av_log_indent = indent;
384 av_log_set_callback(av_log_capture);
385 } else {
386 av_log_set_callback(av_log_default_callback);
387 av_global_ctx = NULL;
388 av_log_indent = 0;
389 av_max_log_level = AV_LOG_QUIET;
390 }
391
392 pthread_mutex_unlock(&log_lock);
393 }
394
cyanrip_log(cyanrip_ctx * ctx,int verbose,const char * format,...)395 void cyanrip_log(cyanrip_ctx *ctx, int verbose, const char *format, ...)
396 {
397 pthread_mutex_lock(&log_lock);
398
399 va_list args;
400 va_start(args, format);
401
402 if (ctx) {
403 for (int i = 0; i < ctx->settings.outputs_num; i++) {
404 if (!ctx->logfile[i])
405 continue;
406
407 va_list args2;
408 va_copy(args2, args);
409 vfprintf(ctx->logfile[i], format, args2);
410 va_end(args2);
411 }
412 }
413
414 vprintf(format, args);
415
416 va_end(args);
417
418 pthread_mutex_unlock(&log_lock);
419 }
420