/*
 *  Copyright 1994-2022 Olivier Girondel
 *
 *  This file is part of lebiniou.
 *
 *  lebiniou 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.
 *
 *  lebiniou 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 lebiniou. If not, see <http://www.gnu.org/licenses/>.
 */

#include "context.h"
#if HAVE_LINUX_VIDEODEV2_H
#include <linux/videodev2.h>
#endif
#if HAVE_SYS_VIDEOIO_H
#include <sys/videoio.h>
#endif
#include "pthread_utils.h"


uint32_t options = BO_NONE;
uint32_t version = 0;

#define DEFAULT_VIDEO_DEVICE "/dev/video2"

static int fdwr = 0;


static void
print_format(const struct v4l2_format* vid_format)
{
#ifdef DEBUG
  printf("	vid_format->type                : %d\n", vid_format->type);
  printf("	vid_format->fmt.pix.width       : %d\n", vid_format->fmt.pix.width);
  printf("	vid_format->fmt.pix.height      : %d\n", vid_format->fmt.pix.height);
  printf("	vid_format->fmt.pix.pixelformat : %d\n", vid_format->fmt.pix.pixelformat);
  printf("	vid_format->fmt.pix.sizeimage   : %d\n", vid_format->fmt.pix.sizeimage);
  printf("	vid_format->fmt.pix.field       : %d\n", vid_format->fmt.pix.field);
  printf("	vid_format->fmt.pix.bytesperline: %d\n", vid_format->fmt.pix.bytesperline);
  printf("	vid_format->fmt.pix.colorspace  : %d\n\n", vid_format->fmt.pix.colorspace);
#endif
}


int8_t
create(Context_t *ctx)
{
  int ret_code;
  const char *device = NULL;
  struct v4l2_capability vid_caps;
  struct v4l2_format vid_format;

  if (NULL == (device = getenv("LEBINIOU_V4L2LOOPBACK"))) {
    device = DEFAULT_VIDEO_DEVICE;
  }
  fdwr = open(device, O_WRONLY);
  if (fdwr < 0) {
    return 0;
  }

  if ((ret_code = ioctl(fdwr, VIDIOC_QUERYCAP, &vid_caps)) == -1) {
    xperror("ioctl(VIDIOC_QUERYCAP)");
  }
  memset(&vid_format, 0, sizeof(vid_format));

  vid_format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
  vid_format.fmt.pix.width = WIDTH;
  vid_format.fmt.pix.height = HEIGHT;
  vid_format.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
  vid_format.fmt.pix.field = V4L2_FIELD_NONE;
  vid_format.fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;

  if ((ret_code = ioctl(fdwr, VIDIOC_S_FMT, &vid_format)) == -1) {
    xperror("ioctl(VIDIOC_S_FMT)");
  }
  print_format(&vid_format);

  return 1;
}


void
destroy(Context_t *ctx)
{
  close(fdwr);
}


void
run(Context_t *ctx)
{
  if (!xpthread_mutex_lock(&ctx->frame_mutex)) {
    int ret = write(fdwr, ctx->frame, RGB_BUFFSIZE * sizeof(Pixel_t));
    if (ret == -1) {
      fprintf(stderr, "%s:%s: write failed\n", __FILE__, __func__);
    }
    xpthread_mutex_unlock(&ctx->frame_mutex);
  }
}
