github.com/aamcrae/webcam@v0.0.0-20210915060337-934acc13bdc3/examples/imageserver/server.go (about) 1 // Copyright 2019 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Program that serves images taken from a webcam. 16 package main 17 18 import ( 19 "flag" 20 "fmt" 21 "image/gif" 22 "image/jpeg" 23 "image/png" 24 "log" 25 "net/http" 26 "strconv" 27 "strings" 28 "time" 29 30 "github.com/aamcrae/webcam" 31 "github.com/aamcrae/webcam/frame" 32 "github.com/aamcrae/webcam/snapshot" 33 ) 34 35 var port = flag.Int("port", 8080, "Web server port number") 36 var path = flag.String("path", "image", "Image base filename") 37 var device = flag.String("input", "/dev/video0", "Input video device") 38 var resolution = flag.String("resolution", "800x600", "Camera resolution") 39 var format = flag.String("format", "YUYV", "Pixel format of camera") 40 var controls = flag.String("controls", "", 41 "Control parameters for camera (use --controls=list to list controls)") 42 var startDelay = flag.Int("delay", 2, "Delay at start (seconds)") 43 var verbose = flag.Bool("v", false, "Log more information") 44 45 var cnames map[string]webcam.ControlID = map[string]webcam.ControlID{ 46 "focus": 0x009a090a, 47 "power_line_frequency": 0x00980918, 48 "brightness": 0x00980900, 49 "contrast": 0x00980901, 50 "autoiso": 0x009a0918, 51 "autoexp": 0x009a0901, 52 "saturation": 0x00980902, 53 "sharpness": 0x0098091b, 54 "rotate": 0x00980922, 55 "stabilization": 0x009a0916, 56 } 57 58 func main() { 59 flag.Parse() 60 s := strings.Split(*resolution, "x") 61 if len(s) != 2 { 62 log.Fatalf("%s: Illegal resolution", *resolution) 63 } 64 x, err := strconv.Atoi(s[0]) 65 if err != nil { 66 log.Fatalf("%s: illegal width: %v", s[0], err) 67 } 68 y, err := strconv.Atoi(s[1]) 69 if err != nil { 70 log.Fatalf("%s: illegal height: %v", s[1], err) 71 } 72 if *controls == "list" { 73 fmt.Printf("Control list (not all cameras may support all options):\n") 74 for c, _ := range cnames { 75 fmt.Printf(" %s\n", c) 76 } 77 return 78 } 79 if *startDelay != 0 { 80 time.Sleep(time.Duration(*startDelay) * time.Second) 81 } 82 cm := snapshot.NewSnapper() 83 if err := cm.Open(*device, frame.FourCC(*format), x, y); err != nil { 84 log.Fatalf("%s: %v", *device, err) 85 } 86 if *startDelay != 0 { 87 time.Sleep(time.Duration(*startDelay) * time.Second) 88 } 89 defer cm.Close() 90 // Set camera controls. 91 if len(*controls) != 0 { 92 for _, control := range strings.Split(*controls, ",") { 93 s := strings.Split(control, "=") 94 if len(s) != 2 { 95 log.Fatalf("Bad control option: %s", control) 96 } 97 id, ok := cnames[s[0]] 98 if !ok { 99 log.Fatalf("%s: Unknown control", s[0]) 100 } 101 val, err := strconv.Atoi(s[1]) 102 if err != nil { 103 log.Fatalf("Bad control value: %s (%v)", control, err) 104 } 105 if *verbose { 106 fmt.Printf("Setting control '%s' to %d\n", s[0], val) 107 } 108 if err = cm.SetControl(id, int32(val)); err != nil { 109 log.Fatalf("SetControl error: %s (%v)", control, err) 110 } 111 } 112 } 113 encodeJpeg := func(w http.ResponseWriter, f frame.Frame) error { 114 w.Header().Set("Content-Type", "image/jpeg") 115 return jpeg.Encode(w, f, nil) 116 } 117 encodePNG := func(w http.ResponseWriter, f frame.Frame) error { 118 w.Header().Set("Content-Type", "image/png") 119 return png.Encode(w, f) 120 } 121 encodeGIF := func(w http.ResponseWriter, f frame.Frame) error { 122 w.Header().Set("Content-Type", "image/gif") 123 return gif.Encode(w, f, nil) 124 } 125 http.Handle(fmt.Sprintf("/%s.jpg", *path), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 126 publishImage(cm, w, r, encodeJpeg) 127 })) 128 http.Handle(fmt.Sprintf("/%s.jpeg", *path), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 129 publishImage(cm, w, r, encodeJpeg) 130 })) 131 http.Handle(fmt.Sprintf("/%s.png", *path), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 132 publishImage(cm, w, r, encodePNG) 133 })) 134 http.Handle(fmt.Sprintf("/%s.gif", *path), http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 135 publishImage(cm, w, r, encodeGIF) 136 })) 137 url := fmt.Sprintf(":%d", *port) 138 if *verbose { 139 log.Printf("Starting server on %s", url) 140 } 141 server := &http.Server{Addr: url} 142 log.Fatal(server.ListenAndServe()) 143 } 144 145 func publishImage(cm *snapshot.Snapper, w http.ResponseWriter, r *http.Request, encode func(http.ResponseWriter, frame.Frame) error) { 146 if *verbose { 147 log.Printf("URL request: %v", r.URL) 148 } 149 f, err := cm.Snap() 150 if err != nil { 151 log.Printf("Getframe: %v", err) 152 w.WriteHeader(http.StatusInternalServerError) 153 return 154 } 155 defer f.Release() 156 if err := encode(w, f); err != nil { 157 log.Printf("Error writing image: %v\n", err) 158 w.WriteHeader(http.StatusInternalServerError) 159 } else if *verbose { 160 log.Printf("Wrote image successfully\n") 161 } 162 }