liblavrec.c
来自「Motion JPEG编解码器源代码」· C语言 代码 · 共 1,916 行 · 第 1/5 页
C
1,916 行
{ int n,res; lavrec_msg(LAVREC_MSG_INFO, info, "Getting audio ..."); for(n=0;;n++) { if(n > NUM_AUDIO_TRIES) { lavrec_msg(LAVREC_MSG_ERROR, info, "Unable to get audio - exiting ...."); return 0; } res = audio_read((unsigned char*)settings->AUDIO_buff,AUDIO_BUFFER_SIZE,0, &(settings->audio_t0),&(settings->astat)); if (res < 0) { lavrec_msg(LAVREC_MSG_ERROR, info, "Error reading audio: %s",audio_strerror()); return 0; } if(res && settings->audio_t0.tv_sec ) break; usleep(20000); } } /* If we can increase process priority ... no need for R/T though... * This is mainly useful for running using "at" which otherwise drops the * priority which causes sporadic audio buffer over-runs */ if( getpriority(PRIO_PROCESS, 0) > -5 ) setpriority(PRIO_PROCESS, 0, -5 ); /* Seconds per video frame: */ settings->spvf = (info->video_norm==VIDEO_MODE_NTSC) ? 1001./30000. : 0.040; settings->sync_lim = settings->spvf*1.5; /* Seconds per audio sample: */ if(info->audio_size) settings->spas = 1.0/info->audio_rate; else settings->spas = 0.; return 1;}/****************************************************** * lavrec_wait_for_start() * catch audio until we have to stop or record ******************************************************/static void lavrec_wait_for_start(lavrec_t *info){ int res; video_capture_setup *settings = (video_capture_setup *)info->settings; while(settings->state == LAVREC_STATE_PAUSED) { usleep(10000); /* Audio (if on) is allready running, empty buffer to avoid overflow */ if (info->audio_size) { while( (res=audio_read((unsigned char*)settings->AUDIO_buff,AUDIO_BUFFER_SIZE, 0,&settings->audio_t0,&settings->astat)) >0 ) /*noop*/; if(res==0) continue; if(res<0) { lavrec_msg(LAVREC_MSG_ERROR, info, "Error reading audio: %s", audio_strerror()); lavrec_change_state(info, LAVREC_STATE_STOP); /* stop */ return; } } }}/****************************************************** * lavrec_queue_buffer() * queues a buffer (either MJPEG or YUV) * * return value: 1 on success, 0 on error ******************************************************/static int lavrec_queue_buffer(lavrec_t *info, unsigned long *num){ video_capture_setup *settings = (video_capture_setup *)info->settings; lavrec_msg(LAVREC_MSG_DEBUG, info, "Queueing frame %lu", *num); if (info->software_encoding) { settings->mm.frame = *num; pthread_mutex_lock(&(settings->queue_mutex)); if (settings->is_queued[*num] < 0) { pthread_mutex_unlock(&(settings->queue_mutex)); return 1; } pthread_mutex_unlock(&(settings->queue_mutex)); if (ioctl(settings->video_fd, VIDIOCMCAPTURE, &(settings->mm)) < 0) return 0; pthread_mutex_lock(&(settings->queue_mutex)); settings->queue_left++; settings->is_queued[*num] = 1; settings->buffers_queued++; pthread_cond_broadcast(&(settings->queue_wait)); pthread_mutex_unlock(&(settings->queue_mutex)); } else { if (ioctl(settings->video_fd, MJPIOC_QBUF_CAPT, num) < 0) return 0; } return 1;}/****************************************************** * lavrec_software_sync_thread () * software syncing to get correct timestamps ******************************************************/static void *lavrec_software_sync_thread(void* arg){ lavrec_t *info = (lavrec_t *) arg; video_capture_setup *settings = (video_capture_setup *)info->settings; int frame = 0; /* framenum to sync on */#if 1 unsigned long qframe, i;#endif /* Allow easy shutting down by other processes... */ /* PTHREAD_CANCEL_ASYNCHRONOUS is evil pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, NULL ); pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL ); */ /* FIXME: is the right? Or can we just stop. * Don't allow cancellation. We need to shutdown in an orderly * fashion (by noticing that settings->state has changed, to make * sure we dequeue all queued buffers. */ pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, NULL ); while (1) { /* evil hack for BTTV-0.8 - we need to queue frames here */ /* this cycle is non-onbligatory - we just queue frames as they become available, * below, we'll wait for queues if we don't have enough of them */ for (i=0;i<settings->softreq.frames;i++) { qframe = settings->buffers_queued % settings->softreq.frames; if (settings->buffer_valid[qframe] == -2) { if (!lavrec_queue_buffer(info, &qframe)) { pthread_mutex_lock(&(settings->software_sync_mutex)); settings->software_sync_ready[qframe] = -1; pthread_cond_broadcast(&(settings->software_sync_wait[qframe])); pthread_mutex_unlock(&(settings->software_sync_mutex)); lavrec_msg(LAVREC_MSG_ERROR, info, "Error re-queueing a buffer (%lu): %s", qframe, strerror(errno)); lavrec_change_state(info, LAVREC_STATE_STOP); pthread_exit(0); } settings->buffer_valid[qframe] = -1; } else break; } pthread_mutex_lock(&(settings->encoding_mutex)); while (settings->queue_left < MIN_QUEUES_NEEDED) { if (settings->is_queued[frame] <= 0 || settings->please_stop_syncing) break; /* sync on all remaining frames */#if 0 lavrec_msg(LAVREC_MSG_DEBUG, info, "Software sync thread: sleeping for new queues (%d)", frame); pthread_cond_wait(&(settings->queue_wait), &(settings->queue_mutex));#else /* sleep for new buffers to be completed encoding. After that, * requeue them so we have more than MIN_QUEUES_NEEDED buffers * free */ qframe = settings->buffers_queued % settings->softreq.frames; lavrec_msg(LAVREC_MSG_DEBUG, info, "Software sync thread: sleeping for new queues (%lu) to become available", qframe); while (settings->buffer_valid[qframe] != -2) { pthread_cond_wait(&(settings->buffer_completion[qframe]), &(settings->encoding_mutex)); if (settings->please_stop_syncing) { pthread_mutex_unlock(&(settings->encoding_mutex)); pthread_exit(0); } } if (!lavrec_queue_buffer(info, &qframe)) { pthread_mutex_unlock(&(settings->encoding_mutex)); pthread_mutex_lock(&(settings->software_sync_mutex)); settings->software_sync_ready[qframe] = -1; pthread_cond_broadcast(&(settings->software_sync_wait[qframe])); pthread_mutex_unlock(&(settings->software_sync_mutex)); lavrec_msg(LAVREC_MSG_ERROR, info, "Error re-queueing a buffer (%lu): %s", qframe, strerror(errno)); lavrec_change_state(info, LAVREC_STATE_STOP); pthread_exit(0); } settings->buffer_valid[qframe] = -1;#endif } if (!settings->queue_left) { lavrec_msg(LAVREC_MSG_DEBUG, info, "Software sync thread stopped"); pthread_mutex_unlock(&settings->encoding_mutex); pthread_exit(NULL); } pthread_mutex_unlock(&settings->encoding_mutex); retry: if (ioctl(settings->video_fd, VIDIOCSYNC, &frame) < 0) { if (errno==EINTR && info->software_encoding) goto retry; /* BTTV sync got interrupted */ pthread_mutex_lock(&(settings->software_sync_mutex)); settings->software_sync_ready[frame] = -1; pthread_cond_broadcast(&(settings->software_sync_wait[frame])); pthread_mutex_unlock(&(settings->software_sync_mutex)); lavrec_msg(LAVREC_MSG_ERROR, info, "Error syncing on a buffer: %s", strerror(errno)); lavrec_change_state(info, LAVREC_STATE_STOP); pthread_exit(0); } else { pthread_mutex_lock(&(settings->software_sync_mutex)); gettimeofday(&(settings->software_sync_timestamp[frame]), NULL); settings->software_sync_ready[frame] = 1; pthread_cond_broadcast(&(settings->software_sync_wait[frame])); pthread_mutex_unlock(&(settings->software_sync_mutex)); } pthread_mutex_lock(&(settings->queue_mutex)); settings->queue_left--; settings->is_queued[frame] = 0; pthread_mutex_unlock(&(settings->queue_mutex)); frame = (frame+1)%settings->softreq.frames; } return NULL;}/****************************************************** * lavrec_sync_buffer() * sync on a buffer (either MJPIOC_SYNC or VIDIOCSYNC) * * return value: 1 on success, 0 on error ******************************************************/static int lavrec_sync_buffer(lavrec_t *info, struct mjpeg_sync *bsync){ video_capture_setup *settings = (video_capture_setup *)info->settings; if (info->software_encoding) { bsync->frame = (bsync->frame+1)%settings->softreq.frames; bsync->seq++; pthread_mutex_lock(&(settings->software_sync_mutex)); while (settings->software_sync_ready[bsync->frame] == 0) { lavrec_msg(LAVREC_MSG_DEBUG, info, "Software sync client: sleeping for new frames (waiting for frame %ld)", bsync->frame); pthread_cond_wait(&(settings->software_sync_wait[bsync->frame]), &(settings->software_sync_mutex)); } pthread_mutex_unlock(&(settings->software_sync_mutex)); if (settings->software_sync_ready[bsync->frame] < 0) { return 0; } memcpy(&(bsync->timestamp), &(settings->software_sync_timestamp[bsync->frame]), sizeof(struct timeval)); settings->software_sync_ready[bsync->frame] = 0; } else { if (ioctl(settings->video_fd, MJPIOC_SYNC, bsync) < 0) { return 0; } } lavrec_msg(LAVREC_MSG_DEBUG, info, "Syncing on frame %ld", bsync->frame); return 1;}/****************************************************** * lavrec_handle_audio() * handle audio and output stats * * return value: 1 on success, 0 on error ******************************************************/static int lavrec_handle_audio(lavrec_t *info, struct timeval *timestamp){ int x; int nerr = 0; video_capture_setup *settings = (video_capture_setup *)info->settings; video_capture_stats *stats = settings->stats; while (info->audio_size) { /* Only try to read a audio sample if video is ahead - else we might * get into difficulties when writing the last samples */ if (settings->output_status < 3 && stats->num_frames * settings->spvf < (stats->num_asamps + settings->audio_buffer_size / settings->audio_bps) * settings->spas) break; x = audio_read((unsigned char*)settings->AUDIO_buff, sizeof(settings->AUDIO_buff), 0, &(settings->audio_tmstmp), &(settings->astat)); if (x == 0) break; if (x < 0) { lavrec_msg(LAVREC_MSG_ERROR, info, "Error reading audio: %s", audio_strerror()); if (info->files) lavrec_close_files_on_error(info); nerr++; break; } if (!(settings->astat)) { stats->num_aerr++; stats->stats_changed = 1; } /* Adjust for difference at start */ if (settings->audio_offset >= x) { settings->audio_offset -= x; continue; } x -= settings->audio_offset; /* Got an audio sample, write it out */ if (audio_captured(info, settings->AUDIO_buff+settings->audio_offset, x/settings->audio_bps) != 1) { nerr++; break; /* Done or error occured */ } settings->audio_offset = 0; /* calculate time differences beetween audio and video * tdiff1 is the difference according to the number of frames/samples written * tdiff2 is the difference according to the timestamps * (only if audio timestamp is not zero) */ if(settings->audio_tmstmp.tv_sec) { stats->tdiff1 = stats->num_frames * settings->spvf - stats->num_asamps * settings->spas; stats->tdiff2 = (timestamp->tv_sec - settin
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?