Example #1
0
static vpx_image_t *
gst_vp8_enc_buffer_to_image (GstVP8Enc * enc, GstBuffer * buffer)
{
  vpx_image_t *image = g_slice_new0 (vpx_image_t);
  guint8 *data = GST_BUFFER_DATA (buffer);
  GstVideoState *state = &GST_BASE_VIDEO_CODEC (enc)->state;

  image->fmt = VPX_IMG_FMT_I420;
  image->bps = 12;
  image->x_chroma_shift = image->y_chroma_shift = 1;
  image->img_data = data;
  image->w = image->d_w = state->width;
  image->h = image->d_h = state->height;

  image->stride[VPX_PLANE_Y] =
      gst_video_format_get_row_stride (state->format, 0, state->width);
  image->stride[VPX_PLANE_U] =
      gst_video_format_get_row_stride (state->format, 1, state->width);
  image->stride[VPX_PLANE_V] =
      gst_video_format_get_row_stride (state->format, 2, state->width);
  image->planes[VPX_PLANE_Y] =
      data + gst_video_format_get_component_offset (state->format, 0,
      state->width, state->height);
  image->planes[VPX_PLANE_U] =
      data + gst_video_format_get_component_offset (state->format, 1,
      state->width, state->height);
  image->planes[VPX_PLANE_V] =
      data + gst_video_format_get_component_offset (state->format, 2,
      state->width, state->height);

  return image;
}
static void
gst_video_balance_planar_yuv (GstVideoBalance * videobalance, guint8 * data)
{
  gint x, y;
  guint8 *ydata;
  guint8 *udata, *vdata;
  gint ystride, ustride, vstride;
  GstVideoFormat format;
  gint width, height;
  gint width2, height2;
  guint8 *tabley = videobalance->tabley;
  guint8 **tableu = videobalance->tableu;
  guint8 **tablev = videobalance->tablev;

  format = videobalance->format;
  width = videobalance->width;
  height = videobalance->height;

  ydata =
      data + gst_video_format_get_component_offset (format, 0, width, height);
  ystride = gst_video_format_get_row_stride (format, 0, width);

  for (y = 0; y < height; y++) {
    guint8 *yptr;

    yptr = ydata + y * ystride;
    for (x = 0; x < width; x++) {
      *ydata = tabley[*ydata];
      ydata++;
    }
  }

  width2 = gst_video_format_get_component_width (format, 1, width);
  height2 = gst_video_format_get_component_height (format, 1, height);

  udata =
      data + gst_video_format_get_component_offset (format, 1, width, height);
  vdata =
      data + gst_video_format_get_component_offset (format, 2, width, height);
  ustride = gst_video_format_get_row_stride (format, 1, width);
  vstride = gst_video_format_get_row_stride (format, 1, width);

  for (y = 0; y < height2; y++) {
    guint8 *uptr, *vptr;
    guint8 u1, v1;

    uptr = udata + y * ustride;
    vptr = vdata + y * vstride;

    for (x = 0; x < width2; x++) {
      u1 = *uptr;
      v1 = *vptr;

      *uptr++ = tableu[u1][v1];
      *vptr++ = tablev[u1][v1];
    }
  }
}
Example #3
0
static void
gst_color_effects_transform_rgb (GstColorEffects * filter, guint8 * data)
{
  gint i, j;
  gint width, height;
  gint pixel_stride, row_stride, row_wrap;
  guint32 r, g, b;
  guint32 luma;
  gint offsets[3];

  /* videoformat fun copied from videobalance */

  offsets[0] = gst_video_format_get_component_offset (filter->format, 0,
      filter->width, filter->height);
  offsets[1] = gst_video_format_get_component_offset (filter->format, 1,
      filter->width, filter->height);
  offsets[2] = gst_video_format_get_component_offset (filter->format, 2,
      filter->width, filter->height);

  width =
      gst_video_format_get_component_width (filter->format, 0, filter->width);
  height =
      gst_video_format_get_component_height (filter->format, 0, filter->height);
  row_stride =
      gst_video_format_get_row_stride (filter->format, 0, filter->width);
  pixel_stride = gst_video_format_get_pixel_stride (filter->format, 0);
  row_wrap = row_stride - pixel_stride * width;

  /* transform */

  for (i = 0; i < height; i++) {
    for (j = 0; j < width; j++) {
      r = data[offsets[0]];
      g = data[offsets[1]];
      b = data[offsets[2]];
      if (filter->map_luma) {
        /* BT. 709 coefficients in B8 fixed point */
        /* 0.2126 R + 0.7152 G + 0.0722 B */
        luma = ((r << 8) * 54) + ((g << 8) * 183) + ((b << 8) * 19);
        luma >>= 16;            /* get integer part */
        luma *= 3;              /* times 3 to retrieve the correct pixel from
                                 * the lut */
        /* map luma to lookup table */
        /* src.luma |-> table[luma].rgb */
        data[offsets[0]] = filter->table[luma];
        data[offsets[1]] = filter->table[luma + 1];
        data[offsets[2]] = filter->table[luma + 2];
      } else {
        /* map each color component to the correspondent lut color */
        /* src.r |-> table[r].r */
        /* src.g |-> table[g].g */
        /* src.b |-> table[b].b */
        data[offsets[0]] = filter->table[r * 3];
        data[offsets[1]] = filter->table[g * 3 + 1];
        data[offsets[2]] = filter->table[b * 3 + 2];
      }
      data += pixel_stride;
    }
Example #4
0
static void
gst_gamma_packed_rgb_ip (GstGamma * gamma, guint8 * data)
{
  gint i, j, height;
  gint width, row_stride, row_wrap;
  gint pixel_stride;
  const guint8 *table = gamma->gamma_table;
  gint offsets[3];
  gint r, g, b;
  gint y, u, v;

  offsets[0] = gst_video_format_get_component_offset (gamma->format, 0,
      gamma->width, gamma->height);
  offsets[1] = gst_video_format_get_component_offset (gamma->format, 1,
      gamma->width, gamma->height);
  offsets[2] = gst_video_format_get_component_offset (gamma->format, 2,
      gamma->width, gamma->height);

  width = gst_video_format_get_component_width (gamma->format, 0, gamma->width);
  height = gst_video_format_get_component_height (gamma->format, 0,
      gamma->height);
  row_stride = gst_video_format_get_row_stride (gamma->format, 0, gamma->width);
  pixel_stride = gst_video_format_get_pixel_stride (gamma->format, 0);
  row_wrap = row_stride - pixel_stride * width;

  for (i = 0; i < height; i++) {
    for (j = 0; j < width; j++) {
      r = data[offsets[0]];
      g = data[offsets[1]];
      b = data[offsets[2]];

      y = APPLY_MATRIX (cog_rgb_to_ycbcr_matrix_8bit_sdtv, 0, r, g, b);
      u = APPLY_MATRIX (cog_rgb_to_ycbcr_matrix_8bit_sdtv, 1, r, g, b);
      v = APPLY_MATRIX (cog_rgb_to_ycbcr_matrix_8bit_sdtv, 2, r, g, b);

      y = table[CLAMP (y, 0, 255)];
      r = APPLY_MATRIX (cog_ycbcr_to_rgb_matrix_8bit_sdtv, 0, y, u, v);
      g = APPLY_MATRIX (cog_ycbcr_to_rgb_matrix_8bit_sdtv, 1, y, u, v);
      b = APPLY_MATRIX (cog_ycbcr_to_rgb_matrix_8bit_sdtv, 2, y, u, v);

      data[offsets[0]] = CLAMP (r, 0, 255);
      data[offsets[1]] = CLAMP (g, 0, 255);
      data[offsets[2]] = CLAMP (b, 0, 255);
      data += pixel_stride;
    }
    data += row_wrap;
  }
}
Example #5
0
static void
gst_gamma_packed_yuv_ip (GstGamma * gamma, guint8 * data)
{
  gint i, j, height;
  gint width, row_stride, row_wrap;
  gint pixel_stride;
  const guint8 *table = gamma->gamma_table;

  data = data + gst_video_format_get_component_offset (gamma->format, 0,
      gamma->width, gamma->height);

  width = gst_video_format_get_component_width (gamma->format, 0, gamma->width);
  height = gst_video_format_get_component_height (gamma->format, 0,
      gamma->height);
  row_stride = gst_video_format_get_row_stride (gamma->format, 0, gamma->width);
  pixel_stride = gst_video_format_get_pixel_stride (gamma->format, 0);
  row_wrap = row_stride - pixel_stride * width;

  for (i = 0; i < height; i++) {
    for (j = 0; j < width; j++) {
      *data = table[*data];
      data += pixel_stride;
    }
    data += row_wrap;
  }
}
Example #6
0
/* Allocate buffer and copy image data into Y444 format */
static GstFlowReturn
theora_handle_image (GstTheoraDec * dec, th_ycbcr_buffer buf, GstBuffer ** out)
{
  gint width, height, stride;
  GstFlowReturn result;
  int i, plane;
  GstVideoFormat format;
  guint8 *dest, *src;

  switch (dec->info.pixel_fmt) {
    case TH_PF_444:
      format = GST_VIDEO_FORMAT_Y444;
      break;
    case TH_PF_420:
      format = GST_VIDEO_FORMAT_I420;
      break;
    case TH_PF_422:
      format = GST_VIDEO_FORMAT_Y42B;
      break;
    default:
      g_assert_not_reached ();
  }

  result =
      gst_pad_alloc_buffer_and_set_caps (dec->srcpad, GST_BUFFER_OFFSET_NONE,
      gst_video_format_get_size (format, dec->width, dec->height),
      GST_PAD_CAPS (dec->srcpad), out);
  if (G_UNLIKELY (result != GST_FLOW_OK)) {
    GST_DEBUG_OBJECT (dec, "could not get buffer, reason: %s",
        gst_flow_get_name (result));
    return result;
  }

  for (plane = 0; plane < 3; plane++) {
    width = gst_video_format_get_component_width (format, plane, dec->width);
    height = gst_video_format_get_component_height (format, plane, dec->height);
    stride = gst_video_format_get_row_stride (format, plane, dec->width);

    dest =
        GST_BUFFER_DATA (*out) + gst_video_format_get_component_offset (format,
        plane, dec->width, dec->height);
    src = buf[plane].data;
    src += ((height == dec->height) ? dec->offset_y : dec->offset_y / 2)
        * buf[plane].stride;
    src += (width == dec->width) ? dec->offset_x : dec->offset_x / 2;

    for (i = 0; i < height; i++) {
      memcpy (dest, src, width);

      dest += stride;
      src += buf[plane].stride;
    }
  }

  return GST_FLOW_OK;
}
Example #7
0
static void
gst_video_scale_setup_vs_image (VSImage * image, GstVideoFormat format,
    gint component, gint width, gint height, gint b_w, gint b_h, uint8_t * data)
{
  image->real_width =
      gst_video_format_get_component_width (format, component, width);
  image->real_height =
      gst_video_format_get_component_height (format, component, height);
  image->width =
      gst_video_format_get_component_width (format, component, MAX (1,
          width - b_w));
  image->height =
      gst_video_format_get_component_height (format, component, MAX (1,
          height - b_h));
  image->stride = gst_video_format_get_row_stride (format, component, width);

  image->border_top = (image->real_height - image->height) / 2;
  image->border_bottom = image->real_height - image->height - image->border_top;

  if (format == GST_VIDEO_FORMAT_YUY2 || format == GST_VIDEO_FORMAT_YVYU
      || format == GST_VIDEO_FORMAT_UYVY) {
    g_assert (component == 0);

    image->border_left = (image->real_width - image->width) / 2;

    if (image->border_left % 2 == 1)
      image->border_left--;
    image->border_right = image->real_width - image->width - image->border_left;
  } else {
    image->border_left = (image->real_width - image->width) / 2;
    image->border_right = image->real_width - image->width - image->border_left;
  }

  if (format == GST_VIDEO_FORMAT_I420
      || format == GST_VIDEO_FORMAT_YV12
      || format == GST_VIDEO_FORMAT_Y444
      || format == GST_VIDEO_FORMAT_Y42B || format == GST_VIDEO_FORMAT_Y41B) {
    image->real_pixels = data + gst_video_format_get_component_offset (format,
        component, width, height);
  } else {
    g_assert (component == 0);
    image->real_pixels = data;
  }

  image->pixels =
      image->real_pixels + image->border_top * image->stride +
      image->border_left * gst_video_format_get_pixel_stride (format,
      component);
}
Example #8
0
static void
gst_ffmpegscale_fill_info(GstFFMpegScale* scale, GstVideoFormat format,
                          guint width, guint height, gint stride[], gint offset[]) {
    gint i;

    for (i = 0; i < 3; i++) {
        stride[i] = gst_video_format_get_row_stride(format, i, width);
        offset[i] = gst_video_format_get_component_offset(format, i, width,
                    height);

        /* stay close to the ffmpeg offset way */
        if (offset[i] < 3) {
            offset[i] = 0;
        }

        GST_DEBUG_OBJECT(scale, "format %d, component %d; stride %d, offset %d",
                         format, i, stride[i], offset[i]);
    }
}
Example #9
0
static void
theora_enc_init_buffer (th_ycbcr_buffer buf, th_info * info, guint8 * data)
{
  GstVideoFormat format;
  guint i;

  switch (info->pixel_fmt) {
    case TH_PF_444:
      format = GST_VIDEO_FORMAT_Y444;
      break;
    case TH_PF_420:
      format = GST_VIDEO_FORMAT_I420;
      break;
    case TH_PF_422:
      format = GST_VIDEO_FORMAT_Y42B;
      break;
    default:
      g_assert_not_reached ();
  }

  /* According to Theora developer Timothy Terriberry, the Theora 
   * encoder will not use memory outside of pic_width/height, even when
   * the frame size is bigger. The values outside this region will be encoded
   * to default values.
   * Due to this, setting the frame's width/height as the buffer width/height
   * is perfectly ok, even though it does not strictly look ok.
   */
  for (i = 0; i < 3; i++) {
    buf[i].width =
        gst_video_format_get_component_width (format, i, info->frame_width);
    buf[i].height =
        gst_video_format_get_component_height (format, i, info->frame_height);

    buf[i].data =
        data + gst_video_format_get_component_offset (format, i,
        info->pic_width, info->pic_height);
    buf[i].stride =
        gst_video_format_get_row_stride (format, i, info->pic_width);
  }
}
Example #10
0
static void
sink_handoff_cb_I420 (GstElement * object, GstBuffer * buffer, GstPad * pad,
    gpointer user_data)
{
  guint *sink_pos = (guint *) user_data;
  gboolean contains_text = (*sink_pos == 1 || *sink_pos == 2);
  guint c, i, j;
  guint8 *data = GST_BUFFER_DATA (buffer);
  gboolean all_red = TRUE;
  guint8 *comp;
  gint comp_stride, comp_width, comp_height;
  const guint8 color[] = { 81, 90, 240 };

  fail_unless_equals_int (GST_BUFFER_SIZE (buffer),
      gst_video_format_get_size (GST_VIDEO_FORMAT_I420, 640, 480));

  for (c = 0; c < 3; c++) {
    comp =
        data + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, c,
        640, 480);
    comp_stride =
        gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, c, 640);
    comp_width =
        gst_video_format_get_component_width (GST_VIDEO_FORMAT_I420, c, 640);
    comp_height =
        gst_video_format_get_component_height (GST_VIDEO_FORMAT_I420, c, 480);

    for (i = 0; i < comp_height; i++) {
      for (j = 0; j < comp_width; j++) {
        all_red = all_red && (comp[i * comp_stride + j] == color[c]);
      }
    }
  }

  fail_unless (contains_text != all_red,
      "Frame %d is incorrect (all red %d, contains text %d)", *sink_pos,
      all_red, contains_text);
  *sink_pos = *sink_pos + 1;
}
static void
gst_video_balance_packed_rgb (GstVideoBalance * videobalance, guint8 * data)
{
  gint i, j, height;
  gint width, row_stride, row_wrap;
  gint pixel_stride;
  gint offsets[3];
  gint r, g, b;
  gint y, u, v;
  gint u_tmp, v_tmp;
  guint8 *tabley = videobalance->tabley;
  guint8 **tableu = videobalance->tableu;
  guint8 **tablev = videobalance->tablev;

  offsets[0] = gst_video_format_get_component_offset (videobalance->format, 0,
      videobalance->width, videobalance->height);
  offsets[1] = gst_video_format_get_component_offset (videobalance->format, 1,
      videobalance->width, videobalance->height);
  offsets[2] = gst_video_format_get_component_offset (videobalance->format, 2,
      videobalance->width, videobalance->height);

  width =
      gst_video_format_get_component_width (videobalance->format, 0,
      videobalance->width);
  height =
      gst_video_format_get_component_height (videobalance->format, 0,
      videobalance->height);
  row_stride =
      gst_video_format_get_row_stride (videobalance->format, 0,
      videobalance->width);
  pixel_stride = gst_video_format_get_pixel_stride (videobalance->format, 0);
  row_wrap = row_stride - pixel_stride * width;

  for (i = 0; i < height; i++) {
    for (j = 0; j < width; j++) {
      r = data[offsets[0]];
      g = data[offsets[1]];
      b = data[offsets[2]];

      y = APPLY_MATRIX (cog_rgb_to_ycbcr_matrix_8bit_sdtv, 0, r, g, b);
      u_tmp = APPLY_MATRIX (cog_rgb_to_ycbcr_matrix_8bit_sdtv, 1, r, g, b);
      v_tmp = APPLY_MATRIX (cog_rgb_to_ycbcr_matrix_8bit_sdtv, 2, r, g, b);

      y = CLAMP (y, 0, 255);
      u_tmp = CLAMP (u_tmp, 0, 255);
      v_tmp = CLAMP (v_tmp, 0, 255);

      y = tabley[y];
      u = tableu[u_tmp][v_tmp];
      v = tablev[u_tmp][v_tmp];

      r = APPLY_MATRIX (cog_ycbcr_to_rgb_matrix_8bit_sdtv, 0, y, u, v);
      g = APPLY_MATRIX (cog_ycbcr_to_rgb_matrix_8bit_sdtv, 1, y, u, v);
      b = APPLY_MATRIX (cog_ycbcr_to_rgb_matrix_8bit_sdtv, 2, y, u, v);

      data[offsets[0]] = CLAMP (r, 0, 255);
      data[offsets[1]] = CLAMP (g, 0, 255);
      data[offsets[2]] = CLAMP (b, 0, 255);
      data += pixel_stride;
    }
    data += row_wrap;
  }
}
gboolean
gst_vdp_video_buffer_upload (GstVdpVideoBuffer * video_buf, GstBuffer * src_buf,
    guint fourcc, gint width, gint height)
{
  guint8 *data[3];
  guint32 stride[3];
  VdpYCbCrFormat format;
  GstVdpDevice *device;
  VdpStatus status;

  g_return_val_if_fail (GST_IS_VDP_VIDEO_BUFFER (video_buf), FALSE);
  g_return_val_if_fail (GST_IS_BUFFER (src_buf), FALSE);

  switch (fourcc) {
    case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
    {
      data[0] = GST_BUFFER_DATA (src_buf) +
          gst_video_format_get_component_offset (GST_VIDEO_FORMAT_YV12,
          0, width, height);
      data[1] = GST_BUFFER_DATA (src_buf) +
          gst_video_format_get_component_offset (GST_VIDEO_FORMAT_YV12,
          2, width, height);
      data[2] = GST_BUFFER_DATA (src_buf) +
          gst_video_format_get_component_offset (GST_VIDEO_FORMAT_YV12,
          1, width, height);

      stride[0] = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_YV12,
          0, width);
      stride[1] = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_YV12,
          2, width);
      stride[2] = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_YV12,
          1, width);

      format = VDP_YCBCR_FORMAT_YV12;
      break;
    }
    case GST_MAKE_FOURCC ('I', '4', '2', '0'):
    {
      data[0] = GST_BUFFER_DATA (src_buf) +
          gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420,
          0, width, height);
      data[1] = GST_BUFFER_DATA (src_buf) +
          gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420,
          2, width, height);
      data[2] = GST_BUFFER_DATA (src_buf) +
          gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420,
          1, width, height);

      stride[0] = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420,
          0, width);
      stride[1] = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420,
          2, width);
      stride[2] = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420,
          1, width);

      format = VDP_YCBCR_FORMAT_YV12;
      break;
    }
    case GST_MAKE_FOURCC ('N', 'V', '1', '2'):
    {
      data[0] = GST_BUFFER_DATA (src_buf);
      data[1] = GST_BUFFER_DATA (src_buf) + width * height;

      stride[0] = width;
      stride[1] = width;

      format = VDP_YCBCR_FORMAT_NV12;
      break;
    }
    case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
    {
      data[0] = GST_BUFFER_DATA (src_buf);

      stride[0] = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_UYVY,
          0, width);

      format = VDP_YCBCR_FORMAT_UYVY;
      break;
    }
    case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
    {
      data[0] = GST_BUFFER_DATA (src_buf);

      stride[0] = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_YUY2,
          0, width);

      format = VDP_YCBCR_FORMAT_YUYV;
      break;
    }
    default:
      return FALSE;
  }

  device = video_buf->device;
  status = device->vdp_video_surface_put_bits_ycbcr (video_buf->surface, format,
      (void *) data, stride);
  if (G_UNLIKELY (status != VDP_STATUS_OK)) {
    GST_ERROR_OBJECT (video_buf, "Couldn't push YUV data to VDPAU, "
        "Error returned from vdpau was: %s",
        device->vdp_get_error_string (status));
    return FALSE;
  }

  return TRUE;
}
Example #13
0
static gboolean
gst_jpegenc_setcaps (GstPad * pad, GstCaps * caps)
{
  GstJpegEnc *enc = GST_JPEGENC (gst_pad_get_parent (pad));
  GstVideoFormat format;
  gint width, height;
  gint fps_num, fps_den;
  gint par_num, par_den;
  gint i;
  GstCaps *othercaps;
  gboolean ret;

  /* get info from caps */
  if (!gst_video_format_parse_caps (caps, &format, &width, &height))
    goto refuse_caps;
  /* optional; pass along if present */
  fps_num = fps_den = -1;
  par_num = par_den = -1;
  gst_video_parse_caps_framerate (caps, &fps_num, &fps_den);
  gst_video_parse_caps_pixel_aspect_ratio (caps, &par_num, &par_den);

  if (width == enc->width && height == enc->height && enc->format == format
      && fps_num == enc->fps_num && fps_den == enc->fps_den
      && par_num == enc->par_num && par_den == enc->par_den)
    return TRUE;

  /* store input description */
  enc->format = format;
  enc->width = width;
  enc->height = height;
  enc->fps_num = fps_num;
  enc->fps_den = fps_den;
  enc->par_num = par_num;
  enc->par_den = par_den;

  /* prepare a cached image description  */
  enc->channels = 3 + (gst_video_format_has_alpha (format) ? 1 : 0);
  /* ... but any alpha is disregarded in encoding */
  if (gst_video_format_is_gray (format))
    enc->channels = 1;
  else
    enc->channels = 3;
  enc->h_max_samp = 0;
  enc->v_max_samp = 0;
  for (i = 0; i < enc->channels; ++i) {
    enc->cwidth[i] = gst_video_format_get_component_width (format, i, width);
    enc->cheight[i] = gst_video_format_get_component_height (format, i, height);
    enc->offset[i] = gst_video_format_get_component_offset (format, i, width,
        height);
    enc->stride[i] = gst_video_format_get_row_stride (format, i, width);
    enc->inc[i] = gst_video_format_get_pixel_stride (format, i);
    enc->h_samp[i] = GST_ROUND_UP_4 (width) / enc->cwidth[i];
    enc->h_max_samp = MAX (enc->h_max_samp, enc->h_samp[i]);
    enc->v_samp[i] = GST_ROUND_UP_4 (height) / enc->cheight[i];
    enc->v_max_samp = MAX (enc->v_max_samp, enc->v_samp[i]);
  }
  /* samp should only be 1, 2 or 4 */
  g_assert (enc->h_max_samp <= 4);
  g_assert (enc->v_max_samp <= 4);
  /* now invert */
  /* maximum is invariant, as one of the components should have samp 1 */
  for (i = 0; i < enc->channels; ++i) {
    enc->h_samp[i] = enc->h_max_samp / enc->h_samp[i];
    enc->v_samp[i] = enc->v_max_samp / enc->v_samp[i];
  }
  enc->planar = (enc->inc[0] == 1 && enc->inc[1] == 1 && enc->inc[2] == 1);

  othercaps = gst_caps_copy (gst_pad_get_pad_template_caps (enc->srcpad));
  gst_caps_set_simple (othercaps,
      "width", G_TYPE_INT, enc->width, "height", G_TYPE_INT, enc->height, NULL);
  if (enc->fps_den > 0)
    gst_caps_set_simple (othercaps,
        "framerate", GST_TYPE_FRACTION, enc->fps_num, enc->fps_den, NULL);
  if (enc->par_den > 0)
    gst_caps_set_simple (othercaps,
        "pixel-aspect-ratio", GST_TYPE_FRACTION, enc->par_num, enc->par_den,
        NULL);

  ret = gst_pad_set_caps (enc->srcpad, othercaps);
  gst_caps_unref (othercaps);

  if (ret)
    gst_jpegenc_resync (enc);

  gst_object_unref (enc);

  return ret;

  /* ERRORS */
refuse_caps:
  {
    GST_WARNING_OBJECT (enc, "refused caps %" GST_PTR_FORMAT, caps);
    gst_object_unref (enc);
    return FALSE;
  }
}
Example #14
0
GstFlowReturn
gst_vdp_video_yuv_transform (GstBaseTransform * trans, GstBuffer * inbuf,
    GstBuffer * outbuf)
{
  GstVdpVideoYUV *video_yuv = GST_VDP_VIDEO_YUV (trans);
  GstVdpDevice *device;
  VdpVideoSurface surface;

  device = GST_VDP_VIDEO_BUFFER (inbuf)->device;
  surface = GST_VDP_VIDEO_BUFFER (inbuf)->surface;

  switch (video_yuv->format) {
    case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
    {
      VdpStatus status;
      guint8 *data[3];
      guint32 stride[3];

      data[0] = GST_BUFFER_DATA (outbuf) +
          gst_video_format_get_component_offset (GST_VIDEO_FORMAT_YV12,
          0, video_yuv->width, video_yuv->height);
      data[1] = GST_BUFFER_DATA (outbuf) +
          gst_video_format_get_component_offset (GST_VIDEO_FORMAT_YV12,
          2, video_yuv->width, video_yuv->height);
      data[2] = GST_BUFFER_DATA (outbuf) +
          gst_video_format_get_component_offset (GST_VIDEO_FORMAT_YV12,
          1, video_yuv->width, video_yuv->height);

      stride[0] = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_YV12,
          0, video_yuv->width);
      stride[1] = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_YV12,
          2, video_yuv->width);
      stride[2] = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_YV12,
          1, video_yuv->width);

      GST_LOG_OBJECT (video_yuv, "Entering vdp_video_surface_get_bits_ycbcr");
      status =
          device->vdp_video_surface_get_bits_ycbcr (surface,
          VDP_YCBCR_FORMAT_YV12, (void *) data, stride);
      GST_LOG_OBJECT (video_yuv,
          "Got status %d from vdp_video_surface_get_bits_ycbcr", status);
      if (G_UNLIKELY (status != VDP_STATUS_OK)) {
        GST_ELEMENT_ERROR (video_yuv, RESOURCE, READ,
            ("Couldn't get data from vdpau"),
            ("Error returned from vdpau was: %s",
                device->vdp_get_error_string (status)));
        return GST_FLOW_ERROR;
      }
      break;
    }
    case GST_MAKE_FOURCC ('I', '4', '2', '0'):
    {
      VdpStatus status;
      guint8 *data[3];
      guint32 stride[3];

      data[0] = GST_BUFFER_DATA (outbuf) +
          gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420,
          0, video_yuv->width, video_yuv->height);
      data[1] = GST_BUFFER_DATA (outbuf) +
          gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420,
          2, video_yuv->width, video_yuv->height);
      data[2] = GST_BUFFER_DATA (outbuf) +
          gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420,
          1, video_yuv->width, video_yuv->height);

      stride[0] = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420,
          0, video_yuv->width);
      stride[1] = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420,
          2, video_yuv->width);
      stride[2] = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420,
          1, video_yuv->width);

      GST_LOG_OBJECT (video_yuv, "Entering vdp_video_surface_get_bits_ycbcr");
      status =
          device->vdp_video_surface_get_bits_ycbcr (surface,
          VDP_YCBCR_FORMAT_YV12, (void *) data, stride);
      GST_LOG_OBJECT (video_yuv,
          "Got status %d from vdp_video_surface_get_bits_ycbcr", status);
      if (G_UNLIKELY (status != VDP_STATUS_OK)) {
        GST_ELEMENT_ERROR (video_yuv, RESOURCE, READ,
            ("Couldn't get data from vdpau"),
            ("Error returned from vdpau was: %s",
                device->vdp_get_error_string (status)));
        return GST_FLOW_ERROR;
      }
      break;
    }
    case GST_MAKE_FOURCC ('N', 'V', '1', '2'):
    {
      VdpStatus status;
      guint8 *data[2];
      guint32 stride[2];

      data[0] = GST_BUFFER_DATA (outbuf);
      data[1] = GST_BUFFER_DATA (outbuf) + video_yuv->width * video_yuv->height;

      stride[0] = video_yuv->width;
      stride[1] = video_yuv->width;

      GST_LOG_OBJECT (video_yuv, "Entering vdp_video_surface_get_bits_ycbcr");
      status =
          device->vdp_video_surface_get_bits_ycbcr (surface,
          VDP_YCBCR_FORMAT_NV12, (void *) data, stride);
      GST_LOG_OBJECT (video_yuv,
          "Got status %d from vdp_video_surface_get_bits_ycbcr", status);
      if (G_UNLIKELY (status != VDP_STATUS_OK)) {
        GST_ELEMENT_ERROR (video_yuv, RESOURCE, READ,
            ("Couldn't get data from vdpau"),
            ("Error returned from vdpau was: %s",
                device->vdp_get_error_string (status)));
        return GST_FLOW_ERROR;
      }
      break;
    }
    case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
    {
      VdpStatus status;
      guint8 *data[1];
      guint32 stride[1];

      data[0] = GST_BUFFER_DATA (outbuf);

      stride[0] = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_UYVY,
          0, video_yuv->width);

      GST_LOG_OBJECT (video_yuv, "Entering vdp_video_surface_get_bits_ycbcr");
      status =
          device->vdp_video_surface_get_bits_ycbcr (surface,
          VDP_YCBCR_FORMAT_UYVY, (void *) data, stride);
      GST_LOG_OBJECT (video_yuv,
          "Got status %d from vdp_video_surface_get_bits_ycbcr", status);
      if (G_UNLIKELY (status != VDP_STATUS_OK)) {
        GST_ELEMENT_ERROR (video_yuv, RESOURCE, READ,
            ("Couldn't get data from vdpau"),
            ("Error returned from vdpau was: %s",
                device->vdp_get_error_string (status)));
        return GST_FLOW_ERROR;
      }
      break;
    }
    case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
    {
      VdpStatus status;
      guint8 *data[1];
      guint32 stride[1];

      data[0] = GST_BUFFER_DATA (outbuf);

      stride[0] = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_YUY2,
          0, video_yuv->width);

      GST_LOG_OBJECT (video_yuv, "Entering vdp_video_surface_get_bits_ycbcr");
      status =
          device->vdp_video_surface_get_bits_ycbcr (surface,
          VDP_YCBCR_FORMAT_YUYV, (void *) data, stride);
      GST_LOG_OBJECT (video_yuv,
          "Got status %d from vdp_video_surface_get_bits_ycbcr", status);
      if (G_UNLIKELY (status != VDP_STATUS_OK)) {
        GST_ELEMENT_ERROR (video_yuv, RESOURCE, READ,
            ("Couldn't get data from vdpau"),
            ("Error returned from vdpau was: %s",
                device->vdp_get_error_string (status)));
        return GST_FLOW_ERROR;
      }
      break;
    }
    default:
      break;
  }

  gst_buffer_copy_metadata (outbuf, inbuf,
      GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);

  GST_LOG_OBJECT (video_yuv, "Pushing buffer with ts %" GST_TIME_FORMAT,
      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));

  return GST_FLOW_OK;
}
Example #15
0
static GstFlowReturn
gst_patchdetect_transform_ip (GstBaseTransform * trans, GstBuffer * buf)
{
  GstPatchdetect *patchdetect = GST_PATCHDETECT (trans);
  Frame frame;
  Point *points;
  int i, j;
  int blocks_x, blocks_y;
  int n_points;
  int n_patches;
  Patch *patches;
  guint8 *patchpix;
  int vec1_x, vec1_y;
  int vec2_x, vec2_y;
  Color detected_colors[24];
  gboolean detected = FALSE;

  frame.y = GST_BUFFER_DATA (buf);
  frame.ystride = gst_video_format_get_row_stride (patchdetect->format,
      0, patchdetect->width);
  frame.u =
      frame.y + gst_video_format_get_component_offset (patchdetect->format, 1,
      patchdetect->width, patchdetect->height);
  frame.ustride =
      gst_video_format_get_row_stride (patchdetect->format, 1,
      patchdetect->width);
  frame.v =
      frame.y + gst_video_format_get_component_offset (patchdetect->format, 2,
      patchdetect->width, patchdetect->height);
  frame.vstride =
      gst_video_format_get_row_stride (patchdetect->format, 2,
      patchdetect->width);
  frame.width = patchdetect->width;
  frame.height = patchdetect->height;
  frame.t = patchdetect->t;
  patchdetect->t++;

  blocks_y = (patchdetect->height & (~7)) / 8;
  blocks_x = (patchdetect->width & (~7)) / 8;

  patchpix = g_malloc0 (patchdetect->width * patchdetect->height);
  patches = g_malloc0 (sizeof (Patch) * 256);

  n_patches = 0;
  for (j = 0; j < blocks_y; j += 4) {
    for (i = 0; i < blocks_x; i += 4) {
      Stats block = { 0 };

      get_block_stats (&frame, i * 8, j * 8, &block);

      patches[n_patches].val = n_patches + 2;
      if (block.match) {
        if (patch_check (&frame, patchpix, i * 8, j * 8, 8, 8)) {
          patch_start (&frame, patchpix, patches + n_patches, i * 8, j * 8, 8,
              8);

          patches[n_patches].y = block.y;
          patches[n_patches].u = block.u;
          patches[n_patches].v = block.v;

          patch_grow (&frame, patchpix, patches + n_patches);
          n_patches++;
          g_assert (n_patches < 256);
        }
      }
    }
  }

  {
    int n;

    for (n = 0; n < n_patches; n++) {
      Patch *patch = &patches[n];
      int xsum;
      int ysum;

      if (patch->count > 10000)
        continue;
      patch->valid = TRUE;

      xsum = 0;
      ysum = 0;
      for (j = patch->ymin; j < patch->ymax; j++) {
        for (i = patch->xmin; i < patch->xmax; i++) {
          if (patchpix[j * frame.width + i] != patch->val)
            continue;
          xsum += i;
          ysum += j;
        }
      }

      patch->cen_x = xsum / patch->count;
      patch->cen_y = ysum / patch->count;
    }

  }

  points = g_malloc0 (sizeof (Point) * 1000);
  n_points = 0;

  for (i = 0; i < n_patches; i++) {
    for (j = i + 1; j < n_patches; j++) {
      int dist_x, dist_y;

      if (i == j)
        continue;

      dist_x = patches[i].cen_x - patches[j].cen_x;
      dist_y = patches[i].cen_y - patches[j].cen_y;

      if (dist_x < 0) {
        dist_x = -dist_x;
        dist_y = -dist_y;
      }
      if (ABS (2 * dist_y) < dist_x && dist_x < 100) {
        points[n_points].x = dist_x;
        points[n_points].y = dist_y;
        points[n_points].valid = TRUE;
        points[n_points].patch1 = i;
        points[n_points].patch2 = j;
        n_points++;
        g_assert (n_points < 1000);
      }
    }
  }

  {
    int dist;
    int ave_x = 0, ave_y = 0;
    for (dist = 50; dist >= 10; dist -= 5) {
      int sum_x, sum_y;
      int n_valid;

      sum_x = 0;
      sum_y = 0;
      n_valid = 0;
      for (i = 0; i < n_points; i++) {
        if (!points[i].valid)
          continue;
        sum_x += points[i].x;
        sum_y += points[i].y;
        n_valid++;
      }
      if (n_valid == 0)
        continue;
      ave_x = sum_x / n_valid;
      ave_y = sum_y / n_valid;

      for (i = 0; i < n_points; i++) {
        int d;
        if (!points[i].valid)
          continue;
        d = (points[i].x - ave_x) * (points[i].x - ave_x);
        d += (points[i].y - ave_y) * (points[i].y - ave_y);
        if (d > dist * dist)
          points[i].valid = FALSE;
      }
    }
    vec1_x = ave_x;
    vec1_y = ave_y;
  }

  n_points = 0;
  for (i = 0; i < n_patches; i++) {
    for (j = i + 1; j < n_patches; j++) {
      int dist_x, dist_y;

      if (i == j)
        continue;

      dist_x = patches[i].cen_x - patches[j].cen_x;
      dist_y = patches[i].cen_y - patches[j].cen_y;

      if (dist_y < 0) {
        dist_x = -dist_x;
        dist_y = -dist_y;
      }
      if (ABS (2 * dist_x) < dist_y && dist_y < 100) {
        points[n_points].x = dist_x;
        points[n_points].y = dist_y;
        points[n_points].valid = TRUE;
        points[n_points].patch1 = i;
        points[n_points].patch2 = j;
        n_points++;
        g_assert (n_points < 1000);
      }
    }
  }

  {
    int dist;
    int ave_x = 0, ave_y = 0;
    for (dist = 50; dist >= 10; dist -= 5) {
      int sum_x, sum_y;
      int n_valid;

      sum_x = 0;
      sum_y = 0;
      n_valid = 0;
      for (i = 0; i < n_points; i++) {
        if (!points[i].valid)
          continue;
        sum_x += points[i].x;
        sum_y += points[i].y;
        n_valid++;
      }
      if (n_valid == 0)
        continue;
      ave_x = sum_x / n_valid;
      ave_y = sum_y / n_valid;

      for (i = 0; i < n_points; i++) {
        int d;
        if (!points[i].valid)
          continue;
        d = (points[i].x - ave_x) * (points[i].x - ave_x);
        d += (points[i].y - ave_y) * (points[i].y - ave_y);
        if (d > dist * dist)
          points[i].valid = FALSE;
      }
    }
    vec2_x = ave_x;
    vec2_y = ave_y;
  }

#if 0
  for (i = 0; i < n_points; i++) {
    if (!points[i].valid)
      continue;
    paint_block (&frame, 4 * points[i].x, 240 + 4 * points[i].y, 16);
  }
#endif
#if 0
  paint_block (&frame, 360, 240, 16);
  paint_block (&frame, 360 + vec1_x, 240 + vec1_y, 16);
  paint_block (&frame, 360 + vec2_x, 240 + vec2_y, 16);
#endif

  {
    double m00, m01, m10, m11;
    double det;
    double v1, v2;
    double ave_v1 = 0, ave_v2 = 0;

    det = vec1_x * vec2_y - vec1_y * vec2_x;
    m00 = vec2_y / det;
    m01 = -vec2_x / det;
    m10 = -vec1_y / det;
    m11 = vec1_x / det;

    for (i = 0; i < n_patches - 1; i++) {
      int count = 0;
      double sum_v1 = 0;
      double sum_v2 = 0;

      if (!patches[i].valid)
        continue;

      n_points = 0;
      for (j = i + 1; j < n_patches; j++) {
        int diff_x = patches[j].cen_x - patches[i].cen_x;
        int diff_y = patches[j].cen_y - patches[i].cen_y;

        if (!patches[j].valid)
          continue;

        v1 = diff_x * m00 + diff_y * m01;
        v2 = diff_x * m10 + diff_y * m11;

        if (v1 > -0.5 && v1 < 5.5 && v2 > -0.5 && v2 < 3.5 &&
            ABS (v1 - rint (v1)) < 0.1 && ABS (v2 - rint (v2)) < 0.1) {
          sum_v1 += v1 - rint (v1);
          sum_v2 += v2 - rint (v2);
          count++;
        }
      }
      ave_v1 = sum_v1 / count;
      ave_v2 = sum_v2 / count;

      if (count > 20) {
        int k;
        for (j = 0; j < 4; j++) {
          for (k = 0; k < 6; k++) {
            Stats block;

            int xx;
            int yy;
            xx = patches[i].cen_x + (ave_v1 + k) * vec1_x + (ave_v2 +
                j) * vec2_x;
            yy = patches[i].cen_y + (ave_v1 + k) * vec1_y + (ave_v2 +
                j) * vec2_y;

            get_block_stats (&frame, xx - 4, yy - 4, &block);
            //GST_ERROR("%d %d: %d %d %d", k, j, block.y, block.u, block.v);

            detected_colors[k + j * 6].y = block.y;
            detected_colors[k + j * 6].u = block.u;
            detected_colors[k + j * 6].v = block.v;

            paint_block (&frame, xx - 4, yy - 4, 16);
          }
        }

        detected = TRUE;

#if 0
        for (j = i + 1; j < n_patches; j++) {
          int diff_x = patches[j].cen_x - patches[i].cen_x;
          int diff_y = patches[j].cen_y - patches[i].cen_y;
          int xx;
          int yy;

          if (!patches[j].valid)
            continue;

          v1 = diff_x * m00 + diff_y * m01;
          v2 = diff_x * m10 + diff_y * m11;

          if (v1 > -0.5 && v1 < 5.5 && v2 > -0.5 && v2 < 3.5 &&
              ABS (v1 - rint (v1)) < 0.1 && ABS (v2 - rint (v2)) < 0.1) {
            v1 = rint (v1);
            v2 = rint (v2);
            xx = patches[i].cen_x + (ave_v1 + v1) * vec1_x + (ave_v2 +
                v2) * vec2_x;
            yy = patches[i].cen_y + (ave_v1 + v1) * vec1_y + (ave_v2 +
                v2) * vec2_y;

            paint_block (&frame, patches[j].cen_x, patches[j].cen_y, 128);
            paint_block (&frame, xx, yy, 16);
          }
        }
        paint_block (&frame, patches[i].cen_x, patches[i].cen_y, 240);
#endif
        break;
      }
    }
  }

#define N 10
  if (detected) {
    int i, j, k;
    int n = N;
    double diff = 0;
    double matrix[10][10] = { {0} };
    double vy[10] = { 0 };
    double vu[10] = { 0 };
    double vv[10] = { 0 };
    double *by = patchdetect->by;
    double *bu = patchdetect->bu;
    double *bv = patchdetect->bv;
    double flip_diff = 0;

    for (i = 0; i < 24; i++) {
      diff += ABS (detected_colors[i].y - patch_colors[i].y);
      diff += ABS (detected_colors[i].u - patch_colors[i].u);
      diff += ABS (detected_colors[i].v - patch_colors[i].v);

      flip_diff += ABS (detected_colors[23 - i].y - patch_colors[i].y);
      flip_diff += ABS (detected_colors[23 - i].u - patch_colors[i].u);
      flip_diff += ABS (detected_colors[23 - i].v - patch_colors[i].v);
    }
    GST_ERROR ("uncorrected error %g (flipped %g)", diff / 24.0,
        flip_diff / 24.0);
    if (flip_diff < diff) {
      for (i = 0; i < 12; i++) {
        Color tmp;
        tmp = detected_colors[i];
        detected_colors[i] = detected_colors[23 - i];
        detected_colors[23 - i] = tmp;
      }
    }

    for (i = 0; i < 24; i++) {
      int dy = detected_colors[i].y - patch_colors[i].y;
      int du = detected_colors[i].u - patch_colors[i].u;
      int dv = detected_colors[i].v - patch_colors[i].v;
      int py = detected_colors[i].y - 128;
      int pu = detected_colors[i].u - 128;
      int pv = detected_colors[i].v - 128;
      int w = (i < 18) ? 1 : 2;
      double z[10];

      diff += ABS (dy) + ABS (du) + ABS (dv);

      z[0] = 1;
      z[1] = py;
      z[2] = pu;
      z[3] = pv;
      z[4] = py * py;
      z[5] = py * pu;
      z[6] = py * pv;
      z[7] = pu * pu;
      z[8] = pu * pv;
      z[9] = pv * pv;

      for (j = 0; j < n; j++) {
        for (k = 0; k < n; k++) {
          matrix[j][k] += w * z[j] * z[k];
        }

        vy[j] += w * dy * z[j];
        vu[j] += w * du * z[j];
        vv[j] += w * dv * z[j];
      }
    }

    invert_matrix (matrix, n);

    for (i = 0; i < n; i++) {
      by[i] = 0;
      bu[i] = 0;
      bv[i] = 0;
      for (j = 0; j < n; j++) {
        by[i] += matrix[i][j] * vy[j];
        bu[i] += matrix[i][j] * vu[j];
        bv[i] += matrix[i][j] * vv[j];
      }
    }

    //GST_ERROR("a %g %g %g b %g %g %g", ay, au, av, by, bu, bv);

    diff = 0;
    for (i = 0; i < 24; i++) {
      double cy, cu, cv;
      double z[10];
      int py = detected_colors[i].y - 128;
      int pu = detected_colors[i].u - 128;
      int pv = detected_colors[i].v - 128;

      z[0] = 1;
      z[1] = py;
      z[2] = pu;
      z[3] = pv;
      z[4] = py * py;
      z[5] = py * pu;
      z[6] = py * pv;
      z[7] = pu * pu;
      z[8] = pu * pv;
      z[9] = pv * pv;

      cy = 0;
      cu = 0;
      cv = 0;
      for (j = 0; j < n; j++) {
        cy += by[j] * z[j];
        cu += bu[j] * z[j];
        cv += bv[j] * z[j];
      }

      diff += fabs (patch_colors[i].y - (128 + py - cy));
      diff += fabs (patch_colors[i].u - (128 + pu - cu));
      diff += fabs (patch_colors[i].v - (128 + pv - cv));
    }
    GST_ERROR ("average error %g", diff / 24.0);
    patchdetect->valid = 3000;
  }

  if (patchdetect->valid > 0) {
    int n = N;
    guint8 *u1, *u2;
    guint8 *v1, *v2;
    double *by = patchdetect->by;
    double *bu = patchdetect->bu;
    double *bv = patchdetect->bv;

    patchdetect->valid--;
    u1 = g_malloc (frame.width);
    u2 = g_malloc (frame.width);
    v1 = g_malloc (frame.width);
    v2 = g_malloc (frame.width);

    for (j = 0; j < frame.height; j += 2) {
      for (i = 0; i < frame.width / 2; i++) {
        u1[2 * i + 0] = frame.u[(j / 2) * frame.ustride + i];
        u1[2 * i + 1] = u1[2 * i + 0];
        u2[2 * i + 0] = u1[2 * i + 0];
        u2[2 * i + 1] = u1[2 * i + 0];
        v1[2 * i + 0] = frame.v[(j / 2) * frame.vstride + i];
        v1[2 * i + 1] = v1[2 * i + 0];
        v2[2 * i + 0] = v1[2 * i + 0];
        v2[2 * i + 1] = v1[2 * i + 0];
      }
      for (i = 0; i < frame.width; i++) {
        int k;
        double z[10];
        double cy, cu, cv;
        int y, u, v;
        int py, pu, pv;

        y = frame.y[(j + 0) * frame.ystride + i];
        u = u1[i];
        v = v1[i];

        py = y - 128;
        pu = u - 128;
        pv = v - 128;

        z[0] = 1;
        z[1] = py;
        z[2] = pu;
        z[3] = pv;
        z[4] = py * py;
        z[5] = py * pu;
        z[6] = py * pv;
        z[7] = pu * pu;
        z[8] = pu * pv;
        z[9] = pv * pv;

        cy = 0;
        cu = 0;
        cv = 0;
        for (k = 0; k < n; k++) {
          cy += by[k] * z[k];
          cu += bu[k] * z[k];
          cv += bv[k] * z[k];
        }

        frame.y[(j + 0) * frame.ystride + i] = CLAMP (rint (y - cy), 0, 255);
        u1[i] = CLAMP (rint (u - cu), 0, 255);
        v1[i] = CLAMP (rint (v - cv), 0, 255);

        y = frame.y[(j + 1) * frame.ystride + i];
        u = u2[i];
        v = v2[i];

        py = y - 128;
        pu = u - 128;
        pv = v - 128;

        z[0] = 1;
        z[1] = py;
        z[2] = pu;
        z[3] = pv;
        z[4] = py * py;
        z[5] = py * pu;
        z[6] = py * pv;
        z[7] = pu * pu;
        z[8] = pu * pv;
        z[9] = pv * pv;

        cy = 0;
        cu = 0;
        cv = 0;
        for (k = 0; k < n; k++) {
          cy += by[k] * z[k];
          cu += bu[k] * z[k];
          cv += bv[k] * z[k];
        }

        frame.y[(j + 1) * frame.ystride + i] = CLAMP (rint (y - cy), 0, 255);
        u2[i] = CLAMP (rint (u - cu), 0, 255);
        v2[i] = CLAMP (rint (v - cv), 0, 255);
      }
      for (i = 0; i < frame.width / 2; i++) {
        frame.u[(j / 2) * frame.ustride + i] = (u1[2 * i + 0] +
            u1[2 * i + 1] + u2[2 * i + 0] + u2[2 * i + 1] + 2) >> 2;
        frame.v[(j / 2) * frame.vstride + i] = (v1[2 * i + 0] +
            v1[2 * i + 1] + v2[2 * i + 0] + v2[2 * i + 1] + 2) >> 2;
      }
    }

    g_free (u1);
    g_free (u2);
    g_free (v1);
    g_free (v2);
  }
Example #16
0
static gboolean
gst_eglglessink_fill_texture (GstEglGlesSink * eglglessink, GstBuffer * buf)
{
  gint w, h;

  w = GST_VIDEO_SINK_WIDTH (eglglessink);
  h = GST_VIDEO_SINK_HEIGHT (eglglessink);

  GST_DEBUG_OBJECT (eglglessink,
      "Got good buffer %p. Sink geometry is %dx%d size %d", buf, w, h,
      buf ? GST_BUFFER_SIZE (buf) : -1);

  switch (eglglessink->format) {
    case GST_VIDEO_FORMAT_RGBA:
    case GST_VIDEO_FORMAT_BGRA:
    case GST_VIDEO_FORMAT_ARGB:
    case GST_VIDEO_FORMAT_ABGR:
    case GST_VIDEO_FORMAT_RGBx:
    case GST_VIDEO_FORMAT_BGRx:
    case GST_VIDEO_FORMAT_xRGB:
    case GST_VIDEO_FORMAT_xBGR:
      glActiveTexture (GL_TEXTURE0);
      glBindTexture (GL_TEXTURE_2D, eglglessink->egl_context->texture[0]);
      glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
          GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf));
      break;
    case GST_VIDEO_FORMAT_AYUV:
      glActiveTexture (GL_TEXTURE0);
      glBindTexture (GL_TEXTURE_2D, eglglessink->egl_context->texture[0]);
      glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
          GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf));
      break;
    case GST_VIDEO_FORMAT_Y444:
    case GST_VIDEO_FORMAT_I420:
    case GST_VIDEO_FORMAT_YV12:
    case GST_VIDEO_FORMAT_Y42B:
    case GST_VIDEO_FORMAT_Y41B:{
      gint coffset, cw, ch;

      coffset =
          gst_video_format_get_component_offset (eglglessink->format, 0, w, h);
      cw = gst_video_format_get_component_width (eglglessink->format, 0, w);
      ch = gst_video_format_get_component_height (eglglessink->format, 0, h);
      glActiveTexture (GL_TEXTURE0);
      glBindTexture (GL_TEXTURE_2D, eglglessink->egl_context->texture[0]);
      glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE, cw, ch, 0,
          GL_LUMINANCE, GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf) + coffset);
      coffset =
          gst_video_format_get_component_offset (eglglessink->format, 1, w, h);
      cw = gst_video_format_get_component_width (eglglessink->format, 1, w);
      ch = gst_video_format_get_component_height (eglglessink->format, 1, h);
      glActiveTexture (GL_TEXTURE1);
      glBindTexture (GL_TEXTURE_2D, eglglessink->egl_context->texture[1]);
      glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE, cw, ch, 0,
          GL_LUMINANCE, GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf) + coffset);
      coffset =
          gst_video_format_get_component_offset (eglglessink->format, 2, w, h);
      cw = gst_video_format_get_component_width (eglglessink->format, 2, w);
      ch = gst_video_format_get_component_height (eglglessink->format, 2, h);
      glActiveTexture (GL_TEXTURE2);
      glBindTexture (GL_TEXTURE_2D, eglglessink->egl_context->texture[2]);
      glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE, cw, ch, 0,
          GL_LUMINANCE, GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf) + coffset);
      break;
    }
    case GST_VIDEO_FORMAT_YUY2:
    case GST_VIDEO_FORMAT_YVYU:
    case GST_VIDEO_FORMAT_UYVY:
      glActiveTexture (GL_TEXTURE0);
      glBindTexture (GL_TEXTURE_2D, eglglessink->egl_context->texture[0]);
      glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, w, h, 0,
          GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf));
      glActiveTexture (GL_TEXTURE1);
      glBindTexture (GL_TEXTURE_2D, eglglessink->egl_context->texture[1]);
      glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, GST_ROUND_UP_2 (w) / 2,
          h, 0, GL_RGBA, GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf));
      break;
    case GST_VIDEO_FORMAT_NV12:
    case GST_VIDEO_FORMAT_NV21:{
      gint coffset, cw, ch;

      coffset =
          gst_video_format_get_component_offset (eglglessink->format, 0, w, h);
      cw = gst_video_format_get_component_width (eglglessink->format, 0, w);
      ch = gst_video_format_get_component_height (eglglessink->format, 0, h);
      glActiveTexture (GL_TEXTURE0);
      glBindTexture (GL_TEXTURE_2D, eglglessink->egl_context->texture[0]);
      glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE, cw, ch, 0,
          GL_LUMINANCE, GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf) + coffset);

      coffset =
          gst_video_format_get_component_offset (eglglessink->format,
          (eglglessink->format == GST_VIDEO_FORMAT_NV12 ? 1 : 2), w, h);
      cw = gst_video_format_get_component_width (eglglessink->format, 1, w);
      ch = gst_video_format_get_component_height (eglglessink->format, 1, h);
      glActiveTexture (GL_TEXTURE1);
      glBindTexture (GL_TEXTURE_2D, eglglessink->egl_context->texture[1]);
      glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, cw, ch, 0,
          GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE,
          GST_BUFFER_DATA (buf) + coffset);
      break;
    }
    default:
      g_assert_not_reached ();
      break;
  }

  if (got_gl_error ("glTexImage2D"))
    goto HANDLE_ERROR;

  return TRUE;

