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