/* * stop the encoder thread * args: * none * * asserts: * none * * returns: error code */ int stop_encoder_thread() { video_capture_save_video(0); __THREAD_JOIN(encoder_thread); return 0; }
/* * stop and join the main loop iteration thread * args: * audio_ctx - pointer to audio context data * * asserts: * audio_ctx is not null * * returns: error code */ int audio_stop_pulseaudio(audio_context_t *audio_ctx) { /*assertions*/ assert(audio_ctx != NULL); audio_ctx->stream_flag = AUDIO_STRM_OFF; __THREAD_JOIN( my_read_thread ); if(verbosity > 0) printf("AUDIO: (pulseaudio) read thread joined\n"); return 0; }
/* run in a thread (SDL overlay)*/ void *main_loop(void *data) { struct ALL_DATA *all_data = (struct ALL_DATA *) data; struct VidState *s = all_data->s; struct paRecordData *pdata = all_data->pdata; struct GLOBAL *global = all_data->global; struct focusData *AFdata = all_data->AFdata; struct vdIn *videoIn = all_data->videoIn; struct particle* particles = NULL; //for the particles video effect SDL_Event event; /*the main SDL surface*/ SDL_Surface *pscreen = NULL; SDL_Overlay *overlay = NULL; SDL_Rect drect; int width = global->width; int height = global->height; int format = global->format; SAMPLE vuPeak[2]; // The maximum vuLevel seen recently int vuPeakFreeze[2]; // The vuPeak values will be frozen for this many frames. vuPeak[0] = vuPeak[1] = 0; vuPeakFreeze[0] = vuPeakFreeze[1] = 0; BYTE *p = NULL; Control *focus_control = NULL; int last_focus = 0; if (global->AFcontrol) { focus_control = get_ctrl_by_id(s->control_list, AFdata->id); get_ctrl(videoIn->fd, s->control_list, AFdata->id, all_data); last_focus = focus_control->value; /*make sure we wait for focus to settle on first check*/ if (last_focus < 0) last_focus = AFdata->f_max; } gboolean capVid = FALSE; gboolean signalquit = FALSE; /*------------------------------ SDL init video ---------------------*/ if(!global->no_display) { overlay = video_init(data, &(pscreen)); if(overlay == NULL) { g_print("FATAL: Couldn't create yuv overlay - please disable hardware accelaration\n"); signalquit = TRUE; /*exit video thread*/ } else { p = (unsigned char *) overlay->pixels[0]; drect.x = 0; drect.y = 0; drect.w = pscreen->w; drect.h = pscreen->h; } } while (!signalquit) { __LOCK_MUTEX(__VMUTEX); capVid = videoIn->capVid; signalquit = videoIn->signalquit; __UNLOCK_MUTEX(__VMUTEX); /*-------------------------- Grab Frame ----------------------------------*/ if (uvcGrab(videoIn, format, width, height, &global->fps, &global->fps_num) < 0) { g_printerr("Error grabbing image \n"); continue; } else { if(!videoIn->timestamp) { global->skip_n++; //skip this frame } if(capVid) { if(global->framecount < 1) { /*reset video start time to first frame capture time */ global->Vidstarttime = videoIn->timestamp; /** set current time for audio ts(0) reference (MONOTONIC) * only used if we have no audio capture before video */ __LOCK_MUTEX(__AMUTEX); pdata->ts_ref = ns_time_monotonic(); __UNLOCK_MUTEX(__AMUTEX); //printf("video ts ref: %llu audio ts_ ref: %llu\n",global->Vidstarttime, pdata->ts_ref); global->v_ts = 0; } else { global->v_ts = videoIn->timestamp - global->Vidstarttime; /*always use the last frame time stamp for video stop time*/ global->Vidstoptime = videoIn->timestamp; } } if (global->FpsCount && !global->no_display) {/* sets fps count in window title bar */ global->frmCount++; if (global->DispFps>0) { /*set every 2 sec*/ g_snprintf(global->WVcaption,24,"GUVCVideo - %3.2f fps",global->DispFps); SDL_WM_SetCaption(global->WVcaption, NULL); global->frmCount=0;/*resets*/ global->DispFps=0; } } /*---------------- autofocus control ------------------*/ if (global->AFcontrol && (global->autofocus || AFdata->setFocus)) { /*AFdata = NULL if no focus control*/ if (AFdata->focus < 0) { /*starting autofocus*/ AFdata->focus = AFdata->left; /*start left*/ focus_control->value = AFdata->focus; if (set_ctrl (videoIn->fd, s->control_list, AFdata->id) != 0) g_printerr("ERROR: couldn't set focus to %d\n", AFdata->focus); /*number of frames until focus is stable*/ /*1.4 ms focus time - every 1 step*/ AFdata->focus_wait = (int) abs(AFdata->focus-last_focus)*1.4/(1000/global->fps)+1; last_focus = AFdata->focus; } else { if (AFdata->focus_wait == 0) { AFdata->sharpness=getSharpness (videoIn->framebuffer, width, height, 5); if (global->debug) g_print("sharp=%d focus_sharp=%d foc=%d right=%d left=%d ind=%d flag=%d\n", AFdata->sharpness,AFdata->focus_sharpness, AFdata->focus, AFdata->right, AFdata->left, AFdata->ind, AFdata->flag); AFdata->focus=getFocusVal (AFdata); if ((AFdata->focus != last_focus)) { focus_control->value = AFdata->focus; if (set_ctrl (videoIn->fd, s->control_list, AFdata->id) != 0) g_printerr("ERROR: couldn't set focus to %d\n", AFdata->focus); /*number of frames until focus is stable*/ /*1.4 ms focus time - every 1 step*/ AFdata->focus_wait = (int) abs(AFdata->focus-last_focus)*1.4/(1000/global->fps)+1; } last_focus = AFdata->focus; } else { AFdata->focus_wait--; if (global->debug) g_print("Wait Frame: %d\n",AFdata->focus_wait); } } } } /*------------------------- Filter Frame ---------------------------------*/ __LOCK_MUTEX(__GMUTEX); if(global->Frame_Flags>0) { if((global->Frame_Flags & YUV_PARTICLES)==YUV_PARTICLES) particles = particles_effect(videoIn->framebuffer, width, height, 20, 4, particles); if((global->Frame_Flags & YUV_MIRROR)==YUV_MIRROR) yuyv_mirror(videoIn->framebuffer, width, height); if((global->Frame_Flags & YUV_UPTURN)==YUV_UPTURN) yuyv_upturn(videoIn->framebuffer, width, height); if((global->Frame_Flags & YUV_NEGATE)==YUV_NEGATE) yuyv_negative (videoIn->framebuffer, width, height); if((global->Frame_Flags & YUV_MONOCR)==YUV_MONOCR) yuyv_monochrome (videoIn->framebuffer, width, height); if((global->Frame_Flags & YUV_PIECES)==YUV_PIECES) pieces (videoIn->framebuffer, width, height, 16 ); } __UNLOCK_MUTEX(__GMUTEX); /*-------------------------capture Image----------------------------------*/ if (videoIn->capImage) { /* * format and resolution can change(enabled) while capturing the frame * but you would need to be speedy gonzalez to press two buttons * at almost the same time :D */ int ret = 0; if((ret=store_picture(all_data)) < 0) g_printerr("saved image to:%s ...Failed \n",videoIn->ImageFName); else if (!ret && global->debug) g_print("saved image to:%s ...OK \n",videoIn->ImageFName); videoIn->capImage=FALSE; } /*---------------------------capture Video---------------------------------*/ if (capVid && !(global->skip_n)) { __LOCK_MUTEX(__VMUTEX); if(videoIn->VidCapStop) videoIn->VidCapStop = FALSE; __UNLOCK_MUTEX(__VMUTEX); int res=0; /* format and resolution don't change(disabled) while capturing video * store_video_frame may sleep if needed to avoid buffer overrun */ if((res=store_video_frame(all_data))<0) g_printerr("WARNING: droped frame (%i)\n",res); } /*video and audio capture have stopped */ else { __LOCK_MUTEX(__VMUTEX); if(!(videoIn->VidCapStop)) videoIn->VidCapStop=TRUE; __UNLOCK_MUTEX(__VMUTEX); } /* decrease skip frame count */ if (global->skip_n > 0) { if (global->debug && capVid) g_print("skiping frame %d...\n", global->skip_n); global->skip_n--; } __LOCK_MUTEX( __AMUTEX ); if (global->Sound_enable && capVid) pdata->skip_n = global->skip_n; __UNLOCK_MUTEX( __AMUTEX ); /*------------------------- Display Frame --------------------------------*/ if(!global->no_display) { if (global->osdFlags && pdata->audio_buff[0]) { draw_vu_meter(width, height, vuPeak, vuPeakFreeze, data); } SDL_LockYUVOverlay(overlay); memcpy(p, videoIn->framebuffer, width * height * 2); SDL_UnlockYUVOverlay(overlay); SDL_DisplayYUVOverlay(overlay, &drect); /*------------------------- Read Key events ------------------------------*/ /* Poll for events */ while( SDL_PollEvent(&event) ) { //printf("event type:%i event key:%i\n", event.type, event.key.keysym.scancode); if(event.type==SDL_KEYDOWN) { if (videoIn->PanTilt) { switch( event.key.keysym.sym ) { /* Keyboard event */ /* Pass the event data onto PrintKeyInfo() */ case SDLK_DOWN: /*Tilt Down*/ uvcPanTilt (videoIn->fd, s->control_list, 0, 1); break; case SDLK_UP: /*Tilt UP*/ uvcPanTilt (videoIn->fd, s->control_list, 0, -1); break; case SDLK_LEFT: /*Pan Left*/ uvcPanTilt (videoIn->fd, s->control_list, 1, 1); break; case SDLK_RIGHT: /*Pan Right*/ uvcPanTilt (videoIn->fd, s->control_list, 1, -1); break; default: break; } } switch( event.key.keysym.scancode ) { case 220: /*webcam button*/ //gdk_threads_enter(); if (all_data->global->default_action == 0) g_main_context_invoke(NULL, image_capture_callback, (gpointer) all_data); else g_main_context_invoke(NULL, video_capture_callback, (gpointer) all_data); break; } switch( event.key.keysym.sym ) { case SDLK_q: //shutDown g_timeout_add(200, shutd_timer, all_data); g_print("q pressed - Quiting...\n"); break; case SDLK_SPACE: { if(global->AFcontrol > 0) setfocus_clicked(NULL, all_data); } break; case SDLK_i: g_main_context_invoke(NULL, image_capture_callback, (gpointer) all_data); break; case SDLK_v: g_main_context_invoke(NULL, video_capture_callback, (gpointer) all_data); break; default: break; } } if(event.type==SDL_VIDEORESIZE) { pscreen = SDL_SetVideoMode(event.resize.w, event.resize.h, global->bpp, SDL_VIDEO_Flags); drect.w = event.resize.w; drect.h = event.resize.h; } if(event.type==SDL_QUIT) { //shutDown g_timeout_add(200, shutd_timer, all_data); } } } /* if set make the thread sleep - default no sleep (full throttle)*/ if(global->vid_sleep) sleep_ms(global->vid_sleep); /*------------------------------------------*/ /* restart video (new resolution/format) */ /*------------------------------------------*/ if (global->change_res) { g_print("setting new resolution (%d x %d)\n", global->width, global->height); /*clean up */ if(particles) g_free(particles); particles = NULL; if (global->debug) g_print("cleaning buffer allocations\n"); fflush(NULL);//flush all output buffers if(!global->no_display) { SDL_FreeYUVOverlay(overlay); overlay = NULL; } /*init device*/ restart_v4l2(videoIn, global); /*set new resolution for video thread*/ width = global->width; height = global->height; format = global->format; /* restart SDL with new values*/ if(!global->no_display) { overlay = video_init(data, &(pscreen)); if(overlay == NULL) { g_print("FATAL: Couldn't create yuv overlay - please disable hardware accelaration\n"); signalquit = TRUE; /*exit video thread*/ } else { if (global->debug) g_print("yuv overlay created (%ix%i).\n", overlay->w, overlay->h); p = (unsigned char *) overlay->pixels[0]; drect.x = 0; drect.y = 0; drect.w = pscreen->w; drect.h = pscreen->h; global->change_res = FALSE; } } else global->change_res = FALSE; } }/*loop end*/ __LOCK_MUTEX(__VMUTEX); capVid = videoIn->capVid; __UNLOCK_MUTEX(__VMUTEX); /*check if thread exited while in Video capture mode*/ if (capVid) { /*stop capture*/ if (global->debug) g_print("stoping Video capture\n"); //global->Vidstoptime = ns_time_monotonic(); /*this is set in IO thread*/ videoIn->VidCapStop=TRUE; capVid = FALSE; __LOCK_MUTEX(__VMUTEX); videoIn->capVid = capVid; __UNLOCK_MUTEX(__VMUTEX); __LOCK_MUTEX(__AMUTEX); pdata->capVid = capVid; __UNLOCK_MUTEX(__AMUTEX); /*join IO thread*/ if (global->debug) g_print("Shuting Down IO Thread\n"); __THREAD_JOIN( all_data->IO_thread ); if (global->debug) g_print("IO Thread finished\n"); } if (global->debug) g_print("Thread terminated...\n"); p = NULL; if(particles) g_free(particles); particles=NULL; if (global->debug) g_print("cleaning Thread allocations: 100%%\n"); fflush(NULL);//flush all output buffers if(!global->no_display) { if(overlay) SDL_FreeYUVOverlay(overlay); //SDL_FreeSurface(pscreen); SDL_Quit(); } if (global->debug) g_print("Video thread completed\n"); global = NULL; AFdata = NULL; videoIn = NULL; return ((void *) 0); }
/* * encoder loop (should run in a separate thread) * args: * data - pointer to user data * * asserts: * none * * returns: pointer to return code */ static void *encoder_loop(void *data) { v4l2_dev_t *device = (v4l2_dev_t *) data; my_encoder_status = 1; if(debug_level > 1) printf("GUVCVIEW: encoder thread (tid: %u)\n", (unsigned int) syscall (SYS_gettid)); /*get the audio context*/ audio_context_t *audio_ctx = get_audio_context(); __THREAD_TYPE encoder_audio_thread; int channels = 0; int samprate = 0; if(audio_ctx) { channels = audio_ctx->channels; samprate = audio_ctx->samprate; } if(debug_level > 0) printf("GUVCVIEW: audio [channels= %i; samprate= %i] \n", channels, samprate); /*create the encoder context*/ encoder_context_t *encoder_ctx = encoder_get_context( device->requested_fmt, get_video_codec_ind(), get_audio_codec_ind(), get_video_muxer(), device->format.fmt.pix.width, device->format.fmt.pix.height, device->fps_num, device->fps_denom, channels, samprate); /*store external SPS and PPS data if needed*/ if(encoder_ctx->video_codec_ind == 0 && /*raw - direct input*/ device->requested_fmt == V4L2_PIX_FMT_H264) { /*request a IDR (key) frame*/ v4l2core_h264_request_idr(device); if(debug_level > 0) printf("GUVCVIEW: storing external pps and sps data in encoder context\n"); encoder_ctx->h264_pps_size = device->h264_PPS_size; if(encoder_ctx->h264_pps_size > 0) { encoder_ctx->h264_pps = calloc(device->h264_PPS_size, sizeof(uint8_t)); if(encoder_ctx->h264_pps == NULL) { fprintf(stderr,"GUVCVIEW: FATAL memory allocation failure (encoder_loop): %s\n", strerror(errno)); exit(-1); } memcpy(encoder_ctx->h264_pps, device->h264_PPS, device->h264_PPS_size); } encoder_ctx->h264_sps_size = device->h264_SPS_size; if(encoder_ctx->h264_sps_size > 0) { encoder_ctx->h264_sps = calloc(device->h264_SPS_size, sizeof(uint8_t)); if(encoder_ctx->h264_sps == NULL) { fprintf(stderr,"GUVCVIEW: FATAL memory allocation failure (encoder_loop): %s\n", strerror(errno)); exit(-1); } memcpy(encoder_ctx->h264_sps, device->h264_SPS, device->h264_SPS_size); } } uint32_t current_framerate = 0; if(device->requested_fmt == V4L2_PIX_FMT_H264) { /* store framerate since it may change due to scheduler*/ current_framerate = v4l2core_get_h264_frame_rate_config(device); } char *video_filename = NULL; /*get_video_[name|path] always return a non NULL value*/ char *name = strdup(get_video_name()); char *path = strdup(get_video_path()); if(get_video_sufix_flag()) { char *new_name = add_file_suffix(path, name); free(name); /*free old name*/ name = new_name; /*replace with suffixed name*/ } int pathsize = strlen(path); if(path[pathsize] != '/') video_filename = smart_cat(path, '/', name); else video_filename = smart_cat(path, 0, name); snprintf(status_message, 79, _("saving video to %s"), video_filename); gui_status_message(status_message); /*muxer initialization*/ encoder_muxer_init(encoder_ctx, video_filename); /*start video capture*/ video_capture_save_video(1); int treshold = 102400; /*100 Mbytes*/ int64_t last_check_pts = 0; /*last pts when disk supervisor called*/ /*start audio processing thread*/ if(encoder_ctx->enc_audio_ctx != NULL && audio_ctx->channels > 0) { if(debug_level > 1) printf("GUVCVIEW: starting encoder audio thread\n"); int ret = __THREAD_CREATE(&encoder_audio_thread, audio_processing_loop, (void *) encoder_ctx); if(ret) fprintf(stderr, "GUVCVIEW: encoder audio thread creation failed (%i)\n", ret); else if(debug_level > 2) printf("GUVCVIEW: created audio encoder thread with tid: %u\n", (unsigned int) encoder_audio_thread); } while(video_capture_get_save_video()) { /*process the video buffer*/ encoder_process_next_video_buffer(encoder_ctx); /*disk supervisor*/ if(encoder_ctx->enc_video_ctx->pts - last_check_pts > 2 * NSEC_PER_SEC) { last_check_pts = encoder_ctx->enc_video_ctx->pts; if(!encoder_disk_supervisor(treshold, path)) { /*stop capture*/ gui_set_video_capture_button_status(0); } } } /*flush the video buffer*/ encoder_flush_video_buffer(encoder_ctx); /*make sure the audio processing thread has stopped*/ if(encoder_ctx->enc_audio_ctx != NULL && audio_ctx->channels > 0) { if(debug_level > 1) printf("GUVCVIEW: join encoder audio thread\n"); __THREAD_JOIN(encoder_audio_thread); } /*close the muxer*/ encoder_muxer_close(encoder_ctx); /*close the encoder context (clean up)*/ encoder_close(encoder_ctx); if(device->requested_fmt == V4L2_PIX_FMT_H264) { /* restore framerate */ v4l2core_set_h264_frame_rate_config(device, current_framerate); } /*clean string*/ free(video_filename); free(path); free(name); my_encoder_status = 0; return ((void *) 0); }
/* * encoder loop (should run in a separate thread) * args: * data - pointer to user data * * asserts: * none * * returns: pointer to return code */ static void *encoder_loop(void *data) { my_encoder_status = 1; if(debug_level > 1) printf("GUVCVIEW: encoder thread (tid: %u)\n", (unsigned int) syscall (SYS_gettid)); /*get the audio context*/ audio_context_t *audio_ctx = get_audio_context(); __THREAD_TYPE encoder_audio_thread; int channels = 0; int samprate = 0; if(audio_ctx) { channels = audio_ctx->channels; samprate = audio_ctx->samprate; } if(debug_level > 0) printf("GUVCVIEW: audio [channels= %i; samprate= %i] \n", channels, samprate); /*create the encoder context*/ encoder_context_t *encoder_ctx = encoder_get_context( v4l2core_get_requested_frame_format(), get_video_codec_ind(), get_audio_codec_ind(), get_video_muxer(), v4l2core_get_frame_width(), v4l2core_get_frame_height(), v4l2core_get_fps_num(), v4l2core_get_fps_denom(), channels, samprate); /*store external SPS and PPS data if needed*/ if(encoder_ctx->video_codec_ind == 0 && /*raw - direct input*/ v4l2core_get_requested_frame_format() == V4L2_PIX_FMT_H264) { /*request a IDR (key) frame*/ v4l2core_h264_request_idr(); if(debug_level > 0) printf("GUVCVIEW: storing external pps and sps data in encoder context\n"); encoder_ctx->h264_pps_size = v4l2core_get_h264_pps_size(); if(encoder_ctx->h264_pps_size > 0) { encoder_ctx->h264_pps = calloc(encoder_ctx->h264_pps_size, sizeof(uint8_t)); if(encoder_ctx->h264_pps == NULL) { fprintf(stderr,"GUVCVIEW: FATAL memory allocation failure (encoder_loop): %s\n", strerror(errno)); exit(-1); } memcpy(encoder_ctx->h264_pps, v4l2core_get_h264_pps(), encoder_ctx->h264_pps_size); } encoder_ctx->h264_sps_size = v4l2core_get_h264_sps_size(); if(encoder_ctx->h264_sps_size > 0) { encoder_ctx->h264_sps = calloc(encoder_ctx->h264_sps_size, sizeof(uint8_t)); if(encoder_ctx->h264_sps == NULL) { fprintf(stderr,"GUVCVIEW: FATAL memory allocation failure (encoder_loop): %s\n", strerror(errno)); exit(-1); } memcpy(encoder_ctx->h264_sps, v4l2core_get_h264_sps(), encoder_ctx->h264_sps_size); } } uint32_t current_framerate = 0; if(v4l2core_get_requested_frame_format() == V4L2_PIX_FMT_H264) { /* store framerate since it may change due to scheduler*/ current_framerate = v4l2core_get_h264_frame_rate_config(); } char *video_filename = NULL; /*get_video_[name|path] always return a non NULL value*/ char *name = strdup(get_video_name()); char *path = strdup(get_video_path()); if(get_video_sufix_flag()) { char *new_name = add_file_suffix(path, name); free(name); /*free old name*/ name = new_name; /*replace with suffixed name*/ } int pathsize = strlen(path); if(path[pathsize] != '/') video_filename = smart_cat(path, '/', name); else video_filename = smart_cat(path, 0, name); snprintf(status_message, 79, _("saving video to %s"), video_filename); gui_status_message(status_message); /*muxer initialization*/ encoder_muxer_init(encoder_ctx, video_filename); /*start video capture*/ video_capture_save_video(1); int treshold = 102400; /*100 Mbytes*/ int64_t last_check_pts = 0; /*last pts when disk supervisor called*/ /*start audio processing thread*/ if(encoder_ctx->enc_audio_ctx != NULL && audio_ctx->channels > 0) { if(debug_level > 1) printf("GUVCVIEW: starting encoder audio thread\n"); int ret = __THREAD_CREATE(&encoder_audio_thread, audio_processing_loop, (void *) encoder_ctx); if(ret) fprintf(stderr, "GUVCVIEW: encoder audio thread creation failed (%i)\n", ret); else if(debug_level > 2) printf("GUVCVIEW: created audio encoder thread with tid: %u\n", (unsigned int) encoder_audio_thread); } while(video_capture_get_save_video()) { /*process the video buffer*/ if(encoder_process_next_video_buffer(encoder_ctx) > 0) { /* * no buffers to process * sleep a couple of milisec */ struct timespec req = { .tv_sec = 0, .tv_nsec = 1000000};/*nanosec*/ nanosleep(&req, NULL); } /*disk supervisor*/ if(encoder_ctx->enc_video_ctx->pts - last_check_pts > 2 * NSEC_PER_SEC) { last_check_pts = encoder_ctx->enc_video_ctx->pts; if(!encoder_disk_supervisor(treshold, path)) { /*stop capture*/ gui_set_video_capture_button_status(0); } } } /*flush the video buffer*/ encoder_flush_video_buffer(encoder_ctx); /*make sure the audio processing thread has stopped*/ if(encoder_ctx->enc_audio_ctx != NULL && audio_ctx->channels > 0) { if(debug_level > 1) printf("GUVCVIEW: join encoder audio thread\n"); __THREAD_JOIN(encoder_audio_thread); } /*close the muxer*/ encoder_muxer_close(encoder_ctx); /*close the encoder context (clean up)*/ encoder_close(encoder_ctx); if(v4l2core_get_requested_frame_format() == V4L2_PIX_FMT_H264) { /* restore framerate */ v4l2core_set_h264_frame_rate_config(current_framerate); } /*clean string*/ free(video_filename); free(path); free(name); my_encoder_status = 0; return ((void *) 0); } /* * capture loop (should run in a separate thread) * args: * data - pointer to user data (options data) * * asserts: * none * * returns: pointer to return code */ void *capture_loop(void *data) { capture_loop_data_t *cl_data = (capture_loop_data_t *) data; options_t *my_options = (options_t *) cl_data->options; //config_t *my_config = (config_t *) cl_data->config; uint64_t my_last_photo_time = 0; /*timer count*/ int my_photo_npics = 0;/*no npics*/ /*reset quit flag*/ quit = 0; if(debug_level > 1) printf("GUVCVIEW: capture thread (tid: %u)\n", (unsigned int) syscall (SYS_gettid)); int ret = 0; int render_flags = 0; if (strcasecmp(my_options->render_flag, "full") == 0) render_flags = 1; else if (strcasecmp(my_options->render_flag, "max") == 0) render_flags = 2; render_set_verbosity(debug_level); if(render_init(render, v4l2core_get_frame_width(), v4l2core_get_frame_height(), render_flags) < 0) render = RENDER_NONE; else { render_set_event_callback(EV_QUIT, &quit_callback, NULL); render_set_event_callback(EV_KEY_V, &key_V_callback, NULL); render_set_event_callback(EV_KEY_I, &key_I_callback, NULL); render_set_event_callback(EV_KEY_UP, &key_UP_callback, NULL); render_set_event_callback(EV_KEY_DOWN, &key_DOWN_callback, NULL); render_set_event_callback(EV_KEY_LEFT, &key_LEFT_callback, NULL); render_set_event_callback(EV_KEY_RIGHT, &key_RIGHT_callback, NULL); } /*add a video capture timer*/ if(my_options->video_timer > 0) { my_video_timer = NSEC_PER_SEC * my_options->video_timer; my_video_begin_time = v4l2core_time_get_timestamp(); /*timer count*/ /*if are not saving video start it*/ if(!get_encoder_status()) start_encoder_thread(); } /*add a photo capture timer*/ if(my_options->photo_timer > 0) { my_photo_timer = NSEC_PER_SEC * my_options->photo_timer; my_last_photo_time = v4l2core_time_get_timestamp(); /*timer count*/ } if(my_options->photo_npics > 0) my_photo_npics = my_options->photo_npics; v4l2core_start_stream(); v4l2_frame_buff_t *frame = NULL; //pointer to frame buffer while(!quit) { if(restart) { restart = 0; /*reset*/ v4l2core_stop_stream(); /*close render*/ render_close(); v4l2core_clean_buffers(); /*try new format (values prepared by the request callback)*/ ret = v4l2core_update_current_format(); /*try to set the video stream format on the device*/ if(ret != E_OK) { fprintf(stderr, "GUCVIEW: could not set the defined stream format\n"); fprintf(stderr, "GUCVIEW: trying first listed stream format\n"); v4l2core_prepare_valid_format(); v4l2core_prepare_valid_resolution(); ret = v4l2core_update_current_format(); if(ret != E_OK) { fprintf(stderr, "GUCVIEW: also could not set the first listed stream format\n"); gui_error("Guvcview error", "could not start a video stream in the device", 1); return ((void *) -1); } } /*restart the render with new format*/ if(render_init(render, v4l2core_get_frame_width(), v4l2core_get_frame_height(), render_flags) < 0) render = RENDER_NONE; else { render_set_event_callback(EV_QUIT, &quit_callback, NULL); render_set_event_callback(EV_KEY_V, &key_V_callback, NULL); render_set_event_callback(EV_KEY_I, &key_I_callback, NULL); render_set_event_callback(EV_KEY_UP, &key_UP_callback, NULL); render_set_event_callback(EV_KEY_DOWN, &key_DOWN_callback, NULL); render_set_event_callback(EV_KEY_LEFT, &key_LEFT_callback, NULL); render_set_event_callback(EV_KEY_RIGHT, &key_RIGHT_callback, NULL); } if(debug_level > 0) printf("GUVCVIEW: reset to pixelformat=%x width=%i and height=%i\n", v4l2core_get_requested_frame_format(), v4l2core_get_frame_width(), v4l2core_get_frame_height()); v4l2core_start_stream(); } frame = v4l2core_get_decoded_frame(); if( frame != NULL) { /*run software autofocus (must be called after frame was grabbed and decoded)*/ if(do_soft_autofocus || do_soft_focus) do_soft_focus = v4l2core_soft_autofocus_run(frame); /*render the decoded frame*/ snprintf(render_caption, 29, "Guvcview (%2.2f fps)", v4l2core_get_realfps()); render_set_caption(render_caption); render_frame(frame->yuv_frame, my_render_mask); if(check_photo_timer()) { if((frame->timestamp - my_last_photo_time) > my_photo_timer) { save_image = 1; my_last_photo_time = frame->timestamp; if(my_options->photo_npics > 0) { if(my_photo_npics > 0) my_photo_npics--; else stop_photo_timer(); /*close timer*/ } } } if(check_video_timer()) { if((frame->timestamp - my_video_begin_time) > my_video_timer) stop_video_timer(); } if(save_image) { char *img_filename = NULL; /*get_photo_[name|path] always return a non NULL value*/ char *name = strdup(get_photo_name()); char *path = strdup(get_photo_path()); if(get_photo_sufix_flag()) { char *new_name = add_file_suffix(path, name); free(name); /*free old name*/ name = new_name; /*replace with suffixed name*/ } int pathsize = strlen(path); if(path[pathsize] != '/') img_filename = smart_cat(path, '/', name); else img_filename = smart_cat(path, 0, name); //if(debug_level > 1) // printf("GUVCVIEW: saving image to %s\n", img_filename); snprintf(status_message, 79, _("saving image to %s"), img_filename); gui_status_message(status_message); v4l2core_save_image(frame, img_filename, get_photo_format()); free(path); free(name); free(img_filename); save_image = 0; /*reset*/ } if(video_capture_get_save_video()) { #ifdef USE_PLANAR_YUV int size = (v4l2core_get_frame_width() * v4l2core_get_frame_height() * 3) / 2; #else int size = v4l2core_get_frame_width() * v4l2core_get_frame_height() * 2; #endif uint8_t *input_frame = frame->yuv_frame; /* * TODO: check codec_id, format and frame flags * (we may want to store a compressed format */ if(get_video_codec_ind() == 0) //raw frame { switch(v4l2core_get_requested_frame_format()) { case V4L2_PIX_FMT_H264: input_frame = frame->h264_frame; size = (int) frame->h264_frame_size; break; default: input_frame = frame->raw_frame; size = (int) frame->raw_frame_size; break; } } encoder_add_video_frame(input_frame, size, frame->timestamp, frame->isKeyframe); /* * exponencial scheduler * with 50% threshold (nanosec) * and max value of 250 ms (4 fps) */ int time_sched = encoder_buff_scheduler(ENCODER_SCHED_EXP, 0.5, 250); if(time_sched > 0) { switch(v4l2core_get_requested_frame_format()) { case V4L2_PIX_FMT_H264: { uint32_t framerate = time_sched; /*nanosec*/ v4l2core_set_h264_frame_rate_config(framerate); break; } default: { struct timespec req = { .tv_sec = 0, .tv_nsec = time_sched};/*nanosec*/ nanosleep(&req, NULL); break; } } } } /*we are done with the frame buffer release it*/ v4l2core_release_frame(frame); } } v4l2core_stop_stream(); /*if we are still saving video then stop it*/ if(video_capture_get_save_video()) stop_encoder_thread(); render_close(); return ((void *) 0); } /* * start the encoder thread * args: * data - pointer to user data * * asserts: * none * * returns: error code */ int start_encoder_thread(void *data) { int ret = __THREAD_CREATE(&encoder_thread, encoder_loop, data); if(ret) fprintf(stderr, "GUVCVIEW: encoder thread creation failed (%i)\n", ret); else if(debug_level > 2) printf("GUVCVIEW: created encoder thread with tid: %u\n", (unsigned int) encoder_thread); return ret; }