HANDLE_ERROR:
  return FALSE;
}
Example #17
0
static void
gst_smpte_alpha_process_i420_ayuv (GstSMPTEAlpha * smpte, const guint8 * in,
    guint8 * out, GstMask * mask, gint width, gint height, gint border,
    gint pos)
{
  const guint8 *srcY;
  const guint8 *srcU;
  const guint8 *srcV;
  gint i, j;
  gint src_wrap, src_uv_wrap;
  gint y_stride, uv_stride;
  gboolean odd_width;
  const guint32 *maskp;
  gint value;
  gint min, max;

  if (border == 0)
    border++;

  min = pos - border;
  max = pos;
  GST_DEBUG_OBJECT (smpte, "pos %d, min %d, max %d, border %d", pos, min, max,
      border);

  maskp = mask->data;

  y_stride = gst_video_format_get_row_stride (smpte->in_format, 0, width);
  uv_stride = gst_video_format_get_row_stride (smpte->in_format, 1, width);

  src_wrap = y_stride - width;
  src_uv_wrap = uv_stride - (width / 2);

  srcY = in;
  srcU = in + gst_video_format_get_component_offset (smpte->in_format,
      1, width, height);
  srcV = in + gst_video_format_get_component_offset (smpte->in_format,
      2, width, height);

  odd_width = (width % 2 != 0);

  for (i = 0; i < height; i++) {
    for (j = 0; j < width / 2; j++) {
      value = *maskp++;
      *out++ = (0xff * ((CLAMP (value, min, max) - min) << 8) / border) >> 8;
      *out++ = *srcY++;
      *out++ = *srcU;
      *out++ = *srcV;
      value = *maskp++;
      *out++ = (0xff * ((CLAMP (value, min, max) - min) << 8) / border) >> 8;
      *out++ = *srcY++;
      *out++ = *srcU++;
      *out++ = *srcV++;
    }
    /* Might have one odd column left to do */
    if (odd_width) {
      value = *maskp++;
      *out++ = (0xff * ((CLAMP (value, min, max) - min) << 8) / border) >> 8;
      *out++ = *srcY++;
      *out++ = *srcU;
      *out++ = *srcV;
    }
    if (i % 2 == 0) {
      srcU -= width / 2;
      srcV -= width / 2;
    } else {
      srcU += src_uv_wrap;
      srcV += src_uv_wrap;
    }
    srcY += src_wrap;
  }
}
bool GStreamerReader::DecodeVideoFrame(bool &aKeyFrameSkip,
                                         int64_t aTimeThreshold)
{
  NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");

  GstBuffer* buffer = nullptr;
  int64_t timestamp, nextTimestamp;
  while (true)
  {
    if (!WaitForDecodedData(&mVideoSinkBufferCount)) {
      mVideoQueue.Finish();
      break;
    }
    mDecoder->NotifyDecodedFrames(0, 1);

    buffer = gst_app_sink_pull_buffer(mVideoAppSink);
    bool isKeyframe = !GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DISCONT);
    if ((aKeyFrameSkip && !isKeyframe)) {
      gst_buffer_unref(buffer);
      buffer = nullptr;
      continue;
    }

    timestamp = GST_BUFFER_TIMESTAMP(buffer);
    {
      ReentrantMonitorAutoEnter mon(mGstThreadsMonitor);
      timestamp = gst_segment_to_stream_time(&mVideoSegment,
          GST_FORMAT_TIME, timestamp);
    }
    NS_ASSERTION(GST_CLOCK_TIME_IS_VALID(timestamp),
        "frame has invalid timestamp");
    timestamp = nextTimestamp = GST_TIME_AS_USECONDS(timestamp);
    if (GST_CLOCK_TIME_IS_VALID(GST_BUFFER_DURATION(buffer)))
      nextTimestamp += GST_TIME_AS_USECONDS(GST_BUFFER_DURATION(buffer));
    else if (fpsNum && fpsDen)
      /* add 1-frame duration */
      nextTimestamp += gst_util_uint64_scale(GST_USECOND, fpsNum, fpsDen);

    if (timestamp < aTimeThreshold) {
      LOG(PR_LOG_DEBUG, ("skipping frame %" GST_TIME_FORMAT
            " threshold %" GST_TIME_FORMAT,
            GST_TIME_ARGS(timestamp), GST_TIME_ARGS(aTimeThreshold)));
      gst_buffer_unref(buffer);
      buffer = nullptr;
      continue;
    }

    break;
  }

  if (!buffer)
    /* no more frames */
    return false;

  nsRefPtr<PlanarYCbCrImage> image;
