/* * capture loop (should run in a separate thread) * args: * data - pointer to user data (device data + options data) * * asserts: * device data is not null * * returns: pointer to return code */ void *capture_loop(void *data) { capture_loop_data_t *cl_data = (capture_loop_data_t *) data; v4l2_dev_t *device = (v4l2_dev_t *) cl_data->device; 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*/ /*asserts*/ assert(device != NULL); /*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, device->format.fmt.pix.width, device->format.fmt.pix.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, device); render_set_event_callback(EV_KEY_I, &key_I_callback, NULL); render_set_event_callback(EV_KEY_UP, &key_UP_callback, device); render_set_event_callback(EV_KEY_DOWN, &key_DOWN_callback, device); render_set_event_callback(EV_KEY_LEFT, &key_LEFT_callback, device); render_set_event_callback(EV_KEY_RIGHT, &key_RIGHT_callback, device); } /*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(device); } /*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(device); while(!quit) { if(restart) { restart = 0; /*reset*/ v4l2core_stop_stream(device); /*close render*/ render_close(); v4l2core_clean_buffers(device); /*try new format (values prepared by the request callback)*/ ret = v4l2core_update_current_format(device); /*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(device); v4l2core_prepare_valid_resolution(device); ret = v4l2core_update_current_format(device); if(ret != E_OK) { fprintf(stderr, "GUCVIEW: also could not set the first listed stream format\n"); gui_error(device, "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, device->format.fmt.pix.width, device->format.fmt.pix.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, device); render_set_event_callback(EV_KEY_I, &key_I_callback, NULL); render_set_event_callback(EV_KEY_UP, &key_UP_callback, device); render_set_event_callback(EV_KEY_DOWN, &key_DOWN_callback, device); render_set_event_callback(EV_KEY_LEFT, &key_LEFT_callback, device); render_set_event_callback(EV_KEY_RIGHT, &key_RIGHT_callback, device); } if(debug_level > 0) printf("GUVCVIEW: reset to pixelformat=%x width=%i and height=%i\n", device->requested_fmt, device->format.fmt.pix.width, device->format.fmt.pix.height); v4l2core_start_stream(device); } if( v4l2core_get_frame(device) == E_OK) { /*decode the raw frame*/ if(v4l2core_frame_decode(device) != E_OK) { fprintf(stderr, "GUVCIEW: Error - Couldn't decode frame\n"); } /*run software autofocus (must be called after frame_decode)*/ if(do_soft_autofocus || do_soft_focus) do_soft_focus = v4l2core_soft_autofocus_run(device); /*render the decoded frame*/ snprintf(render_caption, 29, "Guvcview (%2.2f fps)", v4l2core_get_realfps()); render_set_caption(render_caption); render_frame(device->yuv_frame, my_render_mask); /* Save frame to file */ char filename[50]; sprintf(filename, "/home/cobra/Desktop/frame/%d", device->frame_index); save_image_bmp(device, filename); if(check_photo_timer()) { if((device->timestamp - my_last_photo_time) > my_photo_timer) { save_image = 1; my_last_photo_time = device->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((device->timestamp - my_video_begin_time) > my_video_timer) stop_video_timer(device); } 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(device, 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 = (device->format.fmt.pix.width * device->format.fmt.pix.height * 3) / 2; #else int size = device->format.fmt.pix.width * device->format.fmt.pix.height * 2; #endif uint8_t *input_frame = device->yuv_frame; /* * TODO: check codec_id, format and frame flags * (we may want to store a compressed format */ if(get_video_codec_ind() == 0) { switch(device->requested_fmt) { case V4L2_PIX_FMT_H264: input_frame = device->h264_frame; size = (int) device->h264_frame_size; break; default: input_frame = device->raw_frame; size = (int) device->raw_frame_size; break; } } encoder_add_video_frame(input_frame, size, device->timestamp, device->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(device->requested_fmt) { case V4L2_PIX_FMT_H264: { uint32_t framerate = time_sched; /*nanosec*/ v4l2core_set_h264_frame_rate_config(device, 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(device); } } v4l2core_stop_stream(device); 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; }
/* * 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; }
/*------------------------- read command line options ------------------------*/ void readOpts(int argc,char *argv[], struct GLOBAL *global) { gchar *device=NULL; gchar *format=NULL; gchar *size = NULL; gchar *image = NULL; gchar *video=NULL; gchar *profile=NULL; gchar *separateur=NULL; gboolean help = FALSE; gboolean help_gtk = FALSE; gboolean help_all = FALSE; gboolean vers = FALSE; gchar *help_str = NULL; gchar *help_gtk_str = NULL; gchar *help_all_str = NULL; gchar *config = NULL; int hwaccel=-1; int FpsCount=-1; int cap_meth=-1; GOptionEntry entries[] = { { "help-all", 'h', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &help_all, "Display all help options", NULL}, { "help-gtk", '!', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &help_gtk, "DISPLAY GTK+ help", NULL}, { "help", '?', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &help, "Display help", NULL}, { "version", 0, 0, G_OPTION_ARG_NONE, &vers, N_("Prints version"), NULL}, { "verbose", 'v', 0, G_OPTION_ARG_NONE, &global->debug, N_("Displays debug information"), NULL }, { "device", 'd', 0, G_OPTION_ARG_STRING, &device, N_("Video Device to use [default: /dev/video0]"), "VIDEO_DEVICE" }, { "add_ctrls", 'a', 0, G_OPTION_ARG_NONE, &global->add_ctrls, N_("Exit after adding UVC extension controls (needs root/sudo)"), NULL}, { "control_only", 'o', 0, G_OPTION_ARG_NONE, &global->control_only, N_("Don't stream video (image controls only)"), NULL}, { "no_display", 0,0, G_OPTION_ARG_NONE, &global->no_display, N_("Don't display a GUI"), NULL}, { "capture_method", 'r', 0, G_OPTION_ARG_INT, &cap_meth, N_("Capture method (1-mmap (default) 2-read)"), "[1 | 2]"}, { "config", 'g', 0, G_OPTION_ARG_STRING, &config, N_("Configuration file"), "FILENAME" }, { "hwd_acel", 'w', 0, G_OPTION_ARG_INT, &hwaccel, N_("Hardware accelaration (enable(1) | disable(0))"), "[1 | 0]" }, { "format", 'f', 0, G_OPTION_ARG_STRING, &format, N_("Pixel format(mjpg|jpeg|yuyv|yvyu|uyvy|yyuv|yu12|yv12|nv12|nv21|nv16|nv61|y41p|grey|y10b|y16 |s501|s505|s508|gbrg|grbg|ba81|rggb|bgr3|rgb3)"), "FORMAT" }, { "size", 's', 0, G_OPTION_ARG_STRING, &size, N_("Frame size, default: 640x480"), "WIDTHxHEIGHT"}, { "image", 'i', 0, G_OPTION_ARG_STRING, &image, N_("Image File name"), "FILENAME"}, { "cap_time", 'c', 0, G_OPTION_ARG_INT, &global->image_timer, N_("Image capture interval in seconds"), "TIME"}, { "npics", 'm', 0, G_OPTION_ARG_INT, &global->image_npics, N_("Number of Pictures to capture"), "NUMPIC"}, { "video", 'n', 0, G_OPTION_ARG_STRING, &video, N_("Video File name (capture from start)"), "FILENAME"}, { "vid_time", 't', 0, G_OPTION_ARG_INT, &global->Capture_time,N_("Video capture time (in seconds)"), "TIME"}, { "exit_on_close", 0, 0, G_OPTION_ARG_NONE, &global->exit_on_close, N_("Exits guvcview after closing video"), NULL}, { "skip", 'j', 0, G_OPTION_ARG_INT, &global->skip_n, N_("Number of initial frames to skip"), "N_FRAMES"}, { "show_fps", 'p', 0, G_OPTION_ARG_INT, &FpsCount, N_("Show FPS value (enable(1) | disable (0))"), "[1 | 0]"}, { "profile", 'l', 0, G_OPTION_ARG_STRING, &profile, N_("Load Profile at start"), "FILENAME"}, { "lctl_method", 'k', 0, G_OPTION_ARG_INT, &global->lctl_method, N_("List controls method (0:loop, 1:next_ctrl flag [def])"), "[0 |1]"}, { NULL } }; GError *error = NULL; GOptionContext *context; context = g_option_context_new (N_("- local options")); g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); g_option_context_add_group (context, gtk_get_option_group (TRUE)); g_set_prgname (PACKAGE); help_str = g_option_context_get_help (context, TRUE, NULL); help_gtk_str = g_option_context_get_help (context, FALSE, gtk_get_option_group (TRUE)); help_all_str = g_option_context_get_help (context, FALSE, NULL); /*disable automatic help parsing - must clean global before exit*/ g_option_context_set_help_enabled (context, FALSE); if (!g_option_context_parse (context, &argc, &argv, &error)) { g_printerr ("option parsing failed: %s\n", error->message); g_error_free ( error ); closeGlobals(global); global=NULL; g_print("%s",help_all_str); g_free(help_all_str); g_free(help_str); g_free(help_gtk_str); g_option_context_free (context); exit (1); } if(vers) { //print version and exit //version already printed in guvcview.c closeGlobals(global); global=NULL; g_free(help_all_str); g_free(help_str); g_free(help_gtk_str); g_option_context_free (context); exit(0); } /*Display help message and exit*/ if(help_all) { closeGlobals(global); global=NULL; g_print("%s",help_all_str); g_free(help_all_str); g_free(help_str); g_free(help_gtk_str); g_option_context_free (context); exit(0); } else if(help) { closeGlobals(global); global=NULL; g_print("%s",help_str); g_free(help_str); g_free(help_gtk_str); g_free(help_all_str); g_option_context_free (context); exit(0); } else if(help_gtk) { closeGlobals(global); global=NULL; g_print("%s",help_gtk_str); g_free(help_str); g_free(help_gtk_str); g_free(help_all_str); g_option_context_free (context); exit(0); } /*regular options*/ if(device) { gchar *basename = NULL; gchar *dirname = NULL; basename = g_path_get_basename(device); if(!(g_str_has_prefix(basename,"video"))) { g_printerr("%s not a valid video device name\n", basename); } else { g_free(global->videodevice); global->videodevice=NULL; dirname = g_path_get_dirname(device); if(g_strcmp0(".",dirname)==0) { g_free(dirname); dirname=g_strdup("/dev"); } global->videodevice = g_strjoin("/", dirname, basename, NULL); if(global->flg_config < 1) { if(g_strcmp0("video0",basename) !=0 ) { g_free(global->confPath); global->confPath=NULL; global->confPath = g_strjoin("/", g_get_home_dir(), ".config", "guvcview", basename, NULL); } } } g_free(dirname); g_free(basename); } if(config) { g_free(global->confPath); global->confPath=NULL; global->confPath = g_strdup(config); global->flg_config = 1; } if(format) { /*use fourcc but keep compatability with luvcview*/ if(g_strcmp0("yuv",format)==0) g_snprintf(global->mode,5,"yuyv"); else if (g_strcmp0("bggr",format)==0) // be compatible with guvcview < 1.1.4 g_snprintf(global->mode,5,"ba81"); else g_snprintf(global->mode,5,"%s ",format); printf("requested format \"%s\" from command line\n", global->mode); global->flg_mode = TRUE; } if(size) { global->width = (int) g_ascii_strtoull(size, &separateur, 10); if (*separateur != 'x') { g_printerr("Error in size usage: -s[--size] WIDTHxHEIGHT \n"); } else { ++separateur; global->height = (int) g_ascii_strtoull(separateur, &separateur, 10); if (*separateur != 0) g_printerr("hmm.. don't like that!! trying this height \n"); } global->flg_res = 1; } if(image) { global->imgFPath=splitPath(image,global->imgFPath); /*get the file type*/ global->imgFormat = check_image_type(global->imgFPath[0]); global->flg_imgFPath = TRUE; if(global->image_inc>0) { uint64_t suffix = get_file_suffix(global->imgFPath[1], global->imgFPath[0]); fprintf(stderr, "Image file suffix detected: %" PRIu64 "\n", suffix); if(suffix >= G_MAXUINT64) { global->imgFPath[0] = add_file_suffix(global->imgFPath[0], suffix); suffix = 0; } if(suffix > 0) { global->image_inc = suffix + 1; } } } if(global->image_timer > 0 ) { g_print("capturing images every %i seconds\n",global->image_timer); } if(video) { global->vidFPath=splitPath(video, global->vidFPath); if(global->vid_inc>0) { uint64_t suffix = get_file_suffix(global->vidFPath[1], global->vidFPath[0]); fprintf(stderr, "Video file suffix detected: %" PRIu64 "\n", suffix); if(suffix >= G_MAXUINT64) { global->vidFPath[0] = add_file_suffix(global->vidFPath[0], suffix); suffix = 0; } if(suffix > 0) global->vid_inc = suffix + 1; } global->vidfile = joinPath(global->vidfile, global->vidFPath); g_print("capturing video: %s , from start\n",global->vidfile); /*get the file type*/ global->VidFormat = check_video_type(global->vidFPath[0]); } if(profile) { global->lprofile=1; global->profile_FPath=splitPath(profile,global->profile_FPath); } if(hwaccel != -1 ) { global->hwaccel = hwaccel; global->flg_hwaccel = 1; } if(FpsCount != -1) { global->FpsCount = FpsCount; global->flg_FpsCount = 1; } if(cap_meth != -1) { global->flg_cap_meth = TRUE; global->cap_meth = cap_meth; } //g_print("option capture meth is %i\n", global->cap_meth); g_free(help_str); g_free(help_gtk_str); g_free(help_all_str); g_free(device); g_free(config); g_free(format); g_free(size); g_free(image); g_free(video); g_free(profile); g_option_context_free (context); }
/*----------------------- read conf (.config/guvcview/videoX) file -----------------------*/ int readConf(struct GLOBAL *global) { int ret=0; //int signal=1; /*1=>+ or -1=>-*/ GScanner *scanner; GTokenType ttype; GScannerConfig config = { " \t\r\n", /* characters to skip */ G_CSET_a_2_z "_" G_CSET_A_2_Z, /* identifier start */ G_CSET_a_2_z "_." G_CSET_A_2_Z G_CSET_DIGITS,/* identifier cont. */ "#\n", /* single line comment */ FALSE, /* case_sensitive */ TRUE, /* skip multi-line comments */ TRUE, /* skip single line comments */ FALSE, /* scan multi-line comments */ TRUE, /* scan identifiers */ TRUE, /* scan 1-char identifiers */ FALSE, /* scan NULL identifiers */ FALSE, /* scan symbols */ FALSE, /* scan binary */ FALSE, /* scan octal */ TRUE, /* scan float */ TRUE, /* scan hex */ FALSE, /* scan hex dollar */ TRUE, /* scan single quote strings */ TRUE, /* scan double quote strings */ TRUE, /* numbers to int */ FALSE, /* int to float */ TRUE, /* identifier to string */ TRUE, /* char to token */ FALSE, /* symbol to token */ FALSE, /* scope 0 fallback */ TRUE /* store int64 */ }; int fd = g_open (global->confPath, O_RDONLY, 0); if (fd < 0 ) { printf("Could not open %s for read,\n will try to create it\n",global->confPath); ret=writeConf(global, global->videodevice); } else { scanner = g_scanner_new (&config); g_scanner_input_file (scanner, fd); scanner->input_name = global->confPath; //temp codec values int ac_bit_rate =-1, vc_bit_rate=-1, vc_fps=-1, vc_qmax=-1, vc_qmin=-1, vc_max_qdiff=-1, vc_dia=-1; int vc_pre_dia=-1, vc_pre_me=-1, vc_me_pre_cmp=-1, vc_me_cmp=-1, vc_me_sub_cmp=-1, vc_last_pred=-1; int vc_gop_size=-1, vc_subq=-1, vc_framerefs=-1, vc_mb_decision=-1, vc_trellis=-1, vc_me_method=-1; int vc_mpeg_quant=-1, vc_max_b_frames=-1, vc_num_threads=-1, vc_flags=-1, vc_monotonic_pts=-1; float vc_qcompress=-1, vc_qblur=-1; int VMAJOR =-1, VMINOR=-1, VMICRO=-1; for (ttype = g_scanner_get_next_token (scanner); ttype != G_TOKEN_EOF; ttype = g_scanner_get_next_token (scanner)) { if (ttype == G_TOKEN_STRING) { //printf("reading %s...\n",scanner->value.v_string); char *name = g_strdup (scanner->value.v_string); ttype = g_scanner_get_next_token (scanner); if (ttype != G_TOKEN_EQUAL_SIGN) { g_scanner_unexp_token (scanner, G_TOKEN_EQUAL_SIGN, NULL, NULL, NULL, NULL, FALSE); } else { ttype = g_scanner_get_next_token (scanner); /*check for signed integers*/ if(ttype == '-') { //signal = -1; ttype = g_scanner_get_next_token (scanner); } if (ttype == G_TOKEN_STRING) { if (g_strcmp0(name,"version")==0) { sscanf(scanner->value.v_string,"%i.%i.%i", &(VMAJOR), &(VMINOR), &(VMICRO)); } else if (g_strcmp0(name,"resolution")==0) { if(global->flg_res < 1) /*must check for defaults since ReadOpts runs before ReadConf*/ sscanf(scanner->value.v_string,"%ix%i", &(global->width), &(global->height)); } else if (g_strcmp0(name,"windowsize")==0) { sscanf(scanner->value.v_string,"%ix%i", &(global->winwidth), &(global->winheight)); } else if (g_strcmp0(name,"mode")==0) { if(global->flg_mode < 1) { /*use fourcc but keep it compatible with luvcview*/ if(g_strcmp0(scanner->value.v_string,"yuv") == 0) g_snprintf(global->mode,5,"yuyv"); else g_snprintf(global->mode,5,"%s",scanner->value.v_string); } } else if (g_strcmp0(name,"fps")==0) { sscanf(scanner->value.v_string,"%i/%i", &(global->fps_num), &(global->fps)); } else if (g_strcmp0(name,"image_path")==0) { if(global->flg_imgFPath < 1) { global->imgFPath = splitPath(scanner->value.v_string,global->imgFPath); /*get the file type*/ global->imgFormat = check_image_type(global->imgFPath[0]); } else { /* check if new file != old file */ gchar * newPath = g_strjoin ("/", global->imgFPath[1], global->imgFPath[0], NULL); //printf("image path: %s\n old path: %s\n", newPath, scanner->value.v_string); if(g_strcmp0(scanner->value.v_string, newPath) !=0) { /* reset counter */ //printf("reset counter from: %i\n", global->image_inc); if(global->image_inc > 0) { global->image_inc = 1; //g_snprintf(global->imageinc_str,20,_("File num:%d"),global->image_inc); } } g_free(newPath); } } else if ((g_strcmp0(name,"video_path")==0) || (g_strcmp0(name,"avi_path")==0)) { if(global->vidfile == NULL) { global->vidFPath=splitPath(scanner->value.v_string,global->vidFPath); } } else if (g_strcmp0(name,"profile_path")==0) { if(global->lprofile < 1) global->profile_FPath=splitPath(scanner->value.v_string, global->profile_FPath); } else { printf("unexpected string value (%s) for %s\n", scanner->value.v_string, name); } } else if (ttype==G_TOKEN_INT) { if (g_strcmp0(name,"stack_size")==0) { global->stack_size = scanner->value.v_int; } else if (g_strcmp0(name,"vid_sleep")==0) { global->vid_sleep = scanner->value.v_int; } else if (g_strcmp0(name,"cap_meth")==0) { if(!(global->flg_cap_meth)) global->cap_meth = scanner->value.v_int; } else if (g_strcmp0(name,"spinbehave")==0) { global->spinbehave = scanner->value.v_int; } else if (g_strcmp0(name,"default_action")==0) { global->default_action = scanner->value.v_int; } else if (g_strcmp0(name,"fps")==0) { /*parse non-quoted fps values*/ int line = g_scanner_cur_line(scanner); global->fps_num = scanner->value.v_int; ttype = g_scanner_peek_next_token (scanner); if(ttype=='/') { /*get '/'*/ ttype = g_scanner_get_next_token (scanner); ttype = g_scanner_peek_next_token (scanner); if(ttype==G_TOKEN_INT) { ttype = g_scanner_get_next_token (scanner); global->fps = scanner->value.v_int; } else if (scanner->next_line>line) { /*start new loop*/ break; } else { ttype = g_scanner_get_next_token (scanner); g_scanner_unexp_token (scanner, G_TOKEN_NONE, NULL, NULL, NULL, "bad value for fps", FALSE); } } } else if (strcmp(name,"fps_display")==0) { if(global->flg_FpsCount < 1) global->FpsCount = (short) scanner->value.v_int; } else if (g_strcmp0(name,"auto_focus")==0) { global->autofocus = scanner->value.v_int; } else if (g_strcmp0(name,"bpp")==0) { global->bpp = scanner->value.v_int; } else if (g_strcmp0(name,"hwaccel")==0) { if(global->flg_hwaccel < 1) global->hwaccel = scanner->value.v_int; } else if (g_strcmp0(name,"vid_codec")==0 || (g_strcmp0(name,"avi_format")==0)) { global->VidCodec = scanner->value.v_int; } else if (g_strcmp0(name,"vid_format")==0) { global->VidFormat = scanner->value.v_int; } else if ((g_strcmp0(name,"vid_inc")==0) || (g_strcmp0(name,"avi_inc")==0)) { global->vid_inc = (DWORD) scanner->value.v_int; } else if (g_strcmp0(name,"sound")==0) { global->Sound_enable = (short) scanner->value.v_int; } else if (g_strcmp0(name,"snd_api")==0) { global->Sound_API = scanner->value.v_int; } else if (g_strcmp0(name,"snd_device")==0) { global->Sound_UseDev = scanner->value.v_int; } else if (g_strcmp0(name,"snd_samprate")==0) { global->Sound_SampRateInd = scanner->value.v_int; } else if (g_strcmp0(name,"snd_numchan")==0) { global->Sound_NumChanInd = scanner->value.v_int; } else if (g_strcmp0(name,"snd_delay")==0) { global->Sound_delay = scanner->value.v_int64; } else if (g_strcmp0(name,"aud_codec")==0) { global->AudCodec = scanner->value.v_int; global->Sound_Format = get_aud4cc(global->AudCodec); } else if (g_strcmp0(name,"frame_flags")==0) { global->Frame_Flags = scanner->value.v_int; } else if (g_strcmp0(name,"osd_flags")==0) { global->osdFlags = scanner->value.v_int; } else if (g_strcmp0(name,"image_inc")==0) { global->image_inc = (DWORD) scanner->value.v_int; } else if (g_strcmp0(name,"acodec_bit_rate")==0) { ac_bit_rate = scanner->value.v_int; } else if (g_strcmp0(name,"vcodec_bit_rate")==0) { vc_bit_rate = scanner->value.v_int; } else if (g_strcmp0(name,"vcodec_fps")==0) { vc_fps = scanner->value.v_int; } else if (g_strcmp0(name,"vcodec_monotonic_pts")==0) { vc_monotonic_pts = scanner->value.v_int; } else if (g_strcmp0(name,"vcodec_qmax")==0) { vc_qmax = scanner->value.v_int; } else if (g_strcmp0(name,"vcodec_qmin")==0) { vc_qmin = scanner->value.v_int; } else if (g_strcmp0(name,"vcodec_max_qdiff")==0) { vc_max_qdiff = scanner->value.v_int; } else if (g_strcmp0(name,"vcodec_dia")==0) { vc_dia = scanner->value.v_int; } else if (g_strcmp0(name,"vcodec_pre_dia")==0) { vc_pre_dia = scanner->value.v_int; } else if (g_strcmp0(name,"vcodec_pre_me")==0) { vc_pre_me= scanner->value.v_int; } else if (g_strcmp0(name,"vcodec_me_pre_cmp")==0) { vc_me_pre_cmp = scanner->value.v_int; } else if (g_strcmp0(name,"vcodec_me_cmp")==0) { vc_me_cmp = scanner->value.v_int; } else if (g_strcmp0(name,"vcodec_me_sub_cmp")==0) { vc_me_sub_cmp = scanner->value.v_int; } else if (g_strcmp0(name,"vcodec_last_pred")==0) { vc_last_pred = scanner->value.v_int; } else if (g_strcmp0(name,"vcodec_gop_size")==0) { vc_gop_size = scanner->value.v_int; } else if (g_strcmp0(name,"vcodec_subq")==0) { vc_subq = scanner->value.v_int; } else if (g_strcmp0(name,"vcodec_framerefs")==0) { vc_framerefs = scanner->value.v_int; } else if (g_strcmp0(name,"vcodec_mb_decision")==0) { vc_mb_decision = scanner->value.v_int; } else if (g_strcmp0(name,"vcodec_trellis")==0) { vc_trellis = scanner->value.v_int; } else if (g_strcmp0(name,"vcodec_me_method")==0) { vc_me_method = scanner->value.v_int; } else if (g_strcmp0(name,"vcodec_mpeg_quant")==0) { vc_mpeg_quant = scanner->value.v_int; } else if (g_strcmp0(name,"vcodec_max_b_frames")==0) { vc_max_b_frames = scanner->value.v_int; } else if (g_strcmp0(name,"vcodec_flags")==0) { vc_flags = scanner->value.v_int; } else if (g_strcmp0(name,"vcodec_num_threads")==0) { vc_num_threads = scanner->value.v_int; } else { printf("unexpected integer value (%lu) for %s\n", scanner->value.v_int, name); printf("Strings must be quoted\n"); } } else if (ttype==G_TOKEN_FLOAT) { if (g_strcmp0(name,"vcodec_qcompress")==0) { vc_qcompress = scanner->value.v_float; } else if (g_strcmp0(name,"vcodec_qblur")==0) { vc_qblur = scanner->value.v_float; } else printf("unexpected float value (%f) for %s\n", scanner->value.v_float, name); } else if (ttype==G_TOKEN_CHAR) { printf("unexpected char value (%c) for %s\n", scanner->value.v_char, name); } else { g_scanner_unexp_token (scanner, G_TOKEN_NONE, NULL, NULL, NULL, "string values must be quoted - skiping", FALSE); int line = g_scanner_cur_line (scanner); int stp=0; do { ttype = g_scanner_peek_next_token (scanner); if(scanner->next_line > line) { //printf("next line reached\n"); stp=1; break; } else { ttype = g_scanner_get_next_token (scanner); } } while (!stp); } } g_free(name); } } g_scanner_destroy (scanner); close (fd); //get pointers to codec properties vcodecs_data *vcodec_defaults = get_codec_defaults(global->VidCodec); acodecs_data *acodec_defaults = get_aud_codec_defaults(get_ind_by4cc(global->Sound_Format)); if (ac_bit_rate >= 0) acodec_defaults->bit_rate = ac_bit_rate; if (vc_bit_rate >= 0) vcodec_defaults->bit_rate = vc_bit_rate; if (vc_fps >= 0) vcodec_defaults->fps = vc_fps; //from 1.5.3 onwards we set version on conf file and monotonic is set by default for all codecs if ((vc_monotonic_pts >= 0) && (VMAJOR > 0)) vcodec_defaults->monotonic_pts = vc_monotonic_pts; if (vc_qmax >= 0) vcodec_defaults->qmax = vc_qmax; if (vc_qmin >= 0) vcodec_defaults->qmin = vc_qmin; if (vc_max_qdiff >=0) vcodec_defaults->max_qdiff = vc_max_qdiff; if (vc_dia >=0) vcodec_defaults->dia = vc_dia; if (vc_pre_dia >=0) vcodec_defaults->pre_dia = vc_pre_dia; if (vc_pre_me >=0) vcodec_defaults->pre_me = vc_pre_me; if (vc_me_pre_cmp >=0) vcodec_defaults->me_pre_cmp = vc_me_pre_cmp; if (vc_me_cmp >=0) vcodec_defaults->me_cmp = vc_me_cmp; if (vc_me_sub_cmp >=0) vcodec_defaults->me_sub_cmp = vc_me_sub_cmp; if (vc_last_pred >= 0) vcodec_defaults->last_pred = vc_last_pred; if (vc_gop_size >= 0) vcodec_defaults->gop_size = vc_gop_size; if (vc_subq >=0) vcodec_defaults->subq = vc_subq; if (vc_framerefs >=0) vcodec_defaults->framerefs = vc_framerefs; if (vc_mb_decision >=0) vcodec_defaults->mb_decision = vc_mb_decision; if (vc_trellis >=0) vcodec_defaults->trellis = vc_trellis; if (vc_me_method >=0) vcodec_defaults->me_method = vc_me_method; if (vc_mpeg_quant >=0) vcodec_defaults->mpeg_quant = vc_mpeg_quant; if (vc_max_b_frames >=0) vcodec_defaults->max_b_frames = vc_max_b_frames; if (vc_num_threads >=0) vcodec_defaults->num_threads = vc_num_threads; if (vc_flags >=0) vcodec_defaults->flags = vc_flags; if (vc_qcompress >= 0) vcodec_defaults->qcompress = vc_qcompress; if (vc_qblur >=0) vcodec_defaults->qblur = vc_qblur; if(global->vid_inc>0) { uint64_t suffix = get_file_suffix(global->vidFPath[1], global->vidFPath[0]); fprintf(stderr, "Video file suffix detected: %" PRIu64 "\n", suffix); if(suffix >= G_MAXUINT64) { global->vidFPath[0] = add_file_suffix(global->vidFPath[0], suffix); suffix = 0; } if(suffix > 0) global->vid_inc = suffix + 1; } if(global->image_inc>0) { uint64_t suffix = get_file_suffix(global->imgFPath[1], global->imgFPath[0]); fprintf(stderr, "Image file suffix detected: %" PRIu64 "\n", suffix); if(suffix >= G_MAXUINT64) { global->imgFPath[0] = add_file_suffix(global->imgFPath[0], suffix); suffix = 0; } if(suffix > 0) global->image_inc = suffix + 1; } if (global->debug) { g_print("video_device: %s\n",global->videodevice); g_print("vid_sleep: %i\n",global->vid_sleep); g_print("cap_meth: %i\n",global->cap_meth); g_print("resolution: %i x %i\n",global->width,global->height); g_print("windowsize: %i x %i\n",global->winwidth,global->winheight); g_print("spin behavior: %i\n",global->spinbehave); g_print("default action: %i\n",global->default_action); g_print("mode: %s\n",global->mode); g_print("fps: %i/%i\n",global->fps_num,global->fps); g_print("Display Fps: %i\n",global->FpsCount); g_print("bpp: %i\n",global->bpp); g_print("hwaccel: %i\n",global->hwaccel); g_print("avi_format: %i\n",global->VidCodec); g_print("sound: %i\n",global->Sound_enable); g_print("sound Device: %i\n",global->Sound_UseDev); g_print("sound samp rate: %i\n",global->Sound_SampRateInd); g_print("sound Channels: %i\n",global->Sound_NumChanInd); g_print("Sound delay: %llu nanosec\n",(unsigned long long) global->Sound_delay); g_print("Sound Format: %i \n",global->Sound_Format); g_print("Pan Step: %i degrees\n",global->PanStep); g_print("Tilt Step: %i degrees\n",global->TiltStep); g_print("Video Filter Flags: %i\n",global->Frame_Flags); g_print("image inc: %" PRIu64 "\n",global->image_inc); g_print("profile(default):%s/%s\n",global->profile_FPath[1],global->profile_FPath[0]); } } return (ret); }
int main(int argc, char **argv) { struct usb_vendprod vendprod; struct dfu_if _rt_dif, _dif, *dif = &_dif; int num_devs; int num_ifs; unsigned int transfer_size = 0; enum mode mode = MODE_NONE; struct dfu_status status; int quirks_auto_detect = 1; dfu_quirks manual_quirks; dfu_handle handle; char *filename = NULL; char *alt_name = NULL; /* query alt name if non-NULL */ char *end; int final_reset = 0; int page_size = getpagesize(); int ret; printf("dfu-util - (C) 2007-2008 by OpenMoko Inc.\n" "This program is Free Software and has ABSOLUTELY NO WARRANTY\n\n"); dfu_quirks_clear(&manual_quirks); memset(dif, 0, sizeof(*dif)); usb_init(); //usb_set_debug(255); usb_find_busses(); usb_find_devices(); while (1) { int c, option_index = 0; c = getopt_long(argc, argv, "hVvld:p:c:i:a:t:U:D:C:S:RQNq:", opts, &option_index); if (c == -1) break; switch (c) { case 'h': help(); exit(0); break; case 'V': print_version(); exit(0); break; case 'v': verbose = 1; break; case 'l': list_dfu_interfaces(); exit(0); break; case 'd': /* Parse device */ if (parse_vendprod(&vendprod, optarg) < 0) { fprintf(stderr, "unable to parse `%s'\n", optarg); exit(2); } dif->vendor = vendprod.vendor; dif->product = vendprod.product; dif->flags |= (DFU_IFF_VENDOR | DFU_IFF_PRODUCT); break; case 'p': /* Parse device path */ dif->path = optarg; dif->flags |= DFU_IFF_PATH; ret = resolve_device_path(dif); if (ret < 0) { fprintf(stderr, "unable to parse `%s'\n", optarg); exit(2); } if (!ret) { fprintf(stderr, "cannot find `%s'\n", optarg); exit(1); } break; case 'c': /* Configuration */ dif->configuration = atoi(optarg); dif->flags |= DFU_IFF_CONFIG; break; case 'i': /* Interface */ dif->interface = atoi(optarg); dif->flags |= DFU_IFF_IFACE; break; case 'a': /* Interface Alternate Setting */ dif->altsetting = strtoul(optarg, &end, 0); if (*end) alt_name = optarg; dif->flags |= DFU_IFF_ALT; break; case 't': transfer_size = atoi(optarg); break; case 'U': mode = MODE_UPLOAD; filename = optarg; break; case 'D': mode = MODE_DOWNLOAD; filename = optarg; break; case 'C': mode = MODE_COMPARE; /* TODO: verify firmware */ filename = optarg; break; case 'S': filename = optarg; add_file_suffix(filename); exit(0); break; case 'R': final_reset = 1; break; case 'Q': dfu_quirks_print(); exit(0); break; case 'N': quirks_auto_detect = 0; break; case 'q': quirks_auto_detect = 0; dfu_quirk_set(&manual_quirks, atoi(optarg)); break; default: help(); exit(2); } } if (mode == MODE_NONE) { fprintf(stderr, "You need to specify one of -D or -U\n"); help(); exit(2); } if (!filename) { fprintf(stderr, "You need to specify a filename to -D -r -U\n"); help(); exit(2); } dfu_init(&handle, 5000); num_devs = count_dfu_devices(dif); if (num_devs == 0) { fprintf(stderr, "No DFU capable USB device found\n"); exit(1); } else if (num_devs > 1) { /* We cannot safely support more than one DFU capable device * with same vendor/product ID, since during DFU we need to do * a USB bus reset, after which the target device will get a * new address */ fprintf(stderr, "More than one DFU capable USB device found, " "you might try `--list' and then disconnect all but one " "device\n"); exit(3); } if (!get_first_dfu_device(dif)) exit(3); /* We have exactly one device. It's usb_device is now in dif->dev */ printf("Opening USB Device 0x%04x:0x%04x...\n", dif->vendor, dif->product); dif->dev_handle = usb_open(dif->dev); if (!dif->dev_handle) { fprintf(stderr, "Cannot open device: %s\n", usb_strerror()); exit(1); } /* try to find first DFU interface of device */ memcpy(&_rt_dif, dif, sizeof(_rt_dif)); if (!get_first_dfu_if(&_rt_dif)) exit(1); handle.device = _rt_dif.dev_handle; handle.interface = _rt_dif.interface; /* automatic quirk detection */ if(quirks_auto_detect) { /* TODO: let the detection be influenced by bcdDFU, bcdDevice */ handle.quirk_flags = dfu_quirks_detect(0, dif->vendor, dif->product, 0); } /* merge with manual quirks */ dfu_quirks_insert(&handle.quirk_flags, &manual_quirks); if(!dfu_quirks_is_empty(&handle.quirk_flags)) { printf("Selected quirks: "); dfu_quirks_print_set(&handle.quirk_flags); printf("\n"); } if (!_rt_dif.flags & DFU_IFF_DFU) { /* In the 'first round' during runtime mode, there can only be one * DFU Interface descriptor according to the DFU Spec. */ /* FIXME: check if the selected device really has only one */ printf("Claiming USB DFU Runtime Interface %d...\n", _rt_dif.interface); if (usb_claim_interface(_rt_dif.dev_handle, _rt_dif.interface) < 0) { fprintf(stderr, "Cannot claim interface: %s\n", usb_strerror()); exit(1); } /* DFU 1.0, Table 4.1: in runtime-mode, alternate interface setting must be zero. therefore we can assume, '0' is correct. the reason we use usb_set_altinterface() here: switch devices to the interface set using usb_claim_interface() above - for some reason this isn't done there. is the only libusb API which issues the SET_INTERFACE USB standard request is usb_set_altinterface() */ if (usb_set_altinterface(_rt_dif.dev_handle, 0) < 0) { fprintf(stderr, "Cannot set alternate interface %d: %s\n", 0, usb_strerror()); exit(1); } printf("Determining device state: "); int state = -1; if ( (state = dfu_get_state(&handle)) < 0) { exit(1); } printf("state = %s\n", dfu_state_to_string(state)); dfu_sm_set_state_unchecked(&handle, state); printf("Determining device status: "); if (dfu_get_status(&handle, &status ) < 0) { exit(1); } printf("state = %s, status = %d = \"%s\"\n", dfu_state_to_string(status.bState), status.bStatus, dfu_status_to_string(status.bStatus) ); switch (status.bState) { case DFU_STATE_appIDLE: case DFU_STATE_appDETACH: printf("Device really in Runtime Mode, send DFU " "detach request...\n"); if(status.bState == DFU_STATE_appDETACH) { printf("Device is already in state %s, skipping DFU_DETACH request\n", dfu_state_to_string(status.bState)); } else { if (dfu_detach(&handle, 1000) < 0) { exit(1); break; } } /* handle bitWillDetach (DFU 1.1) */ if(handle.dfu_ver == DFU_VERSION_1_1 && handle.func_dfu.bmAttributes & USB_DFU_WILL_DETACH) { /* TODO: test this with a real DFU 1.1 device */ printf("Waiting for USB device's own detach (bitWillDetach=1)...\n"); dfu_sm_set_state_checked(&handle, DFU_STATE_dfuIDLE); } else { printf("Resetting USB...\n"); ret = dfu_usb_reset(&handle); if (ret < 0 && ret != -ENODEV) { /* do nothing; error msg is output in dfu_usb_reset. */ } } sleep(2); break; case DFU_STATE_dfuERROR: printf("dfuERROR, clearing status\n"); if (dfu_clear_status(&handle) < 0) { exit(1); break; } break; default: fprintf(stderr, "WARNING: Runtime device already " "in DFU state ?!?\n"); goto dfustate; break; } /* now we need to re-scan the bus and locate our device */ if (usb_find_devices() < 2) printf("not at least 2 device changes found ?!?\n"); if (dif->flags & DFU_IFF_PATH) { ret = resolve_device_path(dif); if (ret < 0) { fprintf(stderr, "internal error: cannot re-parse `%s'\n", dif->path); abort(); } if (!ret) { fprintf(stderr, "Can't resolve path after RESET?\n"); exit(1); } } num_devs = count_dfu_devices(dif); if (num_devs == 0) { fprintf(stderr, "Lost device after RESET?\n"); exit(1); } else if (num_devs > 1) { fprintf(stderr, "More than one DFU capable USB " "device found, you might try `--list' and " "then disconnect all but one device\n"); exit(1); } if (!get_first_dfu_device(dif)) exit(3); printf("Opening USB Device...\n"); dif->dev_handle = usb_open(dif->dev); if (!dif->dev_handle) { fprintf(stderr, "Cannot open device: %s\n", usb_strerror()); exit(1); } } else { /* we're already in DFU mode, so we can skip the detach/reset * procedure */ } dfustate: if (alt_name) { int n; n = find_dfu_if(dif->dev, &alt_by_name, alt_name); if (!n) { fprintf(stderr, "No such Alternate Setting: \"%s\"\n", alt_name); exit(1); } if (n < 0) { fprintf(stderr, "Error %d in name lookup\n", n); exit(1); } dif->altsetting = n-1; } print_dfu_if(dif, NULL); num_ifs = count_dfu_interfaces(dif->dev); if (num_ifs < 0) { fprintf(stderr, "No DFU Interface after RESET?!?\n"); exit(1); } else if (num_ifs == 1) { if (!get_first_dfu_if(dif)) { fprintf(stderr, "Can't find the single available " "DFU IF\n"); exit(1); } } else if (num_ifs > 1 && (!dif->flags) & (DFU_IFF_IFACE|DFU_IFF_ALT)) { fprintf(stderr, "We have %u DFU Interfaces/Altsettings, " "you have to specify one via --intf / --alt options\n", num_ifs); exit(1); } #if 0 printf("Setting Configuration %u...\n", dif->configuration); if (usb_set_configuration(dif->dev_handle, dif->configuration) < 0) { fprintf(stderr, "Cannot set configuration: %s\n", usb_strerror()); exit(1); } #endif printf("Claiming USB DFU Interface...\n"); if (usb_claim_interface(dif->dev_handle, dif->interface) < 0) { fprintf(stderr, "Cannot claim interface: %s\n", usb_strerror()); exit(1); } printf("Setting Alternate Setting ...\n"); if (usb_set_altinterface(dif->dev_handle, dif->altsetting) < 0) { fprintf(stderr, "Cannot set alternate interface: %s\n", usb_strerror()); exit(1); } /* update the handle to point to the dfu-mode descriptor */ handle.device = dif->dev_handle; handle.interface = dif->interface; status_again: printf("Determining device status: "); if (dfu_get_status(&handle, &status ) < 0) { fprintf(stderr, "error get_status: %s\n", usb_strerror()); exit(1); } printf("state = %s, status = %d\n", dfu_state_to_string(status.bState), status.bStatus); /* force the statemachine into current status */ dfu_sm_set_state_unchecked(&handle, status.bState); switch (status.bState) { case DFU_STATE_appIDLE: case DFU_STATE_appDETACH: fprintf(stderr, "Device still in Runtime Mode!\n"); exit(1); break; case DFU_STATE_dfuERROR: printf("dfuERROR, clearing status\n"); if (dfu_clear_status(&handle) < 0) { fprintf(stderr, "error clear_status: %s\n", usb_strerror()); exit(1); } goto status_again; break; case DFU_STATE_dfuDNLOAD_IDLE: case DFU_STATE_dfuUPLOAD_IDLE: printf("aborting previous incomplete transfer\n"); if (dfu_abort(&handle) < 0) { fprintf(stderr, "can't send DFU_ABORT: %s\n", usb_strerror()); exit(1); } goto status_again; break; case DFU_STATE_dfuIDLE: printf("dfuIDLE, continuing\n"); break; } /* Obtain DFU functional descriptor */ ret = usb_get_descriptor(dif->dev_handle, 0x21, dif->interface, &(handle.func_dfu), sizeof(handle.func_dfu)); if (ret < 0) { fprintf(stderr, "Error obtaining DFU functional " "descriptor: %s\n", usb_strerror()); if(dfu_quirk_is_set(&handle.quirk_flags, QUIRK_IGNORE_INVALID_FUNCTIONAL_DESCRIPTOR)) { handle.func_dfu.bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_CAN_UPLOAD | USB_DFU_MANIFEST_TOL; handle.func_dfu.wTransferSize = cpu_to_le16(transfer_size); if(!transfer_size) transfer_size = page_size; handle.func_dfu.bcdDFUVersion = USB_DFU_VER_1_0; fprintf(stderr, " Still, try to continue with default flags/manual settings.\n"); } else { exit(1); } } else { transfer_size = le16_to_cpu(handle.func_dfu.wTransferSize); } /* why is this limited to page_size, a host-dependent value? (sgiessl) */ if (transfer_size > page_size) transfer_size = page_size; /* quirk overwriting DFU version */ if(dfu_quirk_is_set(&handle.quirk_flags, QUIRK_FORCE_DFU_VERSION_1_0)) { handle.func_dfu.bcdDFUVersion = USB_DFU_VER_1_0; } else if(dfu_quirk_is_set(&handle.quirk_flags, QUIRK_FORCE_DFU_VERSION_1_1)) { handle.func_dfu.bcdDFUVersion = USB_DFU_VER_1_1; } /* read DFU version */ switch(handle.func_dfu.bcdDFUVersion) { case USB_DFU_VER_1_1: handle.dfu_ver = DFU_VERSION_1_1; break; default: printf("WARNING: device specifies unknown DFU version 0x%.2x, defaulting to DFU 1.0\n", handle.func_dfu.bcdDFUVersion); /* fall through intended */ case USB_DFU_VER_1_0: handle.dfu_ver = DFU_VERSION_1_0; break; } printf("Transfer Size = 0x%04x\n", transfer_size); printf("Device functional descriptor: %s\n", dfu_func_descriptor_to_string(&handle.func_dfu)); if (DFU_STATUS_OK != status.bStatus ) { printf("WARNING: DFU Status: '%s'\n", dfu_status_to_string(status.bStatus)); /* Clear our status & try again. */ dfu_clear_status(&handle); dfu_get_status(&handle, &status); if (DFU_STATUS_OK != status.bStatus) { fprintf(stderr, "Error: %d\n", status.bStatus); exit(1); } } switch (mode) { case MODE_UPLOAD: if (sam7dfu_do_upload(&handle, transfer_size, filename) < 0) exit(1); break; case MODE_DOWNLOAD: if (sam7dfu_do_dnload(&handle, transfer_size, filename) < 0) exit(1); break; default: fprintf(stderr, "Unsupported mode: %u\n", mode); exit(1); } if (final_reset) { if(dfu_quirk_is_set(&handle.quirk_flags, QUIRK_OPENMOKO_DETACH_BEFORE_FINAL_RESET)) { /* DFU_DETACH is only allowed in appIDLE, so this is non-standard (as of DFU 1.0, and 1.1). */ printf("Initiating reset by sending DFU_DETACH (QUIRK_OPENMOKO_DETACH_BEFORE_FINAL_RESET)\n"); if (dfu_detach(&handle, 1000) < 0) { fprintf(stderr, "can't detach: %s\n", usb_strerror()); } } printf("Resetting USB to switch back to runtime mode\n"); ret = usb_reset(dif->dev_handle); if (ret < 0 && ret != -ENODEV) { fprintf(stderr, "error resetting after download: %s\n", usb_strerror()); } } exit(0); }