code: func (s *Service) Generate(videoRef blob.Ref, w io.Writer, src blob.Fetcher) error {
  
  	if s.gate != nil {
  		s.gate.Start()
  		defer s.gate.Done()
  	}
  
  	ln, err := netutil.ListenOnLocalRandomPort()
  	if err != nil {
  		return err
  	}
  	defer ln.Close()
  
  	videoURI := &url.URL{
  		Scheme: "http",
  		Host:   ln.Addr().String(),
  		Path:   videoRef.String(),
  	}
  
  	cmdErrc := make(chan error, 1)
  	cmd := buildCmd(s.thumbnailer, videoURI, w)
  	cmdErrOut, err := cmd.StderrPipe()
  	if err != nil {
  		return err
  	}
  	if err := cmd.Start(); err != nil {
  		return err
  	}
  	defer cmd.Process.Kill()
  	go func() {
  		out, err := ioutil.ReadAll(cmdErrOut)
  		if err != nil {
  			cmdErrc <- err
  			return
  		}
  		cmd.Wait()
  		if cmd.ProcessState.Success() {
  			cmdErrc <- nil
  			return
  		}
  		cmdErrc <- fmt.Errorf("thumbnail subprocess failed:\n%s", out)
  	}()
  
  	servErrc := make(chan error, 1)
  	go func() {
  		servErrc <- http.Serve(ln, createVideothumbnailHandler(videoRef, src))
  	}()
  
  	select {
  	case err := <-cmdErrc:
  		return err
  	case err := <-servErrc:
  		return err
  	case <-s.timer():
  		return errTimeout
  	}
  }
docs: // Generate reads the video given by videoRef from src and writes its thumbnail image to w.