#if GST_VERSION_MICRO >= 36
  const GstStructure* structure = gst_buffer_get_qdata(buffer,
      g_quark_from_string("moz-reader-data"));
  const GValue* value = gst_structure_get_value(structure, "image");
  if (value) {
    BufferData* data = reinterpret_cast<BufferData*>(g_value_get_boxed(value));
    image = data->mImage;
  }
#endif

  if (!image) {
    /* Ugh, upstream is not calling gst_pad_alloc_buffer(). Fallback to
     * allocating a PlanarYCbCrImage backed GstBuffer here and memcpy.
     */
    GstBuffer* tmp = nullptr;
    AllocateVideoBufferFull(nullptr, GST_BUFFER_OFFSET(buffer),
        GST_BUFFER_SIZE(buffer), nullptr, &tmp, image);

    /* copy */
    gst_buffer_copy_metadata(tmp, buffer, (GstBufferCopyFlags)GST_BUFFER_COPY_ALL);
    memcpy(GST_BUFFER_DATA(tmp), GST_BUFFER_DATA(buffer),
        GST_BUFFER_SIZE(tmp));
    gst_buffer_unref(buffer);
    buffer = tmp;
  }

  guint8* data = GST_BUFFER_DATA(buffer);

  int width = mPicture.width;
  int height = mPicture.height;
  GstVideoFormat format = mFormat;

  VideoData::YCbCrBuffer b;
  for(int i = 0; i < 3; i++) {
    b.mPlanes[i].mData = data + gst_video_format_get_component_offset(format, i,
        width, height);
    b.mPlanes[i].mStride = gst_video_format_get_row_stride(format, i, width);
    b.mPlanes[i].mHeight = gst_video_format_get_component_height(format,
        i, height);
    b.mPlanes[i].mWidth = gst_video_format_get_component_width(format,
        i, width);
    b.mPlanes[i].mOffset = 0;
    b.mPlanes[i].mSkip = 0;
  }

  bool isKeyframe = !GST_BUFFER_FLAG_IS_SET(buffer,
      GST_BUFFER_FLAG_DELTA_UNIT);
  /* XXX ? */
  int64_t offset = 0;
  VideoData* video = VideoData::Create(mInfo, image, offset,
                                       timestamp, nextTimestamp, b,
                                       isKeyframe, -1, mPicture);
  mVideoQueue.Push(video);
  gst_buffer_unref(buffer);

  return true;
}
Example #19
0
static void
gst_video_flip_planar_yuv (GstVideoFlip * videoflip, guint8 * dest,
    const guint8 * src)
{
  gint x, y;
  guint8 const *s;
  guint8 *d;
  GstVideoFormat format = videoflip->format;
  gint sw = videoflip->from_width;
  gint sh = videoflip->from_height;
  gint dw = videoflip->to_width;
  gint dh = videoflip->to_height;
  gint src_y_stride, src_u_stride, src_v_stride;
  gint src_y_offset, src_u_offset, src_v_offset;
  gint src_y_height, src_u_height, src_v_height;
  gint src_y_width, src_u_width, src_v_width;
  gint dest_y_stride, dest_u_stride, dest_v_stride;
  gint dest_y_offset, dest_u_offset, dest_v_offset;
  gint dest_y_height, dest_u_height, dest_v_height;
  gint dest_y_width, dest_u_width, dest_v_width;

  src_y_stride = gst_video_format_get_row_stride (format, 0, sw);
  src_u_stride = gst_video_format_get_row_stride (format, 1, sw);
  src_v_stride = gst_video_format_get_row_stride (format, 2, sw);

  dest_y_stride = gst_video_format_get_row_stride (format, 0, dw);
  dest_u_stride = gst_video_format_get_row_stride (format, 1, dw);
  dest_v_stride = gst_video_format_get_row_stride (format, 2, dw);

  src_y_offset = gst_video_format_get_component_offset (format, 0, sw, sh);
  src_u_offset = gst_video_format_get_component_offset (format, 1, sw, sh);
  src_v_offset = gst_video_format_get_component_offset (format, 2, sw, sh);

  dest_y_offset = gst_video_format_get_component_offset (format, 0, dw, dh);
  dest_u_offset = gst_video_format_get_component_offset (format, 1, dw, dh);
  dest_v_offset = gst_video_format_get_component_offset (format, 2, dw, dh);

  src_y_width = gst_video_format_get_component_width (format, 0, sw);
  src_u_width = gst_video_format_get_component_width (format, 1, sw);
  src_v_width = gst_video_format_get_component_width (format, 2, sw);

  dest_y_width = gst_video_format_get_component_width (format, 0, dw);
  dest_u_width = gst_video_format_get_component_width (format, 1, dw);
  dest_v_width = gst_video_format_get_component_width (format, 2, dw);

  src_y_height = gst_video_format_get_component_height (format, 0, sh);
  src_u_height = gst_video_format_get_component_height (format, 1, sh);
  src_v_height = gst_video_format_get_component_height (format, 2, sh);

  dest_y_height = gst_video_format_get_component_height (format, 0, dh);
  dest_u_height = gst_video_format_get_component_height (format, 1, dh);
  dest_v_height = gst_video_format_get_component_height (format, 2, dh);

  switch (videoflip->method) {
    case GST_VIDEO_FLIP_METHOD_90R:
      /* Flip Y */
      s = src + src_y_offset;
      d = dest + dest_y_offset;
      for (y = 0; y < dest_y_height; y++) {
        for (x = 0; x < dest_y_width; x++) {
          d[y * dest_y_stride + x] =
              s[(src_y_height - 1 - x) * src_y_stride + y];
        }
      }
      /* Flip U */
      s = src + src_u_offset;
      d = dest + dest_u_offset;
      for (y = 0; y < dest_u_height; y++) {
        for (x = 0; x < dest_u_width; x++) {
          d[y * dest_u_stride + x] =
              s[(src_u_height - 1 - x) * src_u_stride + y];
        }
      }
      /* Flip V */
      s = src + src_v_offset;
      d = dest + dest_v_offset;
      for (y = 0; y < dest_v_height; y++) {
        for (x = 0; x < dest_v_width; x++) {
          d[y * dest_v_stride + x] =
              s[(src_v_height - 1 - x) * src_v_stride + y];
        }
      }
      break;
    case GST_VIDEO_FLIP_METHOD_90L:
      /* Flip Y */
      s = src + src_y_offset;
      d = dest + dest_y_offset;
      for (y = 0; y < dest_y_height; y++) {
        for (x = 0; x < dest_y_width; x++) {
          d[y * dest_y_stride + x] =
              s[x * src_y_stride + (src_y_width - 1 - y)];
        }
      }
      /* Flip U */
      s = src + src_u_offset;
      d = dest + dest_u_offset;
      for (y = 0; y < dest_u_height; y++) {
        for (x = 0; x < dest_u_width; x++) {
          d[y * dest_u_stride + x] =
              s[x * src_u_stride + (src_u_width - 1 - y)];
        }
      }
      /* Flip V */
      s = src + src_v_offset;
      d = dest + dest_v_offset;
      for (y = 0; y < dest_v_height; y++) {
        for (x = 0; x < dest_v_width; x++) {
          d[y * dest_v_stride + x] =
              s[x * src_v_stride + (src_v_width - 1 - y)];
        }
      }
      break;
    case GST_VIDEO_FLIP_METHOD_180:
      /* Flip Y */
      s = src + src_y_offset;
      d = dest + dest_y_offset;
      for (y = 0; y < dest_y_height; y++) {
        for (x = 0; x < dest_y_width; x++) {
          d[y * dest_y_stride + x] =
              s[(src_y_height - 1 - y) * src_y_stride + (src_y_width - 1 - x)];
        }
      }
      /* Flip U */
      s = src + src_u_offset;
      d = dest + dest_u_offset;
      for (y = 0; y < dest_u_height; y++) {
        for (x = 0; x < dest_u_width; x++) {
          d[y * dest_u_stride + x] =
              s[(src_u_height - 1 - y) * src_u_stride + (src_u_width - 1 - x)];
        }
      }
      /* Flip V */
      s = src + src_v_offset;
      d = dest + dest_v_offset;
      for (y = 0; y < dest_v_height; y++) {
        for (x = 0; x < dest_v_width; x++) {
          d[y * dest_v_stride + x] =
              s[(src_v_height - 1 - y) * src_v_stride + (src_v_width - 1 - x)];
        }
      }
      break;
    case GST_VIDEO_FLIP_METHOD_HORIZ:
      /* Flip Y */
      s = src + src_y_offset;
      d = dest + dest_y_offset;
      for (y = 0; y < dest_y_height; y++) {
        for (x = 0; x < dest_y_width; x++) {
          d[y * dest_y_stride + x] =
              s[y * src_y_stride + (src_y_width - 1 - x)];
        }
      }
      /* Flip U */
      s = src + src_u_offset;
      d = dest + dest_u_offset;
      for (y = 0; y < dest_u_height; y++) {
        for (x = 0; x < dest_u_width; x++) {
          d[y * dest_u_stride + x] =
              s[y * src_u_stride + (src_u_width - 1 - x)];
        }
      }
      /* Flip V */
      s = src + src_v_offset;
      d = dest + dest_v_offset;
      for (y = 0; y < dest_v_height; y++) {
        for (x = 0; x < dest_v_width; x++) {
          d[y * dest_v_stride + x] =
              s[y * src_v_stride + (src_v_width - 1 - x)];
        }
      }
      break;
    case GST_VIDEO_FLIP_METHOD_VERT:
      /* Flip Y */
      s = src + src_y_offset;
      d = dest + dest_y_offset;
      for (y = 0; y < dest_y_height; y++) {
        for (x = 0; x < dest_y_width; x++) {
          d[y * dest_y_stride + x] =
              s[(src_y_height - 1 - y) * src_y_stride + x];
        }
      }
      /* Flip U */
      s = src + src_u_offset;
      d = dest + dest_u_offset;
      for (y = 0; y < dest_u_height; y++) {
        for (x = 0; x < dest_u_width; x++) {
          d[y * dest_u_stride + x] =
              s[(src_u_height - 1 - y) * src_u_stride + x];
        }
      }
      /* Flip V */
      s = src + src_v_offset;
      d = dest + dest_v_offset;
      for (y = 0; y < dest_v_height; y++) {
        for (x = 0; x < dest_v_width; x++) {
          d[y * dest_v_stride + x] =
              s[(src_v_height - 1 - y) * src_v_stride + x];
        }
      }
      break;
    case GST_VIDEO_FLIP_METHOD_TRANS:
      /* Flip Y */
      s = src + src_y_offset;
      d = dest + dest_y_offset;
      for (y = 0; y < dest_y_height; y++) {
        for (x = 0; x < dest_y_width; x++) {
          d[y * dest_y_stride + x] = s[x * src_y_stride + y];
        }
      }
      /* Flip U */
      s = src + src_u_offset;
      d = dest + dest_u_offset;
      for (y = 0; y < dest_u_height; y++) {
        for (x = 0; x < dest_u_width; x++) {
          d[y * dest_u_stride + x] = s[x * src_u_stride + y];
        }
      }
      /* Flip V */
      s = src + src_v_offset;
      d = dest + dest_v_offset;
      for (y = 0; y < dest_u_height; y++) {
        for (x = 0; x < dest_u_width; x++) {
          d[y * dest_v_stride + x] = s[x * src_v_stride + y];
        }
      }
      break;
    case GST_VIDEO_FLIP_METHOD_OTHER:
      /* Flip Y */
      s = src + src_y_offset;
      d = dest + dest_y_offset;
      for (y = 0; y < dest_y_height; y++) {
        for (x = 0; x < dest_y_width; x++) {
          d[y * dest_y_stride + x] =
              s[(src_y_height - 1 - x) * src_y_stride + (src_y_width - 1 - y)];
        }
      }
      /* Flip U */
      s = src + src_u_offset;
      d = dest + dest_u_offset;
      for (y = 0; y < dest_u_height; y++) {
        for (x = 0; x < dest_u_width; x++) {
          d[y * dest_u_stride + x] =
              s[(src_u_height - 1 - x) * src_u_stride + (src_u_width - 1 - y)];
        }
      }
      /* Flip V */
      s = src + src_v_offset;
      d = dest + dest_v_offset;
      for (y = 0; y < dest_v_height; y++) {
        for (x = 0; x < dest_v_width; x++) {
          d[y * dest_v_stride + x] =
              s[(src_v_height - 1 - x) * src_v_stride + (src_v_width - 1 - y)];
        }
      }
      break;
    case GST_VIDEO_FLIP_METHOD_IDENTITY:
      g_assert_not_reached ();
      break;
    default:
      g_assert_not_reached ();
      break;
  }
}
Example #20
0
gboolean AVSC_CC
_avs_vcf_add_buffer (AVS_VideoCacheFilter *p, GstPad *pad, GstBuffer *inbuf, AVS_ScriptEnvironment *env)
{
  AVS_VideoFrame *buf_ptr;
  AVS_CacheableVideoFrame *cvf;
  AVSynthSink *sink;

  gboolean ret = TRUE;

  guint8 *in_data;
  guint in_size;
  GstClockTime in_timestamp, in_duration, in_running_time;
  gint64 in_offset;
  GstVideoFormat vf;
  gint in_stride0, in_stride1, in_stride2;
  gint offset0, offset1, offset2;
  gint rowsize0, rowsize1, rowsize2;
  gint height0, height1, height2;

  in_data = GST_BUFFER_DATA (inbuf);
  in_size = GST_BUFFER_SIZE (inbuf);
  in_timestamp = GST_BUFFER_TIMESTAMP (inbuf);
  in_duration = GST_BUFFER_DURATION (inbuf);
  in_offset = GST_BUFFER_OFFSET (inbuf);

  sink = (AVSynthSink *) g_object_get_data (G_OBJECT (pad), "sinkstruct");

  GST_DEBUG ("Video cache %p: locking sinkmutex", (gpointer) p);
  g_mutex_lock (sink->sinkmutex);

  in_running_time = gst_segment_to_running_time (&sink->segment, GST_FORMAT_TIME, in_timestamp);

  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID(sink->first_ts) && GST_CLOCK_TIME_IS_VALID(in_timestamp)))
  {
    sink->first_ts = in_timestamp;
  }

  /* Offset voodoo magic */
  /* No offset on incoming frame */
  if (in_offset == -1)
  {
    /* Do we know offset of the previous frame? */
    if (sink->last_offset > -1)
    {
      in_offset = sink->last_offset + 1;
    }
    else
    {
      /* Try to convert timestamp to offset */
      if (in_timestamp >= 0 && in_running_time >= 0)
      {
        in_offset = gst_util_uint64_scale (in_running_time - sink->first_ts, p->parent.vi.fps_numerator,
            p->parent.vi.fps_denominator * GST_SECOND);
        /* Attempt to round to nearest integer: if the difference is more
         * than 0.5 (less than -0.5), it means that gst_util_uint64_scale()
         * just truncated an integer, while it had to be rounded
         */

        in_offset = in_offset * GST_SECOND - 
            in_running_time * p->parent.vi.fps_numerator / p->parent.vi.fps_denominator <= 
            -0.5 ? in_offset + 1: in_offset;
      }
      else
      {
        GST_ERROR ("Video cache %p: frame offset is unknown", (gpointer) p);
        ret = FALSE;
        goto end;
      }
    }
  }
  /* Offset sanity check */
  if (sink->last_offset > -1)
  {
    /* Non-monotonic offsets */
    if (in_offset < sink->last_offset || in_offset > sink->last_offset + 1)
    {
      GST_WARNING ("Video cache %p: last offset was %" G_GUINT64_FORMAT ", current offset is %" G_GUINT64_FORMAT " - shouldn't it be %" G_GUINT64_FORMAT "?", p, sink->last_offset, in_offset, sink->last_offset + 1);
      in_offset = sink->last_offset + 1;
    }
    else if (in_offset == sink->last_offset)
    {
      GST_WARNING ("Video cache %p: duplicate offsets %" G_GUINT64_FORMAT ", dropping", (gpointer) p, in_offset);
      goto end;
    }
  }

  sink->last_offset = in_offset;

  if (p->size >= p->used_size && !sink->flush)
  {
    GST_DEBUG ("Video cache %p: blocking at frame %" G_GUINT64_FORMAT, (gpointer) p, in_offset);
    while (p->size >= p->used_size && !sink->flush && !sink->seeking)
    {
      GST_DEBUG ("Video cache %p: sleeping while waiting at frame %" G_GUINT64_FORMAT
        ", cache range%" G_GUINT64_FORMAT "+ %" G_GUINT64_FORMAT
        ", size=%" G_GUINT64_FORMAT" , stream lock = %p", (gpointer) p, in_offset, p->rng_from, p->used_size,
        p->size, GST_PAD_GET_STREAM_LOCK (pad));
      g_cond_wait (p->vcache_block_cond, sink->sinkmutex);
      GST_DEBUG ("Video cache %p: woke up while waiting at frame %" G_GUINT64_FORMAT
        ", cache range%" G_GUINT64_FORMAT "+ %" G_GUINT64_FORMAT
        ", size=%" G_GUINT64_FORMAT" , stream lock = %p", (gpointer) p, in_offset, p->rng_from, p->used_size,
        p->size, GST_PAD_GET_STREAM_LOCK (pad));
    }
  }

  /* We've been seeking backwards and the seek wasn't very precise, so
   * we're getting frames previous to the frame we need.
   * Or we're in seek mode and the frame is not the frame we're seeking to.
   * If we've pushed a seek event and it moved the source to a frame after
   * rng_from (i.e. the seek missed), this will turn into infinite loop.
   */
  if (G_UNLIKELY (sink->flush || in_offset < p->rng_from && !sink->seeking || sink->seeking && in_offset != p->rng_from))
  {
    if (sink->flush)
      GST_DEBUG ("Video cache %p: skipping frame %" G_GUINT64_FORMAT " - flushing", (gpointer) p, in_offset);
    else if (in_offset < p->rng_from && !sink->seeking)
      GST_DEBUG ("Video cache %p: skipping frame %" G_GUINT64_FORMAT " < %" G_GUINT64_FORMAT, (gpointer) p, in_offset, p->rng_from);
    else if (sink->seeking && in_offset != p->rng_from)
      GST_DEBUG ("Video cache %p: skipping frame %" G_GUINT64_FORMAT " - seeking to %" G_GUINT64_FORMAT, (gpointer) p, in_offset, p->rng_from);   
    goto end;
  }
  sink->seeking = FALSE;

  gst_avsynth_buf_pad_caps_to_vi (inbuf, pad, GST_BUFFER_CAPS (inbuf), &p->parent.vi);

  gst_video_format_parse_caps (GST_BUFFER_CAPS (inbuf), &vf, NULL, NULL);

  /* Allocate a new frame, with default alignment */
  buf_ptr = _avs_se_vf_new_a (env, &p->vi, AVS_FRAME_ALIGN);

  offset0 = gst_video_format_get_component_offset (vf, 0, p->parent.vi.width, p->parent.vi.height);
  offset1 = gst_video_format_get_component_offset (vf, 1, p->parent.vi.width, p->parent.vi.height);
  offset2 = gst_video_format_get_component_offset (vf, 2, p->parent.vi.width, p->parent.vi.height);

  /* The Spherical Horse in Vacuum: row stride is not guaranteed to match the
   * value returned by this function.
   */
  in_stride0 = gst_video_format_get_row_stride (vf, 0, p->parent.vi.width);
  in_stride1 = gst_video_format_get_row_stride (vf, 1, p->parent.vi.width);
  in_stride2 = gst_video_format_get_row_stride (vf, 2, p->parent.vi.width);

  rowsize0 = gst_video_format_get_component_width (vf, 0, p->parent.vi.width) * gst_video_format_get_pixel_stride (vf, 0);
  rowsize1 = gst_video_format_get_component_width (vf, 1, p->parent.vi.width) * gst_video_format_get_pixel_stride (vf, 1);
  rowsize2 = gst_video_format_get_component_width (vf, 2, p->parent.vi.width) * gst_video_format_get_pixel_stride (vf, 2);

  height0 = gst_video_format_get_component_height (vf, 0, p->parent.vi.height);
  height1 = gst_video_format_get_component_height (vf, 1, p->parent.vi.height);
  height2 = gst_video_format_get_component_height (vf, 2, p->parent.vi.height);

  if (!AVS_IS_PLANAR (&p->parent.vi))
  {
    offset2 = offset1 = offset0;
    in_stride2 = in_stride1 = 0;
    rowsize2 = rowsize1 = 0;
    height2 = height1 = 0;
  }

  _avs_se_bit_blt (env, _avs_vf_get_write_ptr (buf_ptr), _avs_vf_get_pitch (buf_ptr), in_data + offset0, in_stride0, rowsize0, height0);
  // Blit More planes (pitch, rowsize and height should be 0, if none is present)
  _avs_se_bit_blt (env, _avs_vf_get_write_ptr_p (buf_ptr, PLANAR_U), _avs_vf_get_pitch_p (buf_ptr, PLANAR_U), in_data + offset1, in_stride1, rowsize1, height1);
  _avs_se_bit_blt (env, _avs_vf_get_write_ptr_p (buf_ptr, PLANAR_V), _avs_vf_get_pitch_p (buf_ptr, PLANAR_V), in_data + offset2, in_stride2, rowsize2, height2);

  cvf = g_new0 (AVS_CacheableVideoFrame, 1);
  cvf->vf = buf_ptr;
  cvf->touched = FALSE;
  cvf->selfindex = in_offset;
  cvf->countindex = p->framecounter++;
  _avs_vf_set_timestamp (buf_ptr, in_timestamp);
  _avs_vf_set_parity (buf_ptr, p->parent.vi.image_type);

  /* Buffer is full, meaning that a filter is not processing frames
   * fast enough.
   */
  if (G_UNLIKELY (p->used_size <= p->size))
  {
    if (p->size > p->used_size)
      g_critical ("Video cache %p: buffer overflow - %" G_GUINT64_FORMAT " > %" G_GUINT64_FORMAT, (gpointer) p, p->used_size, p->size);
    GST_DEBUG ("Video cache %p: cache is full", (gpointer) p);
    /* Cache is relatively small, we can expand it */
    if (G_UNLIKELY (p->touched_last_time * 3 > p->used_size))
    {
      GST_DEBUG ("Video cache %p: cache is relatively small (%" G_GUINT64_FORMAT " > %" G_GUINT64_FORMAT "), expanding...", (gpointer) p, p->touched_last_time * 3, p->used_size);
      _avs_vcf_resize (p, p->used_size + 1);
    }
    else
      g_critical ("Video cache %p: cache is overflowing!", (gpointer) p);
  }

  /* It is guaranteed that at this moment we have at least one free unused
   * array element left. At least it should be guaranteed...
   */
  GST_DEBUG ("Video cache %p: cache size = %" G_GUINT64_FORMAT ", adding a buffer %p (%p), offset = %" G_GUINT64_FORMAT, (gpointer) p, p->size, cvf, buf_ptr, in_offset);
  g_ptr_array_index (p->bufs, p->size++) = (gpointer) cvf;

  /* We don't really know the number of frame the other thread is waiting for
   * (or even if it waits at all), so we'll send a signal each time we add
   * a buffer.
   * People told me that calling g_cond_signal once for each frame (60 times
   * a second, unless you're transcoding a video) doesn't make a difference.
   * And transcoding itself is MUCH slower.
   */
  GST_DEBUG ("Video cache %p: signaling newframe", (gpointer) p);
  g_cond_signal (p->vcache_cond);

