liblavrec.c

来自「Motion JPEG编解码器源代码」· C语言 代码 · 共 1,916 行 · 第 1/5 页

C
1,916
字号
/* * liblavrec - a librarified Linux Audio Video Record-application * * Copyright (C) 2000 Rainer Johanni <Rainer@Johanni.de> * Extended by:     Gernot Ziegler  <gz@lysator.liu.se> *               &  Wolfgang Scherr <scherr@net4you.net> *               &  Ronald Bultje   <rbultje@ronald.bitfreak.net> *               &  many others *  * A library for recording MJPEG video from hardware MJPEG * video devices such as the Pinnacle/Miro DC10(+), Iomega * Buz, the Linux Media Labs LML33, the Matrox Marvel G200, * Matrox Marvel G400 and the Rainbow Runner G-series. * Can also be used for video-capture from BTTV-devices *  * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. *  * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. *  * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. */#include <config.h>#include <stdlib.h>#include <stdarg.h>#include <stdio.h>#include <fcntl.h>#include <unistd.h>#include <string.h>#include <errno.h>#include <sched.h>#include <signal.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/ioctl.h>#include <sys/mman.h>#include <sys/time.h>#include <sys/resource.h>#include <sys/wait.h>#include <sys/statfs.h>#include <mjpeg_types.h>#include <sys/vfs.h>#include <stdlib.h>/* Because of some really cool feature in video4linux1, also known as * 'not including sys/types.h and sys/time.h', we had to include it * ourselves. In all their intelligence, these people decided to fix * this in the next version (video4linux2) in such a cool way that it * breaks all compilations of old stuff... * The real problem is actually that linux/time.h doesn't use proper * macro checks before defining types like struct timeval. The proper * fix here is to either fuck the kernel header (which is what we do * by defining _LINUX_TIME_H, an innocent little hack) or by fixing it * upstream, which I'll consider doing later on. If you get compiler * errors here, check your linux/time.h && sys/time.h header setup. */#define _LINUX_TIME_H#include <linux/videodev.h>#ifdef HAVE_SYS_SOUNDCARD_H#include <sys/soundcard.h>#endif#include <videodev_mjpeg.h>#include <pthread.h>#include "mjpeg_types.h"#include "mjpeg_logging.h"#include "liblavrec.h"#include "lav_io.h"#include "audiolib.h"#include "jpegutils.h"/* On some systems MAP_FAILED seems to be missing */#ifndef MAP_FAILED#define MAP_FAILED ( (caddr_t) -1 )#endif#define MJPEG_MAX_BUF 256#define MIN_QUEUES_NEEDED 2 /* minimal number of queues needed to sync */#define NUM_AUDIO_TRIES 500 /* makes 10 seconds with 20 ms pause beetween tries */#define MAX_MBYTES_PER_FILE_64 ((0x3fffff) * 93/100)        /* 4Tb.  (Most filesystems have  */                                                            /* fundamental limitations around ~Tb) */#define MAX_MBYTES_PER_FILE_32 ((0x7fffffff >> 20) * 85/100)/* Is less than 2^31 and 2*10^9 */#if _FILE_OFFSET_BITS == 64#define MAX_MBYTES_PER_FILE MAX_MBYTES_PER_FILE_64#else#define MAX_MBYTES_PER_FILE MAX_MBYTES_PER_FILE_32                                  /* Maximum number of Mbytes per file.                                     We make a conservative guess since we                                     only count the number of bytes output                                     and don't know how big the control                                     information will be */#endif#define MIN_MBYTES_FREE 10        /* Minimum number of Mbytes that should                                     stay free on the file system, this is also                                     only a guess */#define MIN_MBYTES_FREE_OPEN 20   /* Minimum number of Mbytes that have to be                                     free in the filesystem when opening a new file */#define CHECK_INTERVAL 50         /* Interval for checking free space on file system */#define VALUE_NOT_FILLED -10000typedef struct {   int    interlaced;                         /* is the video interlaced (even/odd-first)? */   int    width;                              /* width of the captured frames */   int    height;                             /* height of the captured frames */   double spvf;                               /* seconds per video frame */   int    video_fd;                           /* file descriptor of open("/dev/video") */   int    has_audio;                          /* whether it has an audio ability */   struct mjpeg_requestbuffers breq;          /* buffer requests */   struct mjpeg_sync bsync;   struct video_mbuf softreq;                 /* Software capture (YUV) buffer requests */   uint8_t *MJPG_buff;                         /* the MJPEG buffer */   struct video_mmap mm;                      /* software (YUV) capture info */   unsigned char *YUV_buff;                   /* in case of software encoding: the YUV buffer */   lav_file_t *video_file;                    /* current lav_io.c file we're recording to */   lav_file_t *video_file_old;                /* previous lav_io.c file we're recording to (finish audio/close) */   int    num_frames_old;   uint8_t AUDIO_buff[AUDIO_BUFFER_SIZE];      /* the audio buffer */   struct timeval audio_t0;   int    astat;   long   audio_offset;   struct timeval audio_tmstmp;   int    mixer_set;                          /* whether the mixer settings were changed */   int    audio_bps;                          /* bytes per second for audio stream */   long   audio_buffer_size;                  /* audio stream buffer size */   double spas;                               /* seconds per audio sample */   double sync_lim;                           /* upper limit of 'out-of-sync' - if higher, quit */   video_capture_stats* stats;                /* the stats */   uint64_t   MBytes_fs_free;                 /* Free disk space when that was last checked */   uint64_t   bytes_output_cur;               /* Bytes output to the current output file */   uint64_t   bytes_last_checked;             /* Number of bytes that were output when the                                                 free space was last checked */   int    mixer_volume_saved;                 /* saved recording volume before setting mixer */   int    mixer_recsrc_saved;                 /* saved recording source before setting mixer */   int    mixer_inplev_saved;                 /* saved output volume before setting mixer */   /* the JPEG video encoding thread mess */   struct encoder_info_s * encoders;          /* for software encoding recording */   pthread_mutex_t encoding_mutex;            /* for software encoding recording */   int buffer_valid[MJPEG_MAX_BUF];           /* Non-zero if buffer has been filled */   int buffer_completed[MJPEG_MAX_BUF];       /* Non-zero if buffer has been compressed/written */   pthread_cond_t buffer_filled[MJPEG_MAX_BUF];   pthread_cond_t buffer_completion[MJPEG_MAX_BUF];   /* thread for correctly timestamping the V4L/YUV buffers */   pthread_t software_sync_thread;            /* the thread */   pthread_mutex_t software_sync_mutex;       /* the mutex */   sig_atomic_t please_stop_syncing;   unsigned long buffers_queued;		/* evil hack for BTTV-0.8 */   int software_sync_ready[MJPEG_MAX_BUF];    /* whether the frame has already been synced on */   pthread_cond_t software_sync_wait[MJPEG_MAX_BUF]; /* wait for frame to be synced on */   struct timeval software_sync_timestamp[MJPEG_MAX_BUF];   /* some mutex/cond stuff to make sure we have enough queues left */   pthread_mutex_t queue_mutex;   unsigned short queue_left;   short is_queued[MJPEG_MAX_BUF];   pthread_cond_t queue_wait;   int    output_status;   pthread_mutex_t state_mutex;   int    state;                              /* recording, paused or stoppped */   pthread_t capture_thread;} video_capture_setup;/* Identity record for software encoding worker thread... * Given N workers Worker i compresses frame i,i+n,i+2N and so on. * There may not be more workers than there are capture buffers - 1. */typedef struct encoder_info_s {   lavrec_t *info;   unsigned int encoder_id;   unsigned int num_encoders;   pthread_t thread;} encoder_info_t;/* Forward definitions */static intlavrec_queue_buffer (lavrec_t *info, unsigned long *num);static intlavrec_handle_audio (lavrec_t *info, struct timeval *timestamp);/****************************************************** * lavrec_msg() *   simplicity function which will give messages ******************************************************/static void lavrec_msg(int type, lavrec_t *info, const char format[], ...) GNUC_PRINTF(3,4);static void lavrec_msg(int type, lavrec_t *info, const char format[], ...){   char buf[1024];   va_list args;   va_start(args, format);   vsnprintf(buf, sizeof(buf)-1, format, args);   va_end(args);   if (!info) /* we can't let errors pass without giving notice */      mjpeg_error("%s", buf);   else if (info->msg_callback)      info->msg_callback(type, buf);   else if (type == LAVREC_MSG_ERROR)      mjpeg_error("%s", buf);}/****************************************************** * lavrec_change_state() *   changes the recording state ******************************************************/static intlavrec_change_state_if(lavrec_t *info, int new_state, int require_state){   int okay;     video_capture_setup *settings = (video_capture_setup *)info->settings;   pthread_mutex_lock(&settings->state_mutex);   if ((okay = settings->state == require_state) != 0)   {      settings->state = new_state;      if (info->state_changed)	 info->state_changed(new_state);   }   pthread_mutex_unlock(&settings->state_mutex);   return okay;}static voidlavrec_change_state(lavrec_t *info, int new_state){   video_capture_setup *settings = (video_capture_setup *)info->settings;   pthread_mutex_lock(&settings->state_mutex);   settings->state = new_state;   if (info->state_changed)      info->state_changed(new_state);   pthread_mutex_unlock(&settings->state_mutex);}/****************************************************** * set_mixer() *   set the sound mixer: *    flag = 1 : set for recording from the line input *    flag = 0 : restore previously saved values * * return value: 1 on success, 0 on error ******************************************************/static int lavrec_set_mixer(lavrec_t *info, int flag){   int fd, var;   unsigned int sound_mixer_read_input;   unsigned int sound_mixer_write_input;   unsigned int sound_mask_input;   video_capture_setup *settings = (video_capture_setup *)info->settings;   /* Avoid restoring anything when nothing was set */   if (flag==0 && settings->mixer_set==0) return 1;   /* Open the audio device */   fd = open(info->mixer_dev, O_RDONLY);   if (fd == -1)   {      lavrec_msg(LAVREC_MSG_WARNING, info,         "Unable to open sound mixer \'%s\', try setting the sound mixer with another tool!!!",         info->mixer_dev);      return 1; /* 0 means error, so although we failed return 1 */   }   switch(info->audio_src)   {      case 'm':         sound_mixer_read_input  = SOUND_MIXER_READ_MIC;         sound_mixer_write_input = SOUND_MIXER_WRITE_MIC;         sound_mask_input        = SOUND_MASK_MIC;         break;      case 'c':         sound_mixer_read_input  = SOUND_MIXER_READ_CD;         sound_mixer_write_input = SOUND_MIXER_WRITE_CD;         sound_mask_input        = SOUND_MASK_CD;         break;      case 'l':         sound_mixer_read_input  = SOUND_MIXER_READ_LINE;         sound_mixer_write_input = SOUND_MIXER_WRITE_LINE;         sound_mask_input        = SOUND_MASK_LINE;         break;      case '1':         sound_mixer_read_input  = SOUND_MIXER_READ_LINE1;         sound_mixer_write_input = SOUND_MIXER_WRITE_LINE1;         sound_mask_input        = SOUND_MASK_LINE1;         break;      case '2':         sound_mixer_read_input  = SOUND_MIXER_READ_LINE2;         sound_mixer_write_input = SOUND_MIXER_WRITE_LINE2;         sound_mask_input        = SOUND_MASK_LINE2;         break;      case '3':         sound_mixer_read_input  = SOUND_MIXER_READ_LINE3;         sound_mixer_write_input = SOUND_MIXER_WRITE_LINE3;         sound_mask_input        = SOUND_MASK_LINE3;         break;      default:         lavrec_msg(LAVREC_MSG_WARNING, info,            "Unknown sound source: \'%c\'", info->audio_src);         close(fd);         return 1; /* 0 means error, so although we failed return 1 */   }   if(flag==1)   {      int nerr = 0;      /* Save the values we are going to change */      if (settings->mixer_set == 0) {         if (ioctl(fd, SOUND_MIXER_READ_VOLUME, &(settings->mixer_volume_saved)) == -1) nerr++;         if (ioctl(fd, SOUND_MIXER_READ_RECSRC, &(settings->mixer_recsrc_saved)) == -1) nerr++;         if (ioctl(fd, sound_mixer_read_input , &(settings->mixer_inplev_saved)) == -1) nerr++;         settings->mixer_set = 1;         if (nerr)         {            lavrec_msg (LAVREC_MSG_WARNING, info,               "Unable to save sound mixer settings");            lavrec_msg (LAVREC_MSG_WARNING, info,               "Restore your favorite setting with another tool after capture");            settings->mixer_set = 0; /* prevent us from resetting nonsense settings */         }      }      /* Set the recording source, audio-level and (if wanted) mute */      nerr = 0;      var = sound_mask_input;      if (ioctl(fd, SOUND_MIXER_WRITE_RECSRC, &var) == -1) nerr++;      var = 256*info->audio_level + info->audio_level; /* left and right channel */      if (ioctl(fd, sound_mixer_write_input, &var) == -1) nerr++;      if(info->mute) {         var = 0;         if (ioctl(fd, SOUND_MIXER_WRITE_VOLUME, &var) == -1) nerr++;      }      if (nerr)      {         lavrec_msg (LAVREC_MSG_WARNING, info,            "Unable to set the sound mixer correctly");         lavrec_msg (LAVREC_MSG_WARNING, info,            "Audio capture might not be successfull (try another mixer tool!)");      }   }   else   {      int nerr = 0;      /* Restore previously saved settings */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?