liblavrec.c
来自「Motion JPEG编解码器源代码」· C语言 代码 · 共 1,916 行 · 第 1/5 页
C
1,916 行
{ int fd = lav_fileno( settings->video_file ); if( fd >= 0 ) fdatasync(fd); } return 1;}static int video_captured(lavrec_t *info, uint8_t *buff, long size, long count){ if (info->files) return lavrec_output_video_frame(info, buff, size, count); else info->video_captured(buff, size, count); return 1;}/****************************************************** * lavrec_output_audio_to_file() * writes audio data to a file * * return value: 1 on success, 0 on error ******************************************************/static int lavrec_output_audio_to_file(lavrec_t *info, uint8_t *buff, long samps, int old){ video_capture_setup *settings = (video_capture_setup *)info->settings; if(samps==0) return 1; /* Output data */ if (lav_write_audio(old?settings->video_file_old:settings->video_file,buff,samps)) { /* If an error happened, try to close output files and exit */ lavrec_msg(LAVREC_MSG_ERROR, info, "Error writing to output file: %s", lav_strerror()); lavrec_close_files_on_error(info); return 0; } /* update counters */ settings->stats->num_asamps += samps; if (!old) settings->bytes_output_cur += samps * settings->audio_bps; return 1;}/****************************************************** * lavrec_output_audio_samples() * outputs audio samples to files * * return value: 1 on success, 0 or -1 on error ******************************************************/static int lavrec_output_audio_samples(lavrec_t *info, uint8_t *buff, long samps){ long diff = 0; video_capture_setup *settings = (video_capture_setup *)info->settings; /* Safety first */ if(!settings->output_status) { lavrec_msg(LAVREC_MSG_ERROR, info, "**INTERNAL ERROR: Output audio but no file open"); return -1; } if(settings->output_status<2) { /* Normal mode, just output the sample */ return lavrec_output_audio_to_file(info, buff, samps, 0); } /* if we come here, we have to fill up the old file first */ diff = (settings->num_frames_old * settings->spvf - settings->stats->num_asamps * settings->spas) * info->audio_rate; if(diff<0) { lavrec_msg(LAVREC_MSG_ERROR, info, "**INTERNAL ERROR: Audio output ahead video output"); return -1; } if(diff >= samps) { /* All goes to old file */ return lavrec_output_audio_to_file(info, buff, samps, 1); } /* diff samples go to old file */ if (!lavrec_output_audio_to_file(info, buff, diff, 1)) return 0; /* close old file */ lavrec_msg(LAVREC_MSG_DEBUG, info, "Audio is filled - closing old file"); if (settings->video_file_old) { if (lav_close(settings->video_file_old)) { settings->video_file_old = NULL; lavrec_msg(LAVREC_MSG_ERROR, info, "Error closing video output file, may be unuseable due to error: %s", lav_strerror()); return 0; } settings->video_file_old = NULL; } /* Check if we are ready */ if (settings->output_status==3) return 0; /* remaining samples go to new file */ settings->output_status = 1; return lavrec_output_audio_to_file(info, buff+diff*settings->audio_bps, samps-diff, 0);}static int audio_captured(lavrec_t *info, uint8_t *buff, long samps){ if (info->files) return lavrec_output_audio_samples(info, buff, samps); else info->audio_captured(buff, samps); return 1;}/****************************************************** * lavrec_encoding_thread() * The software encoding thread ******************************************************/static void *lavrec_encoding_thread(void* arg){ encoder_info_t *w_info = (encoder_info_t *)arg; lavrec_t *info = w_info->info; video_capture_setup *settings = (video_capture_setup *)info->settings; struct timeval timestamp[MJPEG_MAX_BUF]; int jpegsize; unsigned long current_frame = w_info->encoder_id; unsigned long predecessor_frame; lavrec_msg(LAVREC_MSG_DEBUG, info, "Starting software encoding thread"); /* Allow easy shutting down by other processes... */ /* PTHREAD_CANCEL_ASYNCHRONOUS is evil pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, NULL ); pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL ); */ while (settings->state == LAVREC_STATE_RECORDING) { pthread_cleanup_push((void (*)(void*))pthread_mutex_unlock, &settings->encoding_mutex); pthread_mutex_lock(&(settings->encoding_mutex)); while (settings->buffer_valid[current_frame] == -1) { lavrec_msg(LAVREC_MSG_DEBUG, info, "Encoding thread: sleeping for new frames (waiting for frame %ld)", current_frame); pthread_cond_wait(&(settings->buffer_filled[current_frame]), &(settings->encoding_mutex)); if (settings->please_stop_syncing) { pthread_mutex_unlock(&(settings->encoding_mutex)); pthread_exit(NULL); } } memcpy(&(timestamp[current_frame]), &(settings->bsync.timestamp), sizeof(struct timeval)); if (settings->buffer_valid[current_frame] > 0) { /* There is no cancellation point in this block, but just to make sure... */ pthread_cleanup_push((void (*)(void*))pthread_mutex_lock, &settings->encoding_mutex); pthread_mutex_unlock(&(settings->encoding_mutex)); jpegsize = encode_jpeg_raw((unsigned char*)(settings->MJPG_buff+current_frame*settings->breq.size), settings->breq.size, info->quality, settings->interlaced, CHROMA422, info->geometry->w, info->geometry->h, settings->YUV_buff+settings->softreq.offsets[current_frame], settings->YUV_buff+settings->softreq.offsets[current_frame]+(info->geometry->w*info->geometry->h), settings->YUV_buff+settings->softreq.offsets[current_frame]+(info->geometry->w*info->geometry->h*3/2)); if (jpegsize<0) { lavrec_msg(LAVREC_MSG_ERROR, info, "Error encoding frame to JPEG"); lavrec_change_state(info, LAVREC_STATE_STOP); pthread_exit(0); } pthread_cleanup_pop(1); } else { jpegsize = 0; /* Just toss the frame */ } /* Writing of video and audio data is non-reentrant and must * occur in-order - acquire lock and wait for preceding * frame's encoder to have completed writing that frames data * * Note that we need to queue the buffers in order, too, * so we need to sync up here even if we're discarding * the frame. */ predecessor_frame = ( (current_frame + settings->softreq.frames-1) % settings->softreq.frames ); while( !settings->buffer_completed[predecessor_frame] ) { pthread_cond_wait(&(settings->buffer_completion[predecessor_frame]), &(settings->encoding_mutex)); } if (jpegsize > 0) { if (video_captured(info, settings->MJPG_buff+(settings->breq.size*current_frame), jpegsize, settings->buffer_valid[current_frame]) != 1) { lavrec_msg(LAVREC_MSG_ERROR, info, "Error writing the frame"); lavrec_change_state(info, LAVREC_STATE_STOP); pthread_exit(0); } }#if 0 if (!lavrec_queue_buffer(info, ¤t_frame)) { if (info->files) lavrec_close_files_on_error(info); lavrec_msg(LAVREC_MSG_ERROR, info, "Error re-queuing buffer: %s", strerror(errno)); lavrec_change_state(info, LAVREC_STATE_STOP); pthread_exit(0); } /* Mark the capture buffer as once again as in progress for capture */ settings->buffer_valid[current_frame] = -1;#endif /* hack for BTTV-0.8 - give it a status that tells us to queue it in another thread */ settings->buffer_valid[current_frame] = -2; if (!lavrec_handle_audio(info, &(timestamp[current_frame]))) lavrec_change_state(info, LAVREC_STATE_STOP); /* Mark this frame as having completed compression and writing, * signal any encoders waiting for this completion so they can write * out their own results, and release lock. */ settings->buffer_completed[current_frame] = 1; pthread_cond_broadcast(&(settings->buffer_completion[current_frame])); current_frame = (current_frame+w_info->num_encoders)%settings->softreq.frames; pthread_cleanup_pop(1); } pthread_exit(NULL); return(NULL);}/****************************************************** * lavrec_software_init() * Some software-MJPEG encoding specific initialization * * return value: 1 on success, 0 on error ******************************************************/static int lavrec_software_init(lavrec_t *info){ struct video_capability vc; int i; video_capture_setup *settings = (video_capture_setup *)info->settings; if (ioctl(settings->video_fd, VIDIOCGCAP, &vc) < 0) { lavrec_msg(LAVREC_MSG_ERROR, info, "Error getting device capabilities: %s", strerror(errno)); return 0; } /* vc.maxwidth is often reported wrong - let's just keep it broken (sigh) */ /*if (vc.maxwidth != 768 && vc.maxwidth != 640) vc.maxwidth = 720;*/ /* set some "subcapture" options - cropping is done later on (during capture) */ if(!info->geometry->w) info->geometry->w = ((vc.maxwidth==720&&info->horizontal_decimation!=1)?704:vc.maxwidth)/4; if(!info->geometry->h) info->geometry->h = (info->video_norm==1 ? 480 : 576)/4; if (info->geometry->w > vc.maxwidth) { lavrec_msg(LAVREC_MSG_ERROR, info, "Image width (%d) bigger than maximum (%d)!", info->geometry->w, vc.maxwidth); return 0; } if ((info->geometry->w%16)!=0) { lavrec_msg(LAVREC_MSG_ERROR, info, "Image width (%d) not multiple of 16 (required for JPEG encoding)!", info->geometry->w); return 0; } if (info->geometry->h > (info->video_norm==1 ? 480 : 576)) { lavrec_msg(LAVREC_MSG_ERROR, info, "Image height (%d) bigger than maximum (%d)!", info->geometry->h, (info->video_norm==1 ? 480 : 576)); return 0; } /* RJ: Image height must only be a multiple of 8, but geom_height * is double the field height */ if ((info->geometry->h%16)!=0) { lavrec_msg(LAVREC_MSG_ERROR, info, "Image height (%d) not multiple of 16 (required for JPEG encoding)!", info->geometry->h); return 0; } settings->mm.width = settings->width = info->geometry->w; settings->mm.height = settings->height = info->geometry->h; settings->mm.format = VIDEO_PALETTE_YUV422P; if (info->geometry->h > (info->video_norm==1?320:384)) settings->interlaced = LAV_INTER_TOP_FIRST; /* all interlaced BT8x8 capture seems top-first ?? */ else settings->interlaced = LAV_NOT_INTERLACED; lavrec_msg(LAVREC_MSG_INFO, info, "Image size will be %dx%d, %d field(s) per buffer", info->geometry->w, info->geometry->h, (settings->interlaced==LAV_NOT_INTERLACED)?1:2); /* request buffer info */ if (ioctl(settings->video_fd, VIDIOCGMBUF, &(settings->softreq)) < 0) { lavrec_msg(LAVREC_MSG_ERROR, info, "Error getting buffer information: %s", strerror(errno)); return 0; } if (settings->softreq.frames < MIN_QUEUES_NEEDED) { lavrec_msg(LAVREC_MSG_ERROR, info, "We need at least %d buffers, but we only got %d", MIN_QUEUES_NEEDED, settings->softreq.frames); return 0; } lavrec_msg(LAVREC_MSG_INFO, info, "Got %d YUV-buffers of size %d KB", settings->softreq.frames, settings->softreq.size/(1024*settings->softreq.frames)); /* Map the buffers */ settings->YUV_buff = mmap(0, settings->softreq.size, PROT_READ|PROT_WRITE, MAP_SHARED, settings->video_fd, 0); if (settings->YUV_buff == MAP_FAILED) { lavrec_msg(LAVREC_MSG_ERROR, info, "Error mapping video buffers: %s", strerror(errno)); return 0; } /* set up buffers for software encoding thread */ if (info->MJPG_numbufs > MJPEG_MAX_BUF) { lavrec_msg(LAVREC_MSG_ERROR, info, "Too many buffers (%d) requested, maximum is %d", info->MJPG_numbufs, MJPEG_MAX_BUF); return 0; } /* Check number of JPEG compression worker threads is consistent with * with the number of buffers available */ if (info->num_encoders > info->MJPG_numbufs-1 ) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?