end:
  g_mutex_unlock (sink->sinkmutex);
 
  GST_DEBUG ("Video cache %p: unlocked sinkmutex", (gpointer) p);

  return ret;
}
Example #21
0
/**
 * gst_video_format_new_caps:
 * @format: the #GstVideoFormat describing the raw video format
 * @width: width of video
 * @height: height of video
 * @framerate_n: numerator of frame rate
 * @framerate_d: denominator of frame rate
 * @par_n: numerator of pixel aspect ratio
 * @par_d: denominator of pixel aspect ratio
 *
 * Creates a new #GstCaps object based on the parameters provided.
 *
 * Since: 0.10.16
 *
 * Returns: a new #GstCaps object, or NULL if there was an error
 */
GstCaps *
gst_video_format_new_caps (GstVideoFormat format, int width, int height,
    int framerate_n, int framerate_d, int par_n, int par_d)
{
  g_return_val_if_fail (format != GST_VIDEO_FORMAT_UNKNOWN, NULL);
  g_return_val_if_fail (width > 0 && height > 0, NULL);

  if (gst_video_format_is_yuv (format)) {
    return gst_caps_new_simple ("video/x-raw-yuv",
        "format", GST_TYPE_FOURCC, gst_video_format_to_fourcc (format),
        "width", G_TYPE_INT, width,
        "height", G_TYPE_INT, height,
        "framerate", GST_TYPE_FRACTION, framerate_n, framerate_d,
        "pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d, NULL);
  }
  if (gst_video_format_is_rgb (format)) {
    GstCaps *caps;
    int red_mask;
    int blue_mask;
    int green_mask;
    int alpha_mask;
    int depth;
    int bpp;
    gboolean have_alpha;
    unsigned int mask;

    switch (format) {
      case GST_VIDEO_FORMAT_RGBx:
      case GST_VIDEO_FORMAT_BGRx:
      case GST_VIDEO_FORMAT_xRGB:
      case GST_VIDEO_FORMAT_xBGR:
        bpp = 32;
        depth = 24;
        have_alpha = FALSE;
        break;
      case GST_VIDEO_FORMAT_RGBA:
      case GST_VIDEO_FORMAT_BGRA:
      case GST_VIDEO_FORMAT_ARGB:
      case GST_VIDEO_FORMAT_ABGR:
        bpp = 32;
        depth = 32;
        have_alpha = TRUE;
        break;
      case GST_VIDEO_FORMAT_RGB:
      case GST_VIDEO_FORMAT_BGR:
        bpp = 24;
        depth = 24;
        have_alpha = FALSE;
        break;
      default:
        return NULL;
    }
    if (bpp == 32) {
      mask = 0xff000000;
    } else {
      mask = 0xff0000;
    }
    red_mask =
        mask >> (8 * gst_video_format_get_component_offset (format, 0, width,
            height));
    green_mask =
        mask >> (8 * gst_video_format_get_component_offset (format, 1, width,
            height));
    blue_mask =
        mask >> (8 * gst_video_format_get_component_offset (format, 2, width,
            height));

    caps = gst_caps_new_simple ("video/x-raw-rgb",
        "bpp", G_TYPE_INT, bpp,
        "depth", G_TYPE_INT, depth,
        "endianness", G_TYPE_INT, G_BIG_ENDIAN,
        "red_mask", G_TYPE_INT, red_mask,
        "green_mask", G_TYPE_INT, green_mask,
        "blue_mask", G_TYPE_INT, blue_mask,
        "width", G_TYPE_INT, width,
        "height", G_TYPE_INT, height,
        "framerate", GST_TYPE_FRACTION, framerate_n, framerate_d,
        "pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d, NULL);
    if (have_alpha) {
      alpha_mask =
          mask >> (8 * gst_video_format_get_component_offset (format, 3, width,
              height));
      gst_caps_set_simple (caps, "alpha_mask", G_TYPE_INT, alpha_mask, NULL);
    }
    return caps;
  }
  return NULL;
}
Example #22
0
static GstFlowReturn
gst_jasper_dec_negotiate (GstJasperDec * dec, jas_image_t * image)
{
  GstFlowReturn flow_ret = GST_FLOW_OK;
  gint width, height, channels;
  gint i, j;
  gboolean negotiate = FALSE;
  jas_clrspc_t clrspc;
  GstCaps *allowed_caps, *caps;

  width = jas_image_width (image);
  height = jas_image_height (image);
  channels = jas_image_numcmpts (image);

  GST_LOG_OBJECT (dec, "%d x %d, %d components", width, height, channels);

  /* jp2c bitstream has no real colour space info (kept in container),
   * so decoder may only pretend to know, where it really does not */
  if (!jas_clrspc_isunknown (dec->clrspc)) {
    clrspc = dec->clrspc;
    GST_DEBUG_OBJECT (dec, "forcing container supplied colour space %d",
        clrspc);
    jas_image_setclrspc (image, clrspc);
  } else
    clrspc = jas_image_clrspc (image);

  if (!width || !height || !channels || jas_clrspc_isunknown (clrspc))
    goto fail_image;

  if (dec->width != width || dec->height != height ||
      dec->channels != channels || dec->clrspc != clrspc)
    negotiate = TRUE;

  if (channels != 3)
    goto not_supported;

  for (i = 0; i < channels; i++) {
    gint cheight, cwidth, depth, sgnd;

    cheight = jas_image_cmptheight (image, i);
    cwidth = jas_image_cmptwidth (image, i);
    depth = jas_image_cmptprec (image, i);
    sgnd = jas_image_cmptsgnd (image, i);

    GST_LOG_OBJECT (dec, "image component %d, %dx%d, depth %d, sgnd %d", i,
        cwidth, cheight, depth, sgnd);

    if (depth != 8 || sgnd)
      goto not_supported;

    if (dec->cheight[i] != cheight || dec->cwidth[i] != cwidth) {
      dec->cheight[i] = cheight;
      dec->cwidth[i] = cwidth;
      negotiate = TRUE;
    }
  }

  if (!negotiate && dec->format != GST_VIDEO_FORMAT_UNKNOWN)
    goto done;

  /* clear and refresh to new state */
  flow_ret = GST_FLOW_NOT_NEGOTIATED;
  dec->format = GST_VIDEO_FORMAT_UNKNOWN;
  dec->width = width;
  dec->height = height;
  dec->channels = channels;

  /* retrieve allowed caps, and find the first one that reasonably maps
   * to the parameters of the colourspace */
  caps = gst_pad_get_allowed_caps (dec->srcpad);
  if (!caps) {
    GST_DEBUG_OBJECT (dec, "... but no peer, using template caps");
    /* need to copy because get_allowed_caps returns a ref,
       and get_pad_template_caps doesn't */
    caps = gst_caps_copy (gst_pad_get_pad_template_caps (dec->srcpad));
  }
  /* avoid lists of fourcc, etc */
  allowed_caps = gst_caps_normalize (caps);
  caps = NULL;
  GST_LOG_OBJECT (dec, "allowed source caps %" GST_PTR_FORMAT, allowed_caps);

  for (i = 0; i < gst_caps_get_size (allowed_caps); i++) {
    GstVideoFormat format;
    gboolean ok;

    if (caps)
      gst_caps_unref (caps);
    caps = gst_caps_copy_nth (allowed_caps, i);
    /* sigh, ds and _parse_caps need fixed caps for parsing, fixate */
    gst_pad_fixate_caps (dec->srcpad, caps);
    GST_LOG_OBJECT (dec, "checking caps %" GST_PTR_FORMAT, caps);
    if (!gst_video_format_parse_caps (caps, &format, NULL, NULL))
      continue;
    if (gst_video_format_is_rgb (format) &&
        jas_clrspc_fam (clrspc) == JAS_CLRSPC_FAM_RGB) {
      GST_DEBUG_OBJECT (dec, "trying RGB");
      if ((dec->cmpt[0] = jas_image_getcmptbytype (image,
                  JAS_IMAGE_CT_COLOR (JAS_CLRSPC_CHANIND_RGB_R))) < 0 ||
          (dec->cmpt[1] = jas_image_getcmptbytype (image,
                  JAS_IMAGE_CT_COLOR (JAS_CLRSPC_CHANIND_RGB_G))) < 0 ||
          (dec->cmpt[2] = jas_image_getcmptbytype (image,
                  JAS_IMAGE_CT_COLOR (JAS_CLRSPC_CHANIND_RGB_B))) < 0) {
        GST_DEBUG_OBJECT (dec, "missing RGB color component");
        continue;
      }
    } else if (gst_video_format_is_yuv (format) &&
        jas_clrspc_fam (clrspc) == JAS_CLRSPC_FAM_YCBCR) {
      GST_DEBUG_OBJECT (dec, "trying YUV");
      if ((dec->cmpt[0] = jas_image_getcmptbytype (image,
                  JAS_IMAGE_CT_COLOR (JAS_CLRSPC_CHANIND_YCBCR_Y))) < 0 ||
          (dec->cmpt[1] = jas_image_getcmptbytype (image,
                  JAS_IMAGE_CT_COLOR (JAS_CLRSPC_CHANIND_YCBCR_CB))) < 0 ||
          (dec->cmpt[2] = jas_image_getcmptbytype (image,
                  JAS_IMAGE_CT_COLOR (JAS_CLRSPC_CHANIND_YCBCR_CR))) < 0) {
        GST_DEBUG_OBJECT (dec, "missing YUV color component");
        continue;
      }
    } else
      continue;
    /* match format with validity checks */
    ok = TRUE;
    for (j = 0; j < channels; j++) {
      gint cmpt;

      cmpt = dec->cmpt[j];
      if (dec->cwidth[cmpt] != gst_video_format_get_component_width (format, j,
              width) ||
          dec->cheight[cmpt] != gst_video_format_get_component_height (format,
              j, height))
        ok = FALSE;
    }
    /* commit to this format */
    if (ok) {
      dec->format = format;
      break;
    }
  }

  if (caps)
    gst_caps_unref (caps);
  gst_caps_unref (allowed_caps);

  if (dec->format != GST_VIDEO_FORMAT_UNKNOWN) {
    /* cache some video format properties */
    for (j = 0; j < channels; ++j) {
      dec->offset[j] = gst_video_format_get_component_offset (dec->format, j,
          dec->width, dec->height);
      dec->inc[j] = gst_video_format_get_pixel_stride (dec->format, j);
      dec->stride[j] = gst_video_format_get_row_stride (dec->format, j,
          dec->width);
    }
    dec->image_size = gst_video_format_get_size (dec->format, width, height);
    dec->alpha = gst_video_format_has_alpha (dec->format);

    if (dec->buf)
      g_free (dec->buf);
    dec->buf = g_new0 (glong, dec->width);

    caps = gst_video_format_new_caps (dec->format, dec->width, dec->height,
        dec->framerate_numerator, dec->framerate_denominator, 1, 1);

    GST_DEBUG_OBJECT (dec, "Set format to %d, size to %dx%d", dec->format,
        dec->width, dec->height);

    if (!gst_pad_set_caps (dec->srcpad, caps))
      flow_ret = GST_FLOW_NOT_NEGOTIATED;
    else
      flow_ret = GST_FLOW_OK;

    gst_caps_unref (caps);
  }

done:
  return flow_ret;

  /* ERRORS */
fail_image:
  {
    GST_DEBUG_OBJECT (dec, "Failed to process decoded image.");
    flow_ret = GST_FLOW_NOT_NEGOTIATED;
    goto done;
  }
not_supported:
  {
    GST_DEBUG_OBJECT (dec, "Decoded image has unsupported colour space.");
    GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("Unsupported colorspace"));
    flow_ret = GST_FLOW_ERROR;
    goto done;
  }
}
Example #23
0
static gdouble
gst_compare_ssim (GstCompare * comp, GstBuffer * buf1, GstBuffer * buf2)
{
  GstCaps *caps;
  GstVideoFormat format, f;
  gint width, height, w, h, i, comps;
  gdouble cssim[4], ssim, c[4] = { 1.0, 0.0, 0.0, 0.0 };
  guint8 *data1, *data2;

  caps = GST_BUFFER_CAPS (buf1);
  if (!caps)
    goto invalid_input;

  if (!gst_video_format_parse_caps (caps, &format, &width, &height))
    goto invalid_input;

  caps = GST_BUFFER_CAPS (buf2);
  if (!caps)
    goto invalid_input;

  if (!gst_video_format_parse_caps (caps, &f, &w, &h))
    goto invalid_input;

  if (f != format || w != width || h != height)
    return comp->threshold + 1;

  comps = gst_video_format_is_gray (format) ? 1 : 3;
  if (gst_video_format_has_alpha (format))
    comps += 1;

  /* note that some are reported both yuv and gray */
  for (i = 0; i < comps; ++i)
    c[i] = 1.0;
  /* increase luma weight if yuv */
  if (gst_video_format_is_yuv (format) && (comps > 1))
    c[0] = comps - 1;
  for (i = 0; i < comps; ++i)
    c[i] /= (gst_video_format_is_yuv (format) && (comps > 1)) ?
        2 * (comps - 1) : comps;

  data1 = GST_BUFFER_DATA (buf1);
  data2 = GST_BUFFER_DATA (buf2);
  for (i = 0; i < comps; i++) {
    gint offset, cw, ch, step, stride;

    /* only support most common formats */
    if (gst_video_format_get_component_depth (format, i) != 8)
      goto unsupported_input;
    offset = gst_video_format_get_component_offset (format, i, width, height);
    cw = gst_video_format_get_component_width (format, i, width);
    ch = gst_video_format_get_component_height (format, i, height);
    step = gst_video_format_get_pixel_stride (format, i);
    stride = gst_video_format_get_row_stride (format, i, width);

    GST_LOG_OBJECT (comp, "component %d", i);
    cssim[i] = gst_compare_ssim_component (comp, data1 + offset, data2 + offset,
        cw, ch, step, stride);
    GST_LOG_OBJECT (comp, "ssim[%d] = %f", i, cssim[i]);
  }

#ifndef GST_DISABLE_GST_DEBUG
  for (i = 0; i < 4; i++) {
    GST_DEBUG_OBJECT (comp, "ssim[%d] = %f, c[%d] = %f", i, cssim[i], i, c[i]);
  }
#endif

  ssim = cssim[0] * c[0] + cssim[1] * c[1] + cssim[2] * c[2] + cssim[3] * c[3];

  return ssim;

  /* ERRORS */
invalid_input:
  {
    GST_ERROR_OBJECT (comp, "ssim method needs raw video input");
    return 0;
  }
unsupported_input:
  {
    GST_ERROR_OBJECT (comp, "raw video format not supported %" GST_PTR_FORMAT,
        caps);
    return 0;
  }
}
static void
gst_deinterlace_method_setup_impl (GstDeinterlaceMethod * self,
    GstVideoFormat format, gint width, gint height)
{
  gint i;
  GstDeinterlaceMethodClass *klass = GST_DEINTERLACE_METHOD_GET_CLASS (self);

  self->format = format;
  self->frame_width = width;
  self->frame_height = height;

  self->deinterlace_frame = NULL;

  if (format == GST_VIDEO_FORMAT_UNKNOWN)
    return;

  for (i = 0; i < 4; i++) {
    self->width[i] = gst_video_format_get_component_width (format, i, width);
    self->height[i] = gst_video_format_get_component_height (format, i, height);
    self->offset[i] =
        gst_video_format_get_component_offset (format, i, width, height);
    self->row_stride[i] = gst_video_format_get_row_stride (format, i, width);
    self->pixel_stride[i] = gst_video_format_get_pixel_stride (format, i);
  }

  switch (format) {
    case GST_VIDEO_FORMAT_YUY2:
      self->deinterlace_frame = klass->deinterlace_frame_yuy2;
      break;
    case GST_VIDEO_FORMAT_YVYU:
      self->deinterlace_frame = klass->deinterlace_frame_yvyu;
      break;
    case GST_VIDEO_FORMAT_UYVY:
      self->deinterlace_frame = klass->deinterlace_frame_uyvy;
      break;
    case GST_VIDEO_FORMAT_I420:
      self->deinterlace_frame = klass->deinterlace_frame_i420;
      break;
    case GST_VIDEO_FORMAT_YV12:
      self->deinterlace_frame = klass->deinterlace_frame_yv12;
      break;
    case GST_VIDEO_FORMAT_Y444:
      self->deinterlace_frame = klass->deinterlace_frame_y444;
      break;
    case GST_VIDEO_FORMAT_Y42B:
      self->deinterlace_frame = klass->deinterlace_frame_y42b;
      break;
    case GST_VIDEO_FORMAT_Y41B:
      self->deinterlace_frame = klass->deinterlace_frame_y41b;
      break;
    case GST_VIDEO_FORMAT_AYUV:
      self->deinterlace_frame = klass->deinterlace_frame_ayuv;
      break;
    case GST_VIDEO_FORMAT_ARGB:
    case GST_VIDEO_FORMAT_xRGB:
      self->deinterlace_frame = klass->deinterlace_frame_argb;
      break;
    case GST_VIDEO_FORMAT_ABGR:
    case GST_VIDEO_FORMAT_xBGR:
      self->deinterlace_frame = klass->deinterlace_frame_abgr;
      break;
    case GST_VIDEO_FORMAT_RGBA:
    case GST_VIDEO_FORMAT_RGBx:
      self->deinterlace_frame = klass->deinterlace_frame_rgba;
      break;
    case GST_VIDEO_FORMAT_BGRA:
    case GST_VIDEO_FORMAT_BGRx:
      self->deinterlace_frame = klass->deinterlace_frame_bgra;
      break;
    case GST_VIDEO_FORMAT_RGB:
      self->deinterlace_frame = klass->deinterlace_frame_rgb;
      break;
    case GST_VIDEO_FORMAT_BGR:
      self->deinterlace_frame = klass->deinterlace_frame_bgr;
      break;
    default:
      self->deinterlace_frame = NULL;
      break;
  }
}
Example #25
0
static GstFlowReturn
gst_video_mark_yuv (GstVideoMark * videomark, GstBuffer * buffer)
{
  GstVideoFormat format;
  gint i, pw, ph, row_stride, pixel_stride, offset;
  gint width, height, req_width, req_height;
  guint8 *d, *data;
  guint64 pattern_shift;
  guint8 color;

  data = GST_BUFFER_DATA (buffer);

  format = videomark->format;
  width = videomark->width;
  height = videomark->height;

  pw = videomark->pattern_width;
  ph = videomark->pattern_height;
  row_stride = gst_video_format_get_row_stride (format, 0, width);
  pixel_stride = gst_video_format_get_pixel_stride (format, 0);
  offset = gst_video_format_get_component_offset (format, 0, width, height);

  req_width =
      (videomark->pattern_count + videomark->pattern_data_count) * pw +
      videomark->left_offset;
  req_height = videomark->bottom_offset + ph;
  if (req_width > width || req_height > height) {
    GST_ELEMENT_ERROR (videomark, STREAM, WRONG_TYPE, (NULL),
        ("videomark pattern doesn't fit video, need at least %ix%i (stream has %ix%i)",
            req_width, req_height, width, height));
    return GST_FLOW_ERROR;
  }

  /* draw the bottom left pixels */
  for (i = 0; i < videomark->pattern_count; i++) {
    d = data + offset;
    /* move to start of bottom left */
    d += row_stride * (height - ph - videomark->bottom_offset) +
        pixel_stride * videomark->left_offset;
    /* move to i-th pattern */
    d += pixel_stride * pw * i;

    if (i & 1)
      /* odd pixels must be white */
      color = 255;
    else
      color = 0;

    /* draw box of width * height */
    gst_video_mark_draw_box (videomark, d, pw, ph, row_stride, pixel_stride,
        color);
  }

  pattern_shift = G_GUINT64_CONSTANT (1) << (videomark->pattern_data_count - 1);

  /* get the data of the pattern */
  for (i = 0; i < videomark->pattern_data_count; i++) {
    d = data + offset;
    /* move to start of bottom left, adjust for offsets */
    d += row_stride * (height - ph - videomark->bottom_offset) +
        pixel_stride * videomark->left_offset;
    /* move after the fixed pattern */
    d += pixel_stride * videomark->pattern_count * pw;
    /* move to i-th pattern data */
    d += pixel_stride * pw * i;

    if (videomark->pattern_data & pattern_shift)
      color = 255;
    else
      color = 0;

    gst_video_mark_draw_box (videomark, d, pw, ph, row_stride, pixel_stride,
        color);

    pattern_shift >>= 1;
  }

  return GST_FLOW_OK;
}
Example #26
0
static gboolean
gst_jasper_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
{
    GstJasperEnc *enc;
    GstVideoFormat format;
    gint width, height;
    gint fps_num, fps_den;
    gint par_num, par_den;
    gint i;

    enc = GST_JASPER_ENC (GST_PAD_PARENT (pad));

    /* get info from caps */
    if (!gst_video_format_parse_caps (caps, &format, &width, &height))
        goto refuse_caps;
    /* optional; pass along if present */
    fps_num = fps_den = -1;
    par_num = par_den = -1;
    gst_video_parse_caps_framerate (caps, &fps_num, &fps_den);
    gst_video_parse_caps_pixel_aspect_ratio (caps, &par_num, &par_den);

    if (width == enc->width && height == enc->height && enc->format == format
            && fps_num == enc->fps_num && fps_den == enc->fps_den
            && par_num == enc->par_num && par_den == enc->par_den)
        return TRUE;

    /* store input description */
    enc->format = format;
    enc->width = width;
    enc->height = height;
    enc->fps_num = fps_num;
    enc->fps_den = fps_den;
    enc->par_num = par_num;
    enc->par_den = par_den;

    /* prepare a cached image description  */
    enc->channels = 3 + (gst_video_format_has_alpha (format) ? 1 : 0);
    for (i = 0; i < enc->channels; ++i) {
        enc->cwidth[i] = gst_video_format_get_component_width (format, i, width);
        enc->cheight[i] = gst_video_format_get_component_height (format, i, height);
        enc->offset[i] = gst_video_format_get_component_offset (format, i, width,
                         height);
        enc->stride[i] = gst_video_format_get_row_stride (format, i, width);
        enc->inc[i] = gst_video_format_get_pixel_stride (format, i);
    }

    if (!gst_jasper_enc_set_src_caps (enc))
        goto setcaps_failed;
    if (!gst_jasper_enc_init_encoder (enc))
        goto setup_failed;

    return TRUE;

    /* ERRORS */
setup_failed:
    {
        GST_ELEMENT_ERROR (enc, LIBRARY, SETTINGS, (NULL), (NULL));
        return FALSE;
    }
setcaps_failed:
    {
        GST_WARNING_OBJECT (enc, "Setting src caps failed");
        GST_ELEMENT_ERROR (enc, LIBRARY, SETTINGS, (NULL), (NULL));
        return FALSE;
    }
refuse_caps:
    {
        GST_WARNING_OBJECT (enc, "refused caps %" GST_PTR_FORMAT, caps);
        gst_object_unref (enc);
        return FALSE;
    }
}
Example #27
0
static void
gst_video_flip_y422 (GstVideoFlip * videoflip, guint8 * dest,
    const guint8 * src)
{
  gint x, y;
  guint8 const *s = src;
  guint8 *d = dest;
  GstVideoFormat format = videoflip->format;
  gint sw = videoflip->from_width;
  gint sh = videoflip->from_height;
  gint dw = videoflip->to_width;
  gint dh = videoflip->to_height;
  gint src_stride, dest_stride;
  gint bpp;
  gint y_offset;
  gint u_offset;
  gint v_offset;
  gint y_stride;

  src_stride = gst_video_format_get_row_stride (format, 0, sw);
  dest_stride = gst_video_format_get_row_stride (format, 0, dw);

  y_offset = gst_video_format_get_component_offset (format, 0, sw, sh);
  u_offset = gst_video_format_get_component_offset (format, 1, sw, sh);
  v_offset = gst_video_format_get_component_offset (format, 2, sw, sh);
  y_stride = gst_video_format_get_pixel_stride (format, 0);
  bpp = y_stride;

  switch (videoflip->method) {
    case GST_VIDEO_FLIP_METHOD_90R:
      for (y = 0; y < dh; y++) {
        for (x = 0; x < dw; x += 2) {
          guint8 u;
          guint8 v;
          /* u/v must be calculated using the offset of the even column */
          gint even_y = (y & ~1);

          u = s[(sh - 1 - x) * src_stride + even_y * bpp + u_offset];
          if (x + 1 < dw)
            u = (s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + u_offset]
                + u) >> 1;
          v = s[(sh - 1 - x) * src_stride + even_y * bpp + v_offset];
          if (x + 1 < dw)
            v = (s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + v_offset]
                + v) >> 1;

          d[y * dest_stride + x * bpp + u_offset] = u;
          d[y * dest_stride + x * bpp + v_offset] = v;
          d[y * dest_stride + x * bpp + y_offset] =
              s[(sh - 1 - x) * src_stride + y * bpp + y_offset];
          if (x + 1 < dw)
            d[y * dest_stride + (x + 1) * bpp + y_offset] =
                s[(sh - 1 - (x + 1)) * src_stride + y * bpp + y_offset];
        }
      }
      break;
    case GST_VIDEO_FLIP_METHOD_90L:
      for (y = 0; y < dh; y++) {
        for (x = 0; x < dw; x += 2) {
          guint8 u;
          guint8 v;
          /* u/v must be calculated using the offset of the even column */
          gint even_y = ((sw - 1 - y) & ~1);

          u = s[x * src_stride + even_y * bpp + u_offset];
          if (x + 1 < dw)
            u = (s[(x + 1) * src_stride + even_y * bpp + u_offset] + u) >> 1;
          v = s[x * src_stride + even_y * bpp + v_offset];
          if (x + 1 < dw)
            v = (s[(x + 1) * src_stride + even_y * bpp + v_offset] + v) >> 1;

          d[y * dest_stride + x * bpp + u_offset] = u;
          d[y * dest_stride + x * bpp + v_offset] = v;
          d[y * dest_stride + x * bpp + y_offset] =
              s[x * src_stride + (sw - 1 - y) * bpp + y_offset];
          if (x + 1 < dw)
            d[y * dest_stride + (x + 1) * bpp + y_offset] =
                s[(x + 1) * src_stride + (sw - 1 - y) * bpp + y_offset];
        }
      }
      break;
    case GST_VIDEO_FLIP_METHOD_180:
      for (y = 0; y < dh; y++) {
        for (x = 0; x < dw; x += 2) {
          guint8 u;
          guint8 v;
          /* u/v must be calculated using the offset of the even column */
          gint even_x = ((sw - 1 - x) & ~1);

          u = (s[(sh - 1 - y) * src_stride + even_x * bpp + u_offset] +
              s[(sh - 1 - y) * src_stride + even_x * bpp + u_offset]) / 2;
          v = (s[(sh - 1 - y) * src_stride + even_x * bpp + v_offset] +
              s[(sh - 1 - y) * src_stride + even_x * bpp + v_offset]) / 2;

          d[y * dest_stride + x * bpp + u_offset] = u;
          d[y * dest_stride + x * bpp + v_offset] = v;
          d[y * dest_stride + x * bpp + y_offset] =
              s[(sh - 1 - y) * src_stride + (sw - 1 - x) * bpp + y_offset];
          if (x + 1 < dw)
            d[y * dest_stride + (x + 1) * bpp + y_offset] =
                s[(sh - 1 - y) * src_stride + (sw - 1 - (x + 1)) * bpp +
                y_offset];
        }
      }
      break;
    case GST_VIDEO_FLIP_METHOD_HORIZ:
      for (y = 0; y < dh; y++) {
        for (x = 0; x < dw; x += 2) {
          guint8 u;
          guint8 v;
          /* u/v must be calculated using the offset of the even column */
          gint even_x = ((sw - 1 - x) & ~1);

          u = (s[y * src_stride + even_x * bpp + u_offset] +
              s[y * src_stride + even_x * bpp + u_offset]) / 2;
          v = (s[y * src_stride + even_x * bpp + v_offset] +
              s[y * src_stride + even_x * bpp + v_offset]) / 2;

          d[y * dest_stride + x * bpp + u_offset] = u;
          d[y * dest_stride + x * bpp + v_offset] = v;
          d[y * dest_stride + x * bpp + y_offset] =
              s[y * src_stride + (sw - 1 - x) * bpp + y_offset];
          if (x + 1 < dw)
            d[y * dest_stride + (x + 1) * bpp + y_offset] =
                s[y * src_stride + (sw - 1 - (x + 1)) * bpp + y_offset];
        }
      }
      break;
    case GST_VIDEO_FLIP_METHOD_VERT:
      for (y = 0; y < dh; y++) {
        for (x = 0; x < dw; x += 2) {
          guint8 u;
          guint8 v;
          /* u/v must be calculated using the offset of the even column */
          gint even_x = (x & ~1);

          u = (s[(sh - 1 - y) * src_stride + even_x * bpp + u_offset] +
              s[(sh - 1 - y) * src_stride + even_x * bpp + u_offset]) / 2;
          v = (s[(sh - 1 - y) * src_stride + even_x * bpp + v_offset] +
              s[(sh - 1 - y) * src_stride + even_x * bpp + v_offset]) / 2;

          d[y * dest_stride + x * bpp + u_offset] = u;
          d[y * dest_stride + x * bpp + v_offset] = v;
          d[y * dest_stride + x * bpp + y_offset] =
              s[(sh - 1 - y) * src_stride + x * bpp + y_offset];
          if (x + 1 < dw)
            d[y * dest_stride + (x + 1) * bpp + y_offset] =
                s[(sh - 1 - y) * src_stride + (x + 1) * bpp + y_offset];
        }
      }
      break;
    case GST_VIDEO_FLIP_METHOD_TRANS:
      for (y = 0; y < dh; y++) {
        for (x = 0; x < dw; x += 2) {
          guint8 u;
          guint8 v;
          /* u/v must be calculated using the offset of the even column */
          gint even_y = (y & ~1);

          u = s[x * src_stride + even_y * bpp + u_offset];
          if (x + 1 < dw)
            u = (s[(x + 1) * src_stride + even_y * bpp + u_offset] + u) >> 1;
          v = s[x * src_stride + even_y * bpp + v_offset];
          if (x + 1 < dw)
            v = (s[(x + 1) * src_stride + even_y * bpp + v_offset] + v) >> 1;

          d[y * dest_stride + x * bpp + u_offset] = u;
          d[y * dest_stride + x * bpp + v_offset] = v;
          d[y * dest_stride + x * bpp + y_offset] =
              s[x * src_stride + y * bpp + y_offset];
          if (x + 1 < dw)
            d[y * dest_stride + (x + 1) * bpp + y_offset] =
                s[(x + 1) * src_stride + y * bpp + y_offset];
        }
      }
      break;
    case GST_VIDEO_FLIP_METHOD_OTHER:
      for (y = 0; y < dh; y++) {
        for (x = 0; x < dw; x += 2) {
          guint8 u;
          guint8 v;
          /* u/v must be calculated using the offset of the even column */
          gint even_y = ((sw - 1 - y) & ~1);

          u = s[(sh - 1 - x) * src_stride + even_y * bpp + u_offset];
          if (x + 1 < dw)
            u = (s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + u_offset]
                + u) >> 1;
          v = s[(sh - 1 - x) * src_stride + even_y * bpp + v_offset];
          if (x + 1 < dw)
            v = (s[(sh - 1 - (x + 1)) * src_stride + even_y * bpp + v_offset]
                + v) >> 1;

          d[y * dest_stride + x * bpp + u_offset] = u;
          d[y * dest_stride + x * bpp + v_offset] = v;
          d[y * dest_stride + x * bpp + y_offset] =
              s[(sh - 1 - x) * src_stride + (sw - 1 - y) * bpp + y_offset];
          if (x + 1 < dw)
            d[y * dest_stride + (x + 1) * bpp + y_offset] =
                s[(sh - 1 - (x + 1)) * src_stride + (sw - 1 - y) * bpp +
                y_offset];
        }
      }
      break;
    case GST_VIDEO_FLIP_METHOD_IDENTITY:
      g_assert_not_reached ();
      break;
    default:
      g_assert_not_reached ();
      break;
  }
}
Example #28
0
static void
gst_video_detect_yuv (GstVideoDetect * videodetect, GstBuffer * buffer)
{
  GstVideoFormat format;
  gdouble brightness;
  gint i, pw, ph, row_stride, pixel_stride, offset;
  gint width, height, req_width, req_height;
  guint8 *d, *data;
  guint64 pattern_data;

  data = GST_BUFFER_DATA (buffer);

  format = videodetect->format;
  width = videodetect->width;
  height = videodetect->height;

  pw = videodetect->pattern_width;
  ph = videodetect->pattern_height;
  row_stride = gst_video_format_get_row_stride (format, 0, width);
  pixel_stride = gst_video_format_get_pixel_stride (format, 0);
  offset = gst_video_format_get_component_offset (format, 0, width, height);

  req_width =
      (videodetect->pattern_count + videodetect->pattern_data_count) * pw +
      videodetect->left_offset;
  req_height = videodetect->bottom_offset + ph;
  if (req_width > width || req_height > height) {
    goto no_pattern;
  }

  /* analyse the bottom left pixels */
  for (i = 0; i < videodetect->pattern_count; i++) {
    d = data + offset;
    /* move to start of bottom left, adjust for offsets */
    d += row_stride * (height - ph - videodetect->bottom_offset) +
        pixel_stride * videodetect->left_offset;
    /* move to i-th pattern */
    d += pixel_stride * pw * i;

    /* calc brightness of width * height box */
    brightness = gst_video_detect_calc_brightness (videodetect, d, pw, ph,
        row_stride, pixel_stride);

    GST_DEBUG_OBJECT (videodetect, "brightness %f", brightness);

    if (i & 1) {
      /* odd pixels must be white, all pixels darker than the center +
       * sensitivity are considered wrong. */
      if (brightness <
          (videodetect->pattern_center + videodetect->pattern_sensitivity))
        goto no_pattern;
    } else {
      /* even pixels must be black, pixels lighter than the center - sensitivity
       * are considered wrong. */
      if (brightness >
          (videodetect->pattern_center - videodetect->pattern_sensitivity))
        goto no_pattern;
    }
  }
  GST_DEBUG_OBJECT (videodetect, "found pattern");

  pattern_data = 0;

  /* get the data of the pattern */
  for (i = 0; i < videodetect->pattern_data_count; i++) {
    d = data + offset;
    /* move to start of bottom left, adjust for offsets */
    d += row_stride * (height - ph - videodetect->bottom_offset) +
        pixel_stride * videodetect->left_offset;
    /* move after the fixed pattern */
    d += pixel_stride * (videodetect->pattern_count * pw);
    /* move to i-th pattern data */
    d += pixel_stride * pw * i;

    /* calc brightness of width * height box */
    brightness = gst_video_detect_calc_brightness (videodetect, d, pw, ph,
        row_stride, pixel_stride);
    /* update pattern, we just use the center to decide between black and white. */
    pattern_data <<= 1;
    if (brightness > videodetect->pattern_center)
      pattern_data |= 1;
  }

  GST_DEBUG_OBJECT (videodetect, "have data %" G_GUINT64_FORMAT, pattern_data);

  videodetect->in_pattern = TRUE;
  gst_video_detect_post_message (videodetect, buffer, pattern_data);

  return;

no_pattern:
  {
    GST_DEBUG_OBJECT (videodetect, "no pattern found");
    if (videodetect->in_pattern) {
      videodetect->in_pattern = FALSE;
      gst_video_detect_post_message (videodetect, buffer, 0);
    }
    return;
  }
}
static gboolean
gst_vp8_enc_set_format (GstBaseVideoEncoder * base_video_encoder,
    GstVideoState * state)
{
  GstVP8Enc *encoder;
  vpx_codec_enc_cfg_t cfg;
  vpx_codec_err_t status;
  vpx_image_t *image;
  guint8 *data = NULL;
  GstCaps *caps;
  gboolean ret;

  encoder = GST_VP8_ENC (base_video_encoder);
  GST_DEBUG_OBJECT (base_video_encoder, "set_format");

  if (encoder->inited) {
    GST_DEBUG_OBJECT (base_video_encoder, "refusing renegotiation");
    return FALSE;
  }

  status = vpx_codec_enc_config_default (&vpx_codec_vp8_cx_algo, &cfg, 0);
  if (status != VPX_CODEC_OK) {
    GST_ELEMENT_ERROR (encoder, LIBRARY, INIT,
        ("Failed to get default encoder configuration"), ("%s",
            gst_vpx_error_name (status)));
    return FALSE;
  }

  /* Scale default bitrate to our size */
  cfg.rc_target_bitrate = gst_util_uint64_scale (cfg.rc_target_bitrate,
      state->width * state->height,
      cfg.g_w * cfg.g_h);

  cfg.g_w = state->width;
  cfg.g_h = state->height;
  cfg.g_timebase.num = state->fps_d;
  cfg.g_timebase.den = state->fps_n;

  cfg.g_error_resilient = encoder->error_resilient;
  cfg.g_lag_in_frames = encoder->max_latency;
  cfg.g_threads = encoder->threads;
  cfg.rc_end_usage = encoder->mode;
  cfg.rc_2pass_vbr_minsection_pct = encoder->minsection_pct;
  cfg.rc_2pass_vbr_maxsection_pct = encoder->maxsection_pct;
  /* Standalone qp-min do not make any sence, with bitrate=0 and qp-min=1
   * encoder will use only default qp-max=63. Also this will make
   * worst possbile quality.
   */
  if (encoder->bitrate != DEFAULT_BITRATE ||
      encoder->max_quantizer != DEFAULT_MAX_QUANTIZER) {
    cfg.rc_target_bitrate = encoder->bitrate / 1000;
    cfg.rc_min_quantizer = encoder->min_quantizer;
    cfg.rc_max_quantizer = encoder->max_quantizer;
  } else {
    cfg.rc_min_quantizer = (gint) (63 - encoder->quality * 6.2);
    cfg.rc_max_quantizer = (gint) (63 - encoder->quality * 6.2);
  }
  cfg.rc_dropframe_thresh = encoder->drop_frame;
  cfg.rc_resize_allowed = encoder->resize_allowed;

  cfg.kf_mode = VPX_KF_AUTO;
  cfg.kf_min_dist = 0;
  cfg.kf_max_dist = encoder->max_keyframe_distance;

  cfg.g_pass = encoder->multipass_mode;
  if (encoder->multipass_mode == VPX_RC_FIRST_PASS) {
    encoder->first_pass_cache_content = g_byte_array_sized_new (4096);
  } else if (encoder->multipass_mode == VPX_RC_LAST_PASS) {
    GError *err = NULL;

    if (!encoder->multipass_cache_file) {
      GST_ELEMENT_ERROR (encoder, RESOURCE, OPEN_READ,
          ("No multipass cache file provided"), (NULL));
      return FALSE;
    }

    if (!g_file_get_contents (encoder->multipass_cache_file,
            (gchar **) & encoder->last_pass_cache_content.buf,
            &encoder->last_pass_cache_content.sz, &err)) {
      GST_ELEMENT_ERROR (encoder, RESOURCE, OPEN_READ,
          ("Failed to read multipass cache file provided"), ("%s",
              err->message));
      g_error_free (err);
      return FALSE;
    }
    cfg.rc_twopass_stats_in = encoder->last_pass_cache_content;
  }

  status = vpx_codec_enc_init (&encoder->encoder, &vpx_codec_vp8_cx_algo,
      &cfg, 0);
  if (status != VPX_CODEC_OK) {
    GST_ELEMENT_ERROR (encoder, LIBRARY, INIT,
        ("Failed to initialize encoder"), ("%s", gst_vpx_error_name (status)));
    return FALSE;
  }

  /* FIXME move this to a set_speed() function */
  status = vpx_codec_control (&encoder->encoder, VP8E_SET_CPUUSED,
      (encoder->speed == 0) ? 0 : (encoder->speed - 1));
  if (status != VPX_CODEC_OK) {
    GST_WARNING_OBJECT (encoder, "Failed to set VP8E_SET_CPUUSED to 0: %s",
        gst_vpx_error_name (status));
  }

  status = vpx_codec_control (&encoder->encoder, VP8E_SET_NOISE_SENSITIVITY,
      encoder->noise_sensitivity);
  status = vpx_codec_control (&encoder->encoder, VP8E_SET_SHARPNESS,
      encoder->sharpness);
  status = vpx_codec_control (&encoder->encoder, VP8E_SET_STATIC_THRESHOLD,
      encoder->static_threshold);
  status = vpx_codec_control (&encoder->encoder, VP8E_SET_TOKEN_PARTITIONS,
      encoder->partitions);
#if 0
  status = vpx_codec_control (&encoder->encoder, VP8E_SET_ARNR_MAXFRAMES,
      encoder->arnr_maxframes);
  status = vpx_codec_control (&encoder->encoder, VP8E_SET_ARNR_STRENGTH,
      encoder->arnr_strength);
  status = vpx_codec_control (&encoder->encoder, VP8E_SET_ARNR_TYPE,
      encoder->arnr_type);
#endif
#ifdef HAVE_VP8ENC_TUNING
  status = vpx_codec_control (&encoder->encoder, VP8E_SET_TUNING,
      encoder->tuning);
#endif

  status =
      vpx_codec_control (&encoder->encoder, VP8E_SET_ENABLEAUTOALTREF,
      (encoder->auto_alt_ref_frames ? 1 : 0));
  if (status != VPX_CODEC_OK) {
    GST_WARNING_OBJECT (encoder,
        "Failed to set VP8E_ENABLEAUTOALTREF to %d: %s",
        (encoder->auto_alt_ref_frames ? 1 : 0), gst_vpx_error_name (status));
  }

  cfg.g_lag_in_frames = encoder->lag_in_frames;

  gst_base_video_encoder_set_latency (base_video_encoder, 0,
      gst_util_uint64_scale (encoder->max_latency,
          state->fps_d * GST_SECOND, state->fps_n));
  encoder->inited = TRUE;

  /* prepare cached image buffer setup */
  image = &encoder->image;
  memset (image, 0, sizeof (*image));

  image->fmt = VPX_IMG_FMT_I420;
  image->bps = 12;
  image->x_chroma_shift = image->y_chroma_shift = 1;
  image->w = image->d_w = state->width;
  image->h = image->d_h = state->height;

  image->stride[VPX_PLANE_Y] =
      gst_video_format_get_row_stride (state->format, 0, state->width);
  image->stride[VPX_PLANE_U] =
      gst_video_format_get_row_stride (state->format, 1, state->width);
  image->stride[VPX_PLANE_V] =
      gst_video_format_get_row_stride (state->format, 2, state->width);
  image->planes[VPX_PLANE_Y] =
      data + gst_video_format_get_component_offset (state->format, 0,
      state->width, state->height);
  image->planes[VPX_PLANE_U] =
      data + gst_video_format_get_component_offset (state->format, 1,
      state->width, state->height);
  image->planes[VPX_PLANE_V] =
      data + gst_video_format_get_component_offset (state->format, 2,
      state->width, state->height);


  caps = gst_caps_new_simple ("video/x-vp8",
      "width", G_TYPE_INT, state->width,
      "height", G_TYPE_INT, state->height,
      "framerate", GST_TYPE_FRACTION, state->fps_n,
      state->fps_d,
      "pixel-aspect-ratio", GST_TYPE_FRACTION, state->par_n,
      state->par_d, NULL);
  {
    GstStructure *s;
    GstBuffer *stream_hdr, *vorbiscomment;
    const GstTagList *iface_tags;
    GValue array = { 0, };
    GValue value = { 0, };
    s = gst_caps_get_structure (caps, 0);

    /* put buffers in a fixed list */
    g_value_init (&array, GST_TYPE_ARRAY);
    g_value_init (&value, GST_TYPE_BUFFER);

    /* Create Ogg stream-info */
    stream_hdr = gst_buffer_new_and_alloc (26);
    data = GST_BUFFER_DATA (stream_hdr);

    GST_WRITE_UINT8 (data, 0x4F);
    GST_WRITE_UINT32_BE (data + 1, 0x56503830); /* "VP80" */
    GST_WRITE_UINT8 (data + 5, 0x01);   /* stream info header */
    GST_WRITE_UINT8 (data + 6, 1);      /* Major version 1 */
    GST_WRITE_UINT8 (data + 7, 0);      /* Minor version 0 */
    GST_WRITE_UINT16_BE (data + 8, state->width);
    GST_WRITE_UINT16_BE (data + 10, state->height);
    GST_WRITE_UINT24_BE (data + 12, state->par_n);
    GST_WRITE_UINT24_BE (data + 15, state->par_d);
    GST_WRITE_UINT32_BE (data + 18, state->fps_n);
    GST_WRITE_UINT32_BE (data + 22, state->fps_d);

    GST_BUFFER_FLAG_SET (stream_hdr, GST_BUFFER_FLAG_IN_CAPS);
    gst_value_set_buffer (&value, stream_hdr);
    gst_value_array_append_value (&array, &value);
    g_value_unset (&value);
    gst_buffer_unref (stream_hdr);

    iface_tags =
        gst_tag_setter_get_tag_list (GST_TAG_SETTER (base_video_encoder));
    if (iface_tags) {
      vorbiscomment =
          gst_tag_list_to_vorbiscomment_buffer (iface_tags,
          (const guint8 *) "OVP80\2 ", 7,
          "Encoded with GStreamer vp8enc " PACKAGE_VERSION);

      GST_BUFFER_FLAG_SET (vorbiscomment, GST_BUFFER_FLAG_IN_CAPS);

      g_value_init (&value, GST_TYPE_BUFFER);
      gst_value_set_buffer (&value, vorbiscomment);
      gst_value_array_append_value (&array, &value);
      g_value_unset (&value);
      gst_buffer_unref (vorbiscomment);
    }

    gst_structure_set_value (s, "streamheader", &array);
    g_value_unset (&array);
  }

  ret = gst_pad_set_caps (GST_BASE_VIDEO_CODEC_SRC_PAD (encoder), caps);
  gst_caps_unref (caps);

  return ret;
}