static void print_report(int is_last_report, int64_t timer_start) { char buf[1024]; OutputStream *ost; AVFormatContext *oc; int64_t total_size; AVCodecContext *enc; int frame_number, vid, i; double bitrate, ti1, pts; static int64_t last_time = -1; static int qp_histogram[52]; if (!print_stats && !is_last_report) return; if (!is_last_report) { int64_t cur_time; /* display the report every 0.5 seconds */ cur_time = av_gettime(); if (last_time == -1) { last_time = cur_time; return; } if ((cur_time - last_time) < 500000) return; last_time = cur_time; } oc = output_files[0]->ctx; total_size = avio_size(oc->pb); if (total_size <= 0) // FIXME improve avio_size() so it works with non seekable output too total_size = avio_tell(oc->pb); if (total_size < 0) { char errbuf[128]; av_strerror(total_size, errbuf, sizeof(errbuf)); av_log(NULL, AV_LOG_VERBOSE, "Bitrate not available, " "avio_tell() failed: %s\n", errbuf); total_size = 0; } buf[0] = '\0'; ti1 = 1e10; vid = 0; for (i = 0; i < nb_output_streams; i++) { float q = -1; ost = output_streams[i]; enc = ost->st->codec; if (!ost->stream_copy && enc->coded_frame) q = enc->coded_frame->quality / (float)FF_QP2LAMBDA; if (vid && enc->codec_type == AVMEDIA_TYPE_VIDEO) { snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "q=%2.1f ", q); } if (!vid && enc->codec_type == AVMEDIA_TYPE_VIDEO) { float t = (av_gettime() - timer_start) / 1000000.0; frame_number = ost->frame_number; snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "frame=%5d fps=%3d q=%3.1f ", frame_number, (t > 1) ? (int)(frame_number / t + 0.5) : 0, q); if (is_last_report) snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "L"); if (qp_hist) { int j; int qp = lrintf(q); if (qp >= 0 && qp < FF_ARRAY_ELEMS(qp_histogram)) qp_histogram[qp]++; for (j = 0; j < 32; j++) snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%X", (int)lrintf(log2(qp_histogram[j] + 1))); } if (enc->flags&CODEC_FLAG_PSNR) { int j; double error, error_sum = 0; double scale, scale_sum = 0; char type[3] = { 'Y','U','V' }; snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "PSNR="); for (j = 0; j < 3; j++) { if (is_last_report) { error = enc->error[j]; scale = enc->width * enc->height * 255.0 * 255.0 * frame_number; } else { error = enc->coded_frame->error[j]; scale = enc->width * enc->height * 255.0 * 255.0; } if (j) scale /= 4; error_sum += error; scale_sum += scale; snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%c:%2.2f ", type[j], psnr(error / scale)); } snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "*:%2.2f ", psnr(error_sum / scale_sum)); } vid = 1; } /* compute min output value */ pts = (double)ost->st->pts.val * av_q2d(ost->st->time_base); if ((pts < ti1) && (pts > 0)) ti1 = pts; } if (ti1 < 0.01) ti1 = 0.01; bitrate = (double)(total_size * 8) / ti1 / 1000.0; snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "size=%8.0fkB time=%0.2f bitrate=%6.1fkbits/s", (double)total_size / 1024, ti1, bitrate); if (nb_frames_dup || nb_frames_drop) snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " dup=%d drop=%d", nb_frames_dup, nb_frames_drop); av_log(NULL, AV_LOG_INFO, "%s \r", buf); fflush(stderr); if (is_last_report) { int64_t raw= audio_size + video_size + extra_size; av_log(NULL, AV_LOG_INFO, "\n"); av_log(NULL, AV_LOG_INFO, "video:%1.0fkB audio:%1.0fkB global headers:%1.0fkB muxing overhead %f%%\n", video_size / 1024.0, audio_size / 1024.0, extra_size / 1024.0, 100.0 * (total_size - raw) / raw ); } }