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