// dump accumulated statistics and reset accumulated values const char *vpx_svc_dump_statistics(SvcContext *svc_ctx) { int number_of_frames; int i, j; uint32_t bytes_total = 0; double scale[COMPONENTS]; double psnr[COMPONENTS]; double mse[COMPONENTS]; double y_scale; SvcInternal *const si = get_svc_internal(svc_ctx); if (svc_ctx == NULL || si == NULL) return NULL; svc_log_reset(svc_ctx); number_of_frames = si->psnr_pkt_received; if (number_of_frames <= 0) return vpx_svc_get_message(svc_ctx); svc_log(svc_ctx, SVC_LOG_INFO, "\n"); for (i = 0; i < svc_ctx->spatial_layers; ++i) { svc_log(svc_ctx, SVC_LOG_INFO, "Layer %d Average PSNR=[%2.3f, %2.3f, %2.3f, %2.3f], Bytes=[%u]\n", i, (double)si->psnr_sum[i][0] / number_of_frames, (double)si->psnr_sum[i][1] / number_of_frames, (double)si->psnr_sum[i][2] / number_of_frames, (double)si->psnr_sum[i][3] / number_of_frames, si->bytes_sum[i]); // the following psnr calculation is deduced from ffmpeg.c#print_report y_scale = si->width * si->height * 255.0 * 255.0 * number_of_frames; scale[1] = y_scale; scale[2] = scale[3] = y_scale / 4; // U or V scale[0] = y_scale * 1.5; // total for (j = 0; j < COMPONENTS; j++) { psnr[j] = calc_psnr(si->sse_sum[i][j] / scale[j]); mse[j] = si->sse_sum[i][j] * 255.0 * 255.0 / scale[j]; } svc_log(svc_ctx, SVC_LOG_INFO, "Layer %d Overall PSNR=[%2.3f, %2.3f, %2.3f, %2.3f]\n", i, psnr[0], psnr[1], psnr[2], psnr[3]); svc_log(svc_ctx, SVC_LOG_INFO, "Layer %d Overall MSE=[%2.3f, %2.3f, %2.3f, %2.3f]\n", i, mse[0], mse[1], mse[2], mse[3]); bytes_total += si->bytes_sum[i]; // clear sums for next time si->bytes_sum[i] = 0; for (j = 0; j < COMPONENTS; ++j) { si->psnr_sum[i][j] = 0; si->sse_sum[i][j] = 0; } } // only display statistics once si->psnr_pkt_received = 0; svc_log(svc_ctx, SVC_LOG_INFO, "Total Bytes=[%u]\n", bytes_total); return vpx_svc_get_message(svc_ctx); }
Uint32 diff_mode(void) { FILE* fd_tmp; Uint8* y_tmp; /* Perhaps a bit ugly but it seams to work... * 1. read frame from fd * 2. store data away * 3. read frame from P.fd2 * 4. calculate diff * 5. place result in P.raw or P.y_data depending on FORMAT * 6. diff works on luma data so clear P.cb_data and P.cr_data * Fiddle with the file descriptors so that we read * from correct file. */ if (!(*reader[FORMAT])()) { return 0; } y_tmp = malloc(sizeof(Uint8) * P.y_size); if (!y_tmp) { fprintf(stderr, "Error allocating memory...\n"); return 0; } for (Uint32 i = 0; i < P.y_size; i++) { y_tmp[i] = P.y_data[i]; } fd_tmp = fd; fd = P.fd2; if (!(*reader[FORMAT])()) { free(y_tmp); fd = fd_tmp; return 0; } /* restore file descriptor */ fd = fd_tmp; /* now, P.y_data contains luminance data for fd2 and * y_tmp contains luma data for fd. * Calculate diff and place result where it belongs * Clear croma data */ calc_psnr(y_tmp, P.y_data); if (FORMAT == YV12 || FORMAT == IYUV) { for (Uint32 i = 0; i < P.y_size; i++) { P.y_data[i] = 0x80 - (y_tmp[i] - P.y_data[i]); } for (Uint32 i = 0; i < P.cb_size; i++) P.cb_data[i] = 0x80; for (Uint32 i = 0; i < P.cr_size; i++) P.cr_data[i] = 0x80; } else { Uint32 j = 0; for (Uint32 i = P.y_start_pos; i < P.frame_size; i += 2) { P.raw[i] = 0x80 - (y_tmp[j] - P.y_data[j]); j++; } for (Uint32 i = P.cb_start_pos; i < P.frame_size; i += 4) P.raw[i] = 0x80; for (Uint32 i = P.cr_start_pos; i < P.frame_size; i += 4) P.raw[i] = 0x80; } free(y_tmp); return 1; }
static int get_image( mlt_frame a_frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_frame b_frame = mlt_frame_pop_frame( a_frame ); mlt_properties properties = MLT_FRAME_PROPERTIES( a_frame ); mlt_transition transition = MLT_TRANSITION( mlt_frame_pop_service( a_frame ) ); uint8_t *b_image; int window_size = mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( transition ), "window_size" ); double psnr[3], ssim[3]; *format = mlt_image_yuv422; mlt_frame_get_image( b_frame, &b_image, format, width, height, writable ); mlt_frame_get_image( a_frame, image, format, width, height, writable ); psnr[0] = calc_psnr( *image, b_image, *width * *height, 2 ); psnr[1] = calc_psnr( *image + 1, b_image + 1, *width * *height / 2, 4 ); psnr[2] = calc_psnr( *image + 3, b_image + 3, *width * *height / 2, 4 ); ssim[0] = calc_ssim( *image, b_image, *width, *height, window_size, 2 ); ssim[1] = calc_ssim( *image + 1, b_image + 1, *width / 2, *height, window_size, 4 ); ssim[2] = calc_ssim( *image + 3, b_image + 3, *width / 2, *height, window_size, 4 ); mlt_properties_set_double( properties, "meta.vqm.psnr.y", psnr[0] ); mlt_properties_set_double( properties, "meta.vqm.psnr.cb", psnr[1] ); mlt_properties_set_double( properties, "meta.vqm.psnr.cr", psnr[2] ); mlt_properties_set_double( properties, "meta.vqm.ssim.y", ssim[0] ); mlt_properties_set_double( properties, "meta.vqm.ssim.cb", ssim[1] ); mlt_properties_set_double( properties, "meta.vqm.ssim.cr", ssim[2] ); printf( "%05d %05.2f %05.2f %05.2f %5.3f %5.3f %5.3f\n", mlt_frame_get_position( a_frame ), psnr[0], psnr[1], psnr[2], ssim[0], ssim[1], ssim[2] ); // copy the B frame to the bottom of the A frame for comparison window_size = mlt_image_format_size( *format, *width, *height, NULL ) / 2; memcpy( *image + window_size, b_image + window_size, window_size ); if ( !mlt_properties_get_int( MLT_TRANSITION_PROPERTIES( transition ), "render" ) ) return 0; // get RGBA image for Qt drawing *format = mlt_image_rgb24a; mlt_frame_get_image( a_frame, image, format, width, height, 1 ); // convert mlt image to qimage QImage img( *width, *height, QImage::Format_ARGB32 ); int y = *height + 1; uint8_t *src = *image; while ( --y ) { QRgb *dst = (QRgb*) img.scanLine( *height - y ); int x = *width + 1; while ( --x ) { *dst++ = qRgba( src[0], src[1], src[2], 255 ); src += 4; } } // setup Qt drawing QPainter painter; painter.begin( &img ); painter.setRenderHints( QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::HighQualityAntialiasing ); // draw some stuff with Qt QPalette palette; QFont font; QString s; font.setBold( true ); font.setPointSize( 30 * *height / 1080 ); painter.setPen( QColor("black") ); painter.drawLine( 0, *height/2 + 1, *width, *height/2 ); painter.setPen( QColor("white") ); painter.drawLine( 0, *height/2 - 1, *width, *height/2 ); painter.setFont( font ); s.sprintf( "Frame: %05d\nPSNR: %05.2f (Y) %05.2f (Cb) %05.2f (Cr)\nSSIM: %5.3f (Y) %5.3f (Cb) %5.3f (Cr)", mlt_frame_get_position( a_frame ), psnr[0], psnr[1], psnr[2], ssim[0], ssim[1], ssim[2] ); painter.setPen( QColor("black") ); painter.drawText( 52, *height * 8 / 10 + 2, *width, *height, 0, s ); painter.setPen( QColor("white") ); painter.drawText( 50, *height * 8 / 10, *width, *height, 0, s ); // finish Qt drawing painter.end(); window_size = mlt_image_format_size( *format, *width, *height, NULL ); uint8_t *dst = (uint8_t *) mlt_pool_alloc( window_size ); mlt_properties_set_data( MLT_FRAME_PROPERTIES(a_frame), "image", dst, window_size, mlt_pool_release, NULL ); *image = dst; // convert qimage to mlt y = *height + 1; while ( --y ) { QRgb *src = (QRgb*) img.scanLine( *height - y ); int x = *width + 1; while ( --x ) { *dst++ = qRed( *src ); *dst++ = qGreen( *src ); *dst++ = qBlue( *src ); *dst++ = qAlpha( *src ); src++; } } return 0; }