/* * * capture.c - part of Danovitsch Webcam * * Copyright (C) 2001 by Daan Vreeken * * Published under the terms of the GNU Public License 2.0 * (or any later version) * */ #include #include #include #include #include #include #include #include "tvtypes.h" #include "webcam.h" #define PAL_DIM_X 768 #define PAL_DIM_Y 576 #define MAX_MMAP_SIZE (ImageWidth*ImageHeight*4) int Capture_Device = -1; int Width = PAL_DIM_X; int Height = PAL_DIM_Y; unsigned char *Frame; unsigned char *FrameBuffer; struct timeval FrameTime; int NewFrame=0; int Capture_Fifo[2]; enum Capture_SettingID { NoID=0, ID_Brightness, ID_Hue, ID_CSaturation, ID_Contrast, ID_Input, ID_InputF, ID_Format, ID_Audio, ID_Channel, ID_ChannelType }; enum Capture_SettingType { NoType=0, Type_Number, Type_Text }; enum Capture_SettingDevice { NoDev=0, Dev_Bktr, Dev_Tuner }; struct Capture_SettingsArr { const enum Capture_SettingID ID; const char *Name; const enum Capture_SettingType Type; const enum Capture_SettingDevice Device; const int MinVal; const int MaxVal; int NumValue; char *OrgValue; char *TxtValue; }; struct Capture_SettingsArr Capture_Settings[] = { {ID_Brightness,"Brightness",Type_Number,Dev_Bktr,0,255,142,NULL,NULL}, {ID_Hue,"Hue",Type_Number,Dev_Bktr,0,256,255,NULL,NULL}, {ID_CSaturation,"Saturation",Type_Number,Dev_Bktr,0,255,128,NULL}, {ID_Contrast,"Contrast",Type_Number,Dev_Bktr,0,255,128,NULL,NULL}, {ID_InputF,"InputF",Type_Text,Dev_Bktr,0,0,0,"Cam1",NULL}, // {ID_InputF,"InputF",Type_Text,Dev_Bktr,0,0,0,"ATV",NULL}, {ID_Input,"Input",Type_Text,Dev_Bktr,0,0,0,"EXT-1",NULL}, {ID_Format,"Format",Type_Text,Dev_Bktr,0,0,0,"PAL-BDGHI",NULL}, {ID_Audio,"Audio",Type_Text,Dev_Tuner,0,0,0,"MUTE",NULL}, // {ID_Channel,"TunerChannel",Type_Number,Dev_Tuner,0,400,29,NULL,NULL}, // {ID_ChannelType,"ChannelType",Type_Text,Dev_Tuner,0,0,0,"WEUROPE",NULL}, {NoID,NULL,NoType,NoDev,0,0,0,NULL,NULL}}; struct Capture_TextTable { const enum Capture_SettingID ID; const char *Text; int Value; }; struct Capture_TextTable Capture_SettingText[] = { //Video inputs {ID_Input,"EXT-1",METEOR_INPUT_DEV0}, {ID_Input,"TUNER",METEOR_INPUT_DEV1}, {ID_Input,"SVHS-composite",METEOR_INPUT_DEV2}, {ID_Input,"SVHS",METEOR_INPUT_DEV_SVIDEO}, {ID_Input,"EXT-2",METEOR_INPUT_DEV3}, //Friendly-named video inputs ;-) {ID_InputF,"Cam1",METEOR_INPUT_DEV0}, {ID_InputF,"Cam2",METEOR_INPUT_DEV_SVIDEO}, {ID_InputF,"Tuner",METEOR_INPUT_DEV1}, {ID_InputF,"ATV",METEOR_INPUT_DEV2}, //Video formats {ID_Format,"AUTO",BT848_IFORM_F_AUTO}, {ID_Format,"NTSC-M",BT848_IFORM_F_NTSCM}, {ID_Format,"NTSC-J",BT848_IFORM_F_NTSCJ}, {ID_Format,"PAL-BDGHI",BT848_IFORM_F_PALBDGHI}, {ID_Format,"PAL-M",BT848_IFORM_F_PALM}, {ID_Format,"PAL-N",BT848_IFORM_F_PALN}, {ID_Format,"SECAM",BT848_IFORM_F_SECAM}, {ID_Format,"RSVD",BT848_IFORM_F_RSVD}, //Audio sources {ID_Audio,"TUNER",AUDIO_TUNER}, {ID_Audio,"EXTERN",AUDIO_EXTERN}, {ID_Audio,"INTERN",AUDIO_INTERN}, {ID_Audio,"MUTE",AUDIO_MUTE}, {ID_Audio,"UNMUTE",AUDIO_UNMUTE}, //Tuner channel types {ID_ChannelType,"NABCST",CHNLSET_NABCST}, {ID_ChannelType,"CABLEIRC",CHNLSET_CABLEIRC}, {ID_ChannelType,"CABLEHRC",CHNLSET_CABLEHRC}, {ID_ChannelType,"WEUROPE",CHNLSET_WEUROPE}, {ID_ChannelType,"JPNBCST",CHNLSET_JPNBCST}, {ID_ChannelType,"JPNCABLE",CHNLSET_JPNCABLE}, {ID_ChannelType,"XUSSR",CHNLSET_XUSSR}, {ID_ChannelType,"AUSTRALIA",CHNLSET_AUSTRALIA}, {ID_ChannelType,"FRANCE",CHNLSET_FRANCE}, {NoID,NULL,0}}; int Capture_LookupText(struct Capture_SettingsArr *Set, char *Text) { struct Capture_TextTable *Entry = &Capture_SettingText[0]; while ((Entry->ID!=NoID) && ((Entry->ID!=Set->ID) || (strcasecmp(Entry->Text,Text)))) Entry++; if (Entry->ID==NoID) return -1; return Entry->Value; } char *Capture_GetTextValue(char *Name) { struct Capture_SettingsArr *Set = &Capture_Settings[0]; while ((Set->ID!=NoID) && (strcasecmp(Set->Name,Name))) Set++; if (Set->ID==NoID) return NULL; return Set->TxtValue; } int Capture_Set(struct Capture_SettingsArr *SetPtr, char *Name, int Value, char *Txt) { TV_INT32 Int; int Int2; unsigned long Request; int Result = -1; struct Capture_SettingsArr *Set = SetPtr; int Device; //If no direct pointer was gives, try figuring it out by the name... if (Set==NULL) { Set=&Capture_Settings[0]; while ((Set->ID!=NoID) && (strcmp(Set->Name,Name))) Set++; if (Set->ID==NoID) { ExitFatal("Wrong Capture_Set() name!!"); } } switch (Set->Type) { case Type_Number: if ((ValueMinVal) || (Value>Set->MaxVal)) { Error("Wrong value!"); return 0; } Set->NumValue=Value; Int=Value; switch (Set->ID) { case ID_Brightness: Request=METEORSBRIG; break; case ID_Hue: Request=METEORSHUE; break; case ID_CSaturation: Request=METEORSCSAT; break; case ID_Contrast: Request=METEORSCONT; break; case ID_Channel: Request=TVTUNER_SETCHNL; break; } switch (Set->Device) { case Dev_Bktr: Device=Capture_Device; break; case Dev_Tuner: Device=open("/devs/tuner0",O_RDONLY); if (Device==-1) { Error("Could not open tuner!"); return 0; } break; } if (Result=ioctl(Device,Request,&Int)==-1) Error("ioctl failed! (req:%ld val:%ld)",Request,Int); if (Set->Device==Dev_Tuner) close(Device); break; case Type_Text: Int=Capture_LookupText(Set,Txt); if (Int==-1) { Error("Wrong text! (id:%s txt:%s)",Set->Name,Txt); return 0; } if (Set->TxtValue!=NULL) free(Set->TxtValue); Set->TxtValue=(char *)malloc(strlen(Txt)+1); if (Set->TxtValue==NULL) { Error("Could not allocate memory for setting! (skipping this one)"); return 0; } memcpy(Set->TxtValue,Txt,strlen(Txt)+1); switch (Set->ID) { case ID_Input: case ID_InputF: Request=METEORSINPUT; break; case ID_Format: Request=BT848SFMT; break; case ID_Audio: Request=BT848_SAUDIO; break; case ID_ChannelType: Request=TVTUNER_SETTYPE; break; default: Error("!!?!?!?!??!!? %d",Int); } switch (Set->Device) { case Dev_Bktr: Device=Capture_Device; break; case Dev_Tuner: Device=open("/devs/tuner0",O_RDONLY); if (Device==-1) { Error("Could not open tuner!"); } break; } if (Result=ioctl(Device,Request,&Int)==-1) Error("ioctl failed! (txt:%s req:%ld val:%ld %ld)",Txt,Request,Int,AUDIO_TUNER); if (Set->Device==Dev_Tuner) close(Device); break; default: Error("Capture_Set: Don't know what to do?!"); } if (Result==-1) return 0; else return 1; } void Capture_SetFormat(void) { TV_INT32 Format; struct meteor_geomet Geo; //PAL Format=BT848_IFORM_F_PALBDGHI; if (ioctl(Capture_Device,BT848SFMT,&Format)==-1) Error("ioctl failed!"); //Geometry Geo.columns=ImageWidth; Geo.rows=ImageHeight; Geo.frames=1; Geo.oformat=METEOR_GEO_RGB24 | METEOR_GEO_ODD_ONLY; //Geo.oformat=METEOR_GEO_RGB24; if (ioctl(Capture_Device,METEORSETGEO,&Geo)==-1) Error("ioctl failed!"); } void Capture_SetSource(void) { int Source; TV_INT32 Bright; //external video input Source=METEOR_INPUT_DEV0; if (ioctl(Capture_Device,METEORSINPUT,&Source)==-1) Error("ioctl failed!"); /* audio: Source=AUDIO_INTERN; if (ioctl(Capture_Device,BT848_SAUDIO,&Source)==-1) Error("ioctl failed!"); */ //brightness Bright=128+13; if (ioctl(Capture_Device,METEORSBRIG,&Bright)==-1) Error("ioctl failed!"); } static void FrameDone_Handler(int Signal) { unsigned char Nop = 0x00; write(Capture_Fifo[0],&Nop,1); } void Capture_Setup(void) { int Signal = SIGUSR1; FrameBuffer=(unsigned char *)malloc(MAX_MMAP_SIZE); if (FrameBuffer==NULL) ExitFatal("Could not allocate FrameBuffer!"); Frame=(unsigned char *)mmap((caddr_t)0,MAX_MMAP_SIZE,PROT_READ,MAP_SHARED,Capture_Device,(off_t)0); if (Frame==(unsigned char *)-1) ExitFatal("mmap failed!"); signal(SIGUSR1,FrameDone_Handler); if (ioctl(Capture_Device,METEORSSIGNAL,&Signal)==-1) ExitFatal("iotrcl failed!"); } void Capture_Single() { TV_INT32 Capture; Capture=METEOR_CAP_SINGLE; //Capture=METEOR_CAP_CONTINOUS; if (ioctl(Capture_Device,METEORCAPTUR,&Capture)==-1) Error("could not start single capture!"); gettimeofday(&FrameTime,NULL); NewFrame=1; } void Capture_Shutdown() { if (Frame!=NULL) munmap(Frame,MAX_MMAP_SIZE); if (Capture_Device!=-1) close(Capture_Device); Output("Shutdown capture device"); }