/* * Apply OSD mask * args: * frame - pointer to frame buffer (yuyv format) * * asserts: * frame is not null * * returns: void */ void render_frame_osd(uint8_t *frame) { float vu_level[2]; render_get_vu_level(vu_level); /*osd vu meter*/ if(((render_get_osd_mask() & (REND_OSD_VUMETER_MONO | REND_OSD_VUMETER_STEREO))) != 0) render_osd_vu_meter(frame, my_width, my_height, vu_level); /*osd crosshair*/ if(((render_get_osd_mask() & REND_OSD_CROSSHAIR)) != 0) render_osd_crosshair(frame, my_width, my_height); }
/* * render a frame * args: * frame - pointer to frame data (yuyv format) * width - frame width * height - frame height * * asserts: * poverlay is not nul * frame is not null * * returns: error code */ int render_sdl2_frame(uint8_t *frame, int width, int height) { /*asserts*/ assert(rending_texture != NULL); assert(frame != NULL); float vu_level[2]; render_get_vu_level(vu_level); #ifdef USE_PLANAR_YUV int size = width * height * 3/2; /* for IYUV */ #else int size = width * height * 2; /* 2 bytes per pixel for YUYV */ #endif void* texture_pixels; int pitch; SDL_SetRenderDrawColor(main_renderer, 0, 0, 0, 255); /*black*/ SDL_RenderClear(main_renderer); if (SDL_LockTexture(rending_texture, NULL, &texture_pixels, &pitch)) { fprintf(stderr, "RENDER: couldn't lock texture to write\n"); return -1; } memcpy(texture_pixels, frame, size); /*osd vu meter*/ if(((render_get_osd_mask() & (REND_OSD_VUMETER_MONO | REND_OSD_VUMETER_STEREO))) != 0) render_osd_vu_meter(texture_pixels, width, height, vu_level); /*osd crosshair*/ if(((render_get_osd_mask() & REND_OSD_CROSSHAIR)) != 0) render_osd_crosshair(texture_pixels, width, height); SDL_UnlockTexture(rending_texture); SDL_RenderCopy(main_renderer, rending_texture, NULL, NULL); SDL_RenderPresent(main_renderer); }
/* * render a vu meter * args: * frame - pointer to yuyv frame data * width - frame width * height - frame height * vu_level - vu level values (array with 2 channels) * * asserts: * none * * returns: none */ void render_osd_vu_meter(uint8_t *frame, int width, int height, float vu_level[2]) { int bw = 2 * (width / (VU_BARS * 8)); /*make it at least two pixels*/ int bh = height / 24; int channel; for (channel = 0; channel < 2; ++channel) { if((render_get_osd_mask() & REND_OSD_VUMETER_MONO) != 0 && channel > 0) continue; /*if mono mode only render first channel*/ /*make sure we have a positive value (required by log10)*/ if(vu_level[channel] < 0) vu_level[channel] = -vu_level[channel]; /* Handle peak calculation and falloff */ if (vu_peak[channel] < vu_level[channel]) { vu_peak[channel] = vu_level[channel]; vu_peak_freeze[channel] = 30; } else if (vu_peak_freeze[channel] > 0) { vu_peak_freeze[channel]--; } else if (vu_peak[channel] > vu_level[channel]) { vu_peak[channel] -= (vu_peak[channel] - vu_level[channel]) / 10; } /*by default no bar is light */ float dBuLevel = - 4 * (VU_BARS - 1); float dBuPeak = - 4 * (VU_BARS - 1); if(vu_level[channel] > 0) dBuLevel = 10 * log10(vu_level[channel] / REFERENCE_LEVEL); if(vu_peak[channel] > 0) dBuPeak = 10 * log10(vu_peak[channel] / REFERENCE_LEVEL); /* draw the bars */ int peaked = 0; int box = 0; for (box = 0; box <= (VU_BARS - 1); ++box) { /* * The dB it takes to light the current box * step of 2 db between boxes */ float db = 2 * (box - (VU_BARS - 1)); /* start x coordinate for box */ int bx = box * (bw + 4) + (16); /* Start y coordinate for box (box top)*/ int by = channel * (bh + 4) + bh; yuv_color_t color; color.y = 127; color.u = 127; color.v = 127; /*green bar*/ if (db < -10) { color.y = 154; color.u = 72; color.v = 57; } else if (db < -2) /*yellow bar*/ { color.y = 203; color.u = 44; color.v = 142; } else /*red bar*/ { color.y = 107; color.u = 100; color.v = 212; } int light = dBuLevel > db; if (dBuPeak < db+1 && !peaked) { peaked = 1; light = 1; } if (light) plot_box_yu12(frame, height, width, bx, by, bw, bh, &color); else if (bw > 0) /*draw single line*/ plot_line_yu12(frame, height, width, bx, by + (bh /2), bw, &color); } } }
/* * audio processing loop (should run in a separate thread) * args: * data - pointer to user data * * asserts: * none * * returns: pointer to return code */ static void *audio_processing_loop(void *data) { encoder_context_t *encoder_ctx = (encoder_context_t *) data; if(debug_level > 1) printf("GUVCVIEW: audio thread (tid: %u)\n", (unsigned int) syscall (SYS_gettid)); audio_context_t *audio_ctx = get_audio_context(); if(!audio_ctx) { fprintf(stderr, "GUVCVIEW: no audio context: skiping audio processing\n"); return ((void *) -1); } audio_buff_t *audio_buff = NULL; /*start audio capture*/ int frame_size = encoder_get_audio_frame_size(encoder_ctx); audio_ctx->capture_buff_size = frame_size * audio_ctx->channels; audio_start(audio_ctx); /* * alloc the buffer after audio_start * otherwise capture_buff_size may not * be correct * allocated data is big enough for float samples (32 bit) * although it may contain int16 samples (16 bit) */ audio_buff = audio_get_buffer(audio_ctx); int sample_type = encoder_get_audio_sample_fmt(encoder_ctx); uint32_t osd_mask = render_get_osd_mask(); /*enable vu meter OSD display*/ if(audio_ctx->channels > 1) osd_mask |= REND_OSD_VUMETER_STEREO; else osd_mask |= REND_OSD_VUMETER_MONO; render_set_osd_mask(osd_mask); while(video_capture_get_save_video()) { int ret = audio_get_next_buffer(audio_ctx, audio_buff, sample_type, my_audio_mask); if(ret > 0) { /* * no buffers to process * sleep a couple of milisec */ struct timespec req = { .tv_sec = 0, .tv_nsec = 1000000};/*nanosec*/ nanosleep(&req, NULL); } else if(ret == 0) { encoder_ctx->enc_audio_ctx->pts = audio_buff->timestamp; /*OSD vu meter level*/ render_set_vu_level(audio_buff->level_meter); encoder_process_audio_buffer(encoder_ctx, audio_buff->data); } } /*flush any delayed audio frames*/ encoder_flush_audio_buffer(encoder_ctx); /*reset vu meter*/ audio_buff->level_meter[0] = 0; audio_buff->level_meter[1] = 0; render_set_vu_level(audio_buff->level_meter); /*disable OSD vumeter*/ osd_mask &= ~REND_OSD_VUMETER_STEREO; osd_mask &= ~REND_OSD_VUMETER_MONO; render_set_osd_mask(osd_mask); audio_stop(audio_ctx); audio_delete_buffer(audio_buff); return ((void *) 0); }