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 + -
显示快捷键?