📄 main.cc
字号:
/* Copyright (C) Bram Avontuur (bram@avontuur.org) */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <stdio.h>#include <unistd.h>#ifdef HAVE_STDLIB_H#include <stdlib.h>#endif /* HAVE_STDLIB_H */#include <errno.h>#include <ctype.h>#include <string.h>#include <sys/time.h>#include <ctype.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/ioctl.h>#include <fcntl.h>#include <iostream>/* Custom headerfiles */#include "vcr.h"#include <creators.h>using namespace Creators;using namespace std;#include <signal.h>#include <getopt.h>#include <avifile.h>#include <videoencoder.h>#include "capproc.h"#include "v4lxif.h"#include "global.h"#include "parseconfig.h"#include "channel.h"#include "frequencies.h"#include VCR_SOUNDCARD_Husing namespace std;/* External variables/functions *//* Function prototypes */void init_v4l();void vcr_debug(const char*);void usage();void parse_arguments(int, char*argv[]);void init_debug();void init_globals();void verify_globals();void end_program(int);short add_attribute(const char*);short set_attributes();int get_codec_index(int);char **split_string(const char *);short parse_config_file();short set_error(const char *);void show_error();void vcr_warning(const char *);void vcr_notice(const char *);void vcr_notice(string&);void vcr_notice(ostringstream&);int set_rectime(const char *);void clear_attributes();void list_attributes(int fourcc, int indent_level = 0);void list_codecs();/* Global variables *///enum cmdopts { OPT_struct codec_attr { char *name; char *val;} *attributes;static short mp3_bitrates[2][2][6] = { { //22 Khz { //mono 32, 48, 56, 64, 96, 112 }, { //stereo 64, 80, 96, 112, 128, 160 } }, { //44 Khz { //mono 56, 64, 96, 112, 128, 160 }, { //stereo 112, 128, 160, 192, 256, 320 } }};static struct STRTAB norms[] = { { 0, "PAL" }, { 1, "NTSC" }, { 2, "SECAM" }, { 3, "AUTO" }, { -1, NULL }};CaptureProcess *cap = NULL;v4lxif *v4l = NULL;FILE *vcr_debug_file = NULL;short want_debug, verbose;char *prog_name = NULL, *codec_name = NULL, *rectime_str = NULL, *attributes_str = NULL, *input_source, *preset, *filename, *config_file, *norm, *audio_mode, *freqtab, *error = NULL, *debugfile = NULL, *window_str = NULL, *codec_preset = NULL, *init_sound = NULL, *sound_device = NULL, *grabdevice;int rectime, codecID, keyframes, quality, normID, audio_freq, audio_size, audio_bitrate = -1, vertical_flip = -1, resolution = 0, splitsize = -1, attr_count = 0, resolution_width = 0, resolution_height = 0;avm::vector<AttributeInfo> encoder_info;float fps;window_t window;enum Sound_Freqs soundfreq;enum Sample_Sizes samplesize;enum Sound_Chans soundchan;enum Resolutions videores;void stop_record_handler(int arg){ cerr << "Caught CTRL+C: Stopping capture.\n" << endl; cap->stopRecord(); signal(SIGINT, SIG_IGN); //otherwise this function will be called again}voidend_program(int exit_status){ if (cap) delete cap; if (v4l) { v4l->setCapture(0); v4l->setAudioMute(1); delete v4l; } exit(exit_status);}/* Kinda quick & dirty ... */voidlist_audiobitrates(){ cerr << "Available mp3 bitrates: " << endl << endl; int f_index = 0, m_index = 0, b_index = 0; for (f_index = 0; f_index < 2; f_index++) { const char *khz = (f_index ? "44 Khz" : "22 Khz"); for (m_index = 0; m_index < 2; m_index++) { if (!m_index) cerr << khz << " mono : "; else cerr << khz << " stereo: "; for (b_index = 0; b_index < 6; b_index++) cerr << mp3_bitrates[f_index][m_index][b_index] << " "; cerr << endl; } }}voidlist_norms(){ cerr << "Available norms: "; int i = 0; while (norms[i].nr > -1) { cerr << norms[i++].str << " "; } cerr << endl;}voidlist_resolutions(){ int i = 0; cerr << "Possible video sizes:" << endl; while (restable[i].res != WNONE) { cerr << restable[i].width << "x" << restable[i].height << " (config value: " << restable[i].width << ")" << endl; i++; }}voidlist_presets(){ cerr << "Available presets are:" << endl << endl; char **list; for (list = cfg_list_sections(); *list != NULL; list++) { if ( !strcmp(*list, "defaults") || !strcmp(*list, "global") || !strcmp(*list, "launch") || cfg_get_str(*list, "codec") //codec => codec preset ) continue; cerr << "\"" << *list << "\" "; } cerr << endl;}voidlist_codec_presets(){ cerr << "Available codec presets are:" << endl << endl; char **list; for (list = cfg_list_sections(); *list != NULL; list++) { if ( !strcmp(*list, "defaults") || !strcmp(*list, "global") || !strcmp(*list, "launch") || !cfg_get_str(*list, "codec") //codec => codec preset ) continue; cerr << "\"" << *list << "\" "; } cerr << endl;}voidlist_sources(){ int i, nrsources; if (!v4l) { init_v4l(); if (!v4l) { cerr << "Error opening video4linux device; cannot show input sources." << endl; end_program(1); } } cerr << "Available input sources: "; nrsources = v4l->capCapChannelC(); for (i = 0; i < nrsources; i++) { cerr << v4l->capChannelName(i); cerr << (i != nrsources - 1 ? ", " : "."); } cerr << endl;}voidlist_codecs(){ avm::vector<const CodecInfo*> codecList; avm::vector<const CodecInfo*>::const_iterator it; cerr << "Available codecs: " << endl << endl; CodecInfo::Get(codecList); for ( it = codecList.begin(); it != codecList.end(); it++) { if ((*it)->kind == CodecInfo::DShow_Dec) continue; //probably not a usable codec.. if (!((*it)->direction & CodecInfo::Encode)) continue; //only interested in codecs that can encode const char *cname = (*it)->GetName(); cerr << "\"" << cname << "\"" << endl; list_attributes((*it)->fourcc, 1); } cerr << endl;}voidlist_attributes(int fourcc, int indent_level){ int defval; const char *def_str; avm::vector<const CodecInfo*> codecList; int idx; string indent(indent_level, ' '); idx = get_codec_index(fourcc); if (idx < 0) return; CodecInfo::Get(codecList); avm::vector<AttributeInfo> encinfo = codecList[idx]->encoder_info; if (0 == encinfo.size()) { cerr << indent << "There are no attributes for this codec." << endl; return; } cerr << indent << "These attributes are supported for this codec:" << endl; avm::vector<AttributeInfo>::const_iterator it; for(it=encinfo.begin(); it!=encinfo.end(); it++) { ostringstream att; att << "\"" << it->GetName() << "\""; cerr << indent << "Attribute "; cerr.width(22); cerr << right << att.str() << ": "; switch(it->kind) { case AttributeInfo::Integer: { int status = avm::CodecGetAttr(*(codecList[idx]), it->GetName(), &defval); cerr << indent << "Type: integer (default value: "; if (status) cerr << "none"; else cerr << defval; cerr << ")" << endl; break; } case AttributeInfo::Select: { avm::CodecGetAttr(*(codecList[idx]), it->GetName(), &defval); cerr << indent << "Type: select (default value: " << (defval < (int)it->options.size() ? it->options[defval] : "unknown") << ")" << endl; cerr << indent << "=>Possible values: "; avm::vector<avm::string>::const_iterator sit; for (sit=(it->options).begin(); sit!=(it->options).end(); sit++) { cerr << sit->c_str() << " "; } cerr << endl; break; } case AttributeInfo::String: GetCodecAttr(*(codecList[idx]), it->GetName(), (const char **)&def_str); cerr << indent << "Type: string (default value: " << def_str << ")"<< endl; break; case AttributeInfo::Float: cerr << "Type: float" << endl; break; default: break; } }}voidlist_freqtabs(){ int i = 0; cerr << "Supported frequency tables:" << endl << endl; while (chanlist_names[i].nr != -1) { cerr << chanlist_names[i].str << endl; i++; }}voidinit_v4l(){ if (grabdevice) v4l = new v4l1if(0, grabdevice); else v4l = new v4l1if(0, V4L_DEVICE);}voidvcr_debug(const char *txt){ if (vcr_debug_file) { fwrite(txt, sizeof(char), strlen(txt), vcr_debug_file); fflush(vcr_debug_file); }}voidusage(){ cerr << "vcr " << VERSION << ": non-interactive video recorder." << endl << "Usage: " << prog_name << " [options] filename" << endl << endl << "Options with an asterisk (*) support a parameter 'list', to list the " << "options you can choose from." << endl << endl << "Options:" << endl << " -a, --codec-attribute a=b set codec attribute" << endl << " *-b, --audiobitrate RATE set mp3 compression bitrate" << endl << " *-c, --codec CODEC set encoding codec" << endl << " -d, --debug [DEBUG] write debugging information to DEBUG" << endl << " -F, --framerate RATE set framerate (default=25)" << endl << " -f, --config-file FILE read FILE for configuration" << endl << " -g, --grabdevice DEVICE use DEVICE as capture device" << endl << " -h, --help display help" << endl << " -k, --keyframes NUM set group of picture count" << endl << " -m, --audiomode MODE set audio-capture to mono or stereo" << endl << " *-P, --codec-preset PRESET Use codec preset" << endl << " *-p, --preset STATION tune v4l into STATION" << endl << " -q, --quality QUAL set quality of encoding percentage" << endl << " *-r, --resolution RES set frame size ('-r list' for a list)" << endl << " -S, --splitsize SIZE split file in chunks of SIZE Megabytes" << endl << " *-s, --source v4l input source (default=Television)" << endl << " -t, --rectime TIME set recording time (see 'man vcr')" << endl << " -v, --verbose verbose output during capturing" << endl << " -w, --window X,Y,W,H crop frame size:(X,Y)=top left, (W,H)=size" << endl << endl;}voidinit_globals(){ input_source = NULL; want_debug = 0; rectime = 0; codec_name = NULL; rectime_str = NULL; codecID = -1; normID = -1; keyframes = 0; quality = 0; audio_freq = 0; audio_size = 0; audio_bitrate = -1; // 0 => no mp3 compression resolution = 0; fps = -1; verbose = 0; window.x = -1; // to force resize to full resolution when no window is specified preset = NULL; filename = NULL; attributes = NULL; attr_count = 0; config_file = NULL; error = NULL; norm = NULL; audio_mode = NULL; cap = NULL; freqtab = NULL; grabdevice = NULL; debugfile = NULL; window_str = NULL; codec_preset = NULL; init_sound = NULL; attributes_str = NULL;}voidinit_debug(){ if (!debugfile) { char *homedir = get_homedir(NULL); char *dbfile = new char[strlen(homedir) + 255]; strcpy(dbfile, homedir); free(homedir); strcat(dbfile, "/.vcrdebug"); vcr_debug_file = fopen(dbfile, "a"); delete[] dbfile; } else vcr_debug_file = fopen(debugfile, "a"); if (!vcr_debug_file) { cerr << "Could not open debug file." << endl; end_program(1); } vcr_debug("VCR Debugging started!\n");}intis_valid_audiobitrate(int kbps, enum Sound_Chans mode, enum Sound_Freqs freq){ int i = 0; short foundit = 0; short m_index = (mode == Stereo ? 1 : 0); short f_index = (freq == F44 ? 1 : 0); for (i = 0; i < 6; i++) { if (kbps == (int)mp3_bitrates[f_index][m_index][i]) { foundit = true; break; } } if (foundit) return (kbps * 1000) / 8; return -1;}intis_valid_norm(const char *n){ if (!n) return -1; int i = 0; while (norms[i].nr > -1) { if (!strcasecmp(norms[i].str, n)) { return norms[i].nr; } i++; } return -1;}/* returns -1 if codec does not exist. * Otherwise, the codec's unique ID */intis_valid_codec(const char *cname){ if (!cname) return -1; int found_codec = -1; avm::vector<const CodecInfo*> codecList; CodecInfo::Get(codecList); avm::vector<const CodecInfo*>::iterator it; for (it = codecList.begin(); it != codecList.end(); it++) { if ( (*it)->kind == CodecInfo::DShow_Dec) continue; if (!strcasecmp(cname, (*it)->GetName())) { found_codec = (*it)->fourcc; encoder_info = (*it)->encoder_info; break; } } return found_codec;}shortset_resolution(int width){ int i = 0; while (restable[i].width != width && restable[i].res != WNONE) i++; if (restable[i].res == WNONE) return 0; videores = restable[i].res; resolution_width = restable[i].width; resolution_height = restable[i].height; return 1;}/* sndstring format: [/sound/device:][mixer_device_name:]volume * initialize_sound returns < 0 in case of failure, and sets global * error variable. */shortinitialize_sound(const char *sndstring){ //no ":"'s: just the volume (of /dev/mixer:line) //1 ":" device (starts with '/'), else mixerdevname //2 ":" device:mixerdevname:volume char dev[strlen(sndstring)+20], mixdev[strlen(sndstring)+20]; int temp; unsigned int volume; temp = sscanf(sndstring, "%[^:]:%[^:]:%u", dev, mixdev, &volume); if (temp < 1 || temp > 3) return 0; if (temp == 1) //only sound is specified. { volume = (unsigned int)atoi(dev); strcpy(dev, "/dev/mixer"); strcpy(mixdev, "line"); } else if (temp == 2) //sound device OR mixer name, and volume { volume = (unsigned int)atoi(mixdev); if (strlen(dev) && dev[0] == '/') //sound dev { strcpy(mixdev, "line"); } else { strcpy(mixdev, dev); strcpy(dev, "/dev/mixer"); } } if (!volume) { return set_error("Invalid recording device volume given. A sane value "\ "would probably be in the range of 70..100."); } if (!strlen(dev) || !strlen(mixdev)) return set_error("No (or empty) sound- or mixer device given."); if (volume < 50) vcr_warning("Recording device volume is very low!"); ostringstream s; s << "Using mixer " << dev << ", mixer device " << mixdev << "with volume " << volume << " to record audio from."; vcr_notice(s); int i, mixer = open(dev, O_RDWR); unsigned int available_devs, available_recdevs; short found_label = 0; if (mixer < 0) return set_error("Could not open sound device."); ioctl(mixer, MIXER_READ(SOUND_MIXER_DEVMASK), &available_devs); ioctl(mixer, MIXER_READ(SOUND_MIXER_RECMASK), &available_recdevs); static const char *mixer_labels[] = SOUND_DEVICE_LABELS; char *cropped_label = NULL; //if label's found, mixerdevice-ID == i for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -