static void gst_video_crop_transform_packed_simple (GstVideoCrop * vcrop, GstVideoFrame * in_frame, GstVideoFrame * out_frame) { guint8 *in_data, *out_data; gint width, height; guint i, dx; gint in_stride, out_stride; width = GST_VIDEO_FRAME_WIDTH (out_frame); height = GST_VIDEO_FRAME_HEIGHT (out_frame); in_data = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0); out_data = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0); in_stride = GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0); out_stride = GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 0); in_data += vcrop->crop_top * in_stride; in_data += vcrop->crop_left * GST_VIDEO_FRAME_COMP_PSTRIDE (in_frame, 0); dx = width * GST_VIDEO_FRAME_COMP_PSTRIDE (out_frame, 0); for (i = 0; i < height; ++i) { memcpy (out_data, in_data, dx); in_data += in_stride; out_data += out_stride; } }
/* this function does the actual processing */ static GstFlowReturn gst_yuv_to_rgb_transform_frame (GstVideoFilter *filter, GstVideoFrame *in_frame, GstVideoFrame *out_frame) { GstYuvToRgb *rgbtoyuv = GST_YUVTORGB_CAST (filter); gint width, height, stride; gint y_stride, uv_stride; guint32 *out_data; guint8 *y_in, *u_in, *v_in; y_stride = GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0); uv_stride = GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 1); y_in = (guint8*) GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0); u_in = (guint8*) GST_VIDEO_FRAME_PLANE_DATA (in_frame, 1); v_in = (guint8*) GST_VIDEO_FRAME_PLANE_DATA (in_frame, 2); width = GST_VIDEO_FRAME_WIDTH (out_frame); height = GST_VIDEO_FRAME_HEIGHT (out_frame); stride = GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 0); out_data = (guint32*) GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0); // GST_INFO ("DEBUG_INFO: rgbtoyuv::transform_frame: "); // GST_INFO ("in stride: %d; out stride: %d %d\n", stride, y_stride, uv_stride); libyuv::I420ToARGB (y_in, y_stride, u_in, uv_stride, v_in, uv_stride, (guint8*)out_data, stride, width, height); return GST_FLOW_OK; }
static void copy_field (GstInterlace * interlace, GstBuffer * dest, GstBuffer * src, int field_index) { GstVideoInfo *info = &interlace->info; gint i, j, n_planes; guint8 *d, *s; GstVideoFrame dframe, sframe; if (!gst_video_frame_map (&dframe, info, dest, GST_MAP_WRITE)) goto dest_map_failed; if (!gst_video_frame_map (&sframe, info, src, GST_MAP_READ)) goto src_map_failed; n_planes = GST_VIDEO_FRAME_N_PLANES (&dframe); for (i = 0; i < n_planes; i++) { gint cheight, cwidth; gint ss, ds; d = GST_VIDEO_FRAME_PLANE_DATA (&dframe, i); s = GST_VIDEO_FRAME_PLANE_DATA (&sframe, i); ds = GST_VIDEO_FRAME_PLANE_STRIDE (&dframe, i); ss = GST_VIDEO_FRAME_PLANE_STRIDE (&sframe, i); d += field_index * ds; s += field_index * ss; cheight = GST_VIDEO_FRAME_COMP_HEIGHT (&dframe, i); cwidth = MIN (ABS (ss), ABS (ds)); for (j = field_index; j < cheight; j += 2) { memcpy (d, s, cwidth); d += ds * 2; s += ss * 2; } } gst_video_frame_unmap (&dframe); gst_video_frame_unmap (&sframe); return; dest_map_failed: { GST_ERROR_OBJECT (interlace, "failed to map dest"); return; } src_map_failed: { GST_ERROR_OBJECT (interlace, "failed to map src"); gst_video_frame_unmap (&dframe); return; } }
static void gst_video_balance_semiplanar_yuv (GstVideoBalance * videobalance, GstVideoFrame * frame) { gint x, y; guint8 *ydata; guint8 *uvdata; gint ystride, uvstride; gint width, height; gint width2, height2; guint8 *tabley = videobalance->tabley; guint8 **tableu = videobalance->tableu; guint8 **tablev = videobalance->tablev; gint upos, vpos; width = GST_VIDEO_FRAME_WIDTH (frame); height = GST_VIDEO_FRAME_HEIGHT (frame); ydata = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); ystride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0); for (y = 0; y < height; y++) { guint8 *yptr; yptr = ydata + y * ystride; for (x = 0; x < width; x++) { *yptr = tabley[*yptr]; yptr++; } } width2 = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1); height2 = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 1); uvdata = GST_VIDEO_FRAME_PLANE_DATA (frame, 1); uvstride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 1); upos = GST_VIDEO_INFO_FORMAT (&frame->info) == GST_VIDEO_FORMAT_NV12 ? 0 : 1; vpos = GST_VIDEO_INFO_FORMAT (&frame->info) == GST_VIDEO_FORMAT_NV12 ? 1 : 0; for (y = 0; y < height2; y++) { guint8 *uvptr; guint8 u1, v1; uvptr = uvdata + y * uvstride; for (x = 0; x < width2; x++) { u1 = uvptr[upos]; v1 = uvptr[vpos]; uvptr[upos] = tableu[u1][v1]; uvptr[vpos] = tablev[u1][v1]; uvptr += 2; } } }
static void gst_video_balance_planar_yuv (GstVideoBalance * videobalance, GstVideoFrame * frame) { gint x, y; guint8 *ydata; guint8 *udata, *vdata; gint ystride, ustride, vstride; gint width, height; gint width2, height2; guint8 *tabley = videobalance->tabley; guint8 **tableu = videobalance->tableu; guint8 **tablev = videobalance->tablev; width = GST_VIDEO_FRAME_WIDTH (frame); height = GST_VIDEO_FRAME_HEIGHT (frame); ydata = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); ystride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0); for (y = 0; y < height; y++) { guint8 *yptr; yptr = ydata + y * ystride; for (x = 0; x < width; x++) { *yptr = tabley[*yptr]; yptr++; } } width2 = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1); height2 = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 1); udata = GST_VIDEO_FRAME_PLANE_DATA (frame, 1); vdata = GST_VIDEO_FRAME_PLANE_DATA (frame, 2); ustride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 1); vstride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 2); 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]; } } }
static void gst_video_crop_transform_packed_complex (GstVideoCrop * vcrop, GstVideoFrame * in_frame, GstVideoFrame * out_frame) { guint8 *in_data, *out_data; guint i, dx; gint width, height; gint in_stride; gint out_stride; width = GST_VIDEO_FRAME_WIDTH (out_frame); height = GST_VIDEO_FRAME_HEIGHT (out_frame); in_data = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0); out_data = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0); in_stride = GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0); out_stride = GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 0); in_data += vcrop->crop_top * in_stride; /* rounding down here so we end up at the start of a macro-pixel and not * in the middle of one */ in_data += ROUND_DOWN_2 (vcrop->crop_left) * GST_VIDEO_FRAME_COMP_PSTRIDE (in_frame, 0); dx = width * GST_VIDEO_FRAME_COMP_PSTRIDE (out_frame, 0); /* UYVY = 4:2:2 - [U0 Y0 V0 Y1] [U2 Y2 V2 Y3] [U4 Y4 V4 Y5] * YUYV = 4:2:2 - [Y0 U0 Y1 V0] [Y2 U2 Y3 V2] [Y4 U4 Y5 V4] = YUY2 */ if ((vcrop->crop_left % 2) != 0) { for (i = 0; i < height; ++i) { gint j; memcpy (out_data, in_data, dx); /* move just the Y samples one pixel to the left, don't worry about * chroma shift */ for (j = vcrop->macro_y_off; j < out_stride - 2; j += 2) out_data[j] = in_data[j + 2]; in_data += in_stride; out_data += out_stride; } } else { for (i = 0; i < height; ++i) { memcpy (out_data, in_data, dx); in_data += in_stride; out_data += out_stride; } } }
/* Copy the frame data from the GstBuffer (from decoder) * to the picture obtained from downstream in VLC. * This function should be avoided as much * as possible, since it involves a complete frame copy. */ static void gst_CopyPicture( picture_t *p_pic, GstVideoFrame *p_frame ) { int i_plane, i_planes, i_line, i_dst_stride, i_src_stride; uint8_t *p_dst, *p_src; int i_w, i_h; i_planes = p_pic->i_planes; for( i_plane = 0; i_plane < i_planes; i_plane++ ) { p_dst = p_pic->p[i_plane].p_pixels; p_src = GST_VIDEO_FRAME_PLANE_DATA( p_frame, i_plane ); i_dst_stride = p_pic->p[i_plane].i_pitch; i_src_stride = GST_VIDEO_FRAME_PLANE_STRIDE( p_frame, i_plane ); i_w = GST_VIDEO_FRAME_COMP_WIDTH( p_frame, i_plane ) * GST_VIDEO_FRAME_COMP_PSTRIDE( p_frame, i_plane ); i_h = GST_VIDEO_FRAME_COMP_HEIGHT( p_frame, i_plane ); for( i_line = 0; i_line < __MIN( p_pic->p[i_plane].i_lines, i_h ); i_line++ ) { memcpy( p_dst, p_src, i_w ); p_src += i_src_stride; p_dst += i_dst_stride; } } }
static GstFlowReturn openni2_read_gstbuffer (GstOpenni2Src * src, GstBuffer * buf) { openni::Status rc = openni::STATUS_OK; openni::VideoStream * pStream = src->depth; int changedStreamDummy; GstVideoFrame vframe; uint64_t oni_ts; /* Block until we get some data */ rc = openni::OpenNI::waitForAnyStream (&pStream, 1, &changedStreamDummy, SAMPLE_READ_WAIT_TIMEOUT); if (rc != openni::STATUS_OK) { GST_ERROR_OBJECT (src, "Frame read timeout: %s", openni::OpenNI::getExtendedError ()); return GST_FLOW_ERROR; } if (src->depth->isValid () && src->color->isValid () && src->sourcetype == SOURCETYPE_BOTH) { rc = src->depth->readFrame (src->depthFrame); if (rc != openni::STATUS_OK) { GST_ERROR_OBJECT (src, "Frame read error: %s", openni::OpenNI::getExtendedError ()); return GST_FLOW_ERROR; } rc = src->color->readFrame (src->colorFrame); if (rc != openni::STATUS_OK) { GST_ERROR_OBJECT (src, "Frame read error: %s", openni::OpenNI::getExtendedError ()); return GST_FLOW_ERROR; } /* Copy colour information */ gst_video_frame_map (&vframe, &src->info, buf, GST_MAP_WRITE); guint8 *pData = (guint8 *) GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0); guint8 *pColor = (guint8 *) src->colorFrame->getData (); /* Add depth as 8bit alpha channel, depth is 16bit samples. */ guint16 *pDepth = (guint16 *) src->depthFrame->getData (); for (int i = 0; i < src->colorFrame->getHeight (); ++i) { for (int j = 0; j < src->colorFrame->getWidth (); ++j) { pData[4 * j + 0] = pColor[3 * j + 0]; pData[4 * j + 1] = pColor[3 * j + 1]; pData[4 * j + 2] = pColor[3 * j + 2]; pData[4 * j + 3] = pDepth[j] >> 8; } pData += GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 0); pColor += src->colorFrame->getStrideInBytes (); pDepth += src->depthFrame->getStrideInBytes () / 2; } gst_video_frame_unmap (&vframe); oni_ts = src->colorFrame->getTimestamp () * 1000; GST_LOG_OBJECT (src, "sending buffer (%d+%d)B", src->colorFrame->getDataSize (), src->depthFrame->getDataSize ()); } else if (src->depth->isValid () && src->sourcetype == SOURCETYPE_DEPTH) {
static void fill_image_planar8_3 (opj_image_t * image, GstVideoFrame * frame) { gint c, x, y, w, h; const guint8 *data_in, *tmp; gint *data_out; gint sstride; for (c = 0; c < 3; c++) { w = GST_VIDEO_FRAME_COMP_WIDTH (frame, c); h = GST_VIDEO_FRAME_COMP_HEIGHT (frame, c); data_in = GST_VIDEO_FRAME_COMP_DATA (frame, c); sstride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, c); data_out = image->comps[c].data; for (y = 0; y < h; y++) { tmp = data_in; for (x = 0; x < w; x++) { *data_out = *tmp; data_out++; tmp++; } data_in += sstride; } } }
static void fill_frame_planar16_1 (GstVideoFrame * frame, opj_image_t * image) { gint x, y, w, h; guint16 *data_out, *tmp; const gint *data_in; gint dstride; gint shift; w = GST_VIDEO_FRAME_WIDTH (frame); h = GST_VIDEO_FRAME_HEIGHT (frame); data_out = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); dstride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0) / 2; data_in = image->comps[0].data; shift = 16 - image->comps[0].prec; for (y = 0; y < h; y++) { tmp = data_out; for (x = 0; x < w; x++) { *tmp = *data_in << shift; tmp++; data_in++; } data_out += dstride; } }
static void fill_frame_packed8_3 (GstVideoFrame * frame, opj_image_t * image) { gint x, y, w, h; guint8 *data_out, *tmp; const gint *data_in[3]; gint dstride; w = GST_VIDEO_FRAME_WIDTH (frame); h = GST_VIDEO_FRAME_HEIGHT (frame); data_out = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); dstride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0); data_in[0] = image->comps[0].data; data_in[1] = image->comps[1].data; data_in[2] = image->comps[2].data; for (y = 0; y < h; y++) { tmp = data_out; for (x = 0; x < w; x++) { tmp[1] = *data_in[0]; tmp[2] = *data_in[1]; tmp[3] = *data_in[2]; tmp += 4; data_in[0]++; data_in[1]++; data_in[2]++; } data_out += dstride; } }
static void fill_image_packed8_3 (opj_image_t * image, GstVideoFrame * frame) { gint x, y, w, h; const guint8 *data_in, *tmp; gint *data_out[3]; gint sstride; w = GST_VIDEO_FRAME_WIDTH (frame); h = GST_VIDEO_FRAME_HEIGHT (frame); data_in = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); sstride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0); data_out[0] = image->comps[0].data; data_out[1] = image->comps[1].data; data_out[2] = image->comps[2].data; for (y = 0; y < h; y++) { tmp = data_in; for (x = 0; x < w; x++) { *data_out[0] = tmp[1]; *data_out[1] = tmp[2]; *data_out[2] = tmp[3]; tmp += 4; data_out[0]++; data_out[1]++; data_out[2]++; } data_in += sstride; } }
static void gst_video_balance_packed_rgb (GstVideoBalance * videobalance, GstVideoFrame * frame) { gint i, j, height; gint width, stride, row_wrap; gint pixel_stride; guint8 *data; 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; width = GST_VIDEO_FRAME_WIDTH (frame); height = GST_VIDEO_FRAME_HEIGHT (frame); offsets[0] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 0); offsets[1] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 1); offsets[2] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 2); data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0); pixel_stride = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 0); row_wrap = 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; } }
static void gst_video_crop_transform_planar (GstVideoCrop * vcrop, GstVideoFrame * in_frame, GstVideoFrame * out_frame) { gint width, height; guint8 *y_out, *u_out, *v_out; guint8 *y_in, *u_in, *v_in; guint i, dx; width = GST_VIDEO_FRAME_WIDTH (out_frame); height = GST_VIDEO_FRAME_HEIGHT (out_frame); /* Y plane */ y_in = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0); y_out = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0); y_in += (vcrop->crop_top * GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0)) + vcrop->crop_left; dx = width; for (i = 0; i < height; ++i) { memcpy (y_out, y_in, dx); y_in += GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0); y_out += GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 0); } /* U + V planes */ u_in = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 1); u_out = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 1); u_in += (vcrop->crop_top / 2) * GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 1); u_in += vcrop->crop_left / 2; v_in = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 2); v_out = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 2); v_in += (vcrop->crop_top / 2) * GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 2); v_in += vcrop->crop_left / 2; dx = GST_ROUND_UP_2 (width) / 2; for (i = 0; i < GST_ROUND_UP_2 (height) / 2; ++i) { memcpy (u_out, u_in, dx); memcpy (v_out, v_in, dx); u_in += GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 1); u_out += GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 1); v_in += GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 2); v_out += GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 2); } }
static void gst_smpte_alpha_process_ayuv_ayuv (GstSMPTEAlpha * smpte, const GstVideoFrame * in_frame, GstVideoFrame * out_frame, GstMask * mask, gint border, gint pos) { gint i, j; const guint32 *maskp; gint value; gint min, max; gint width, height; guint8 *in, *out; gint src_wrap, dest_wrap; 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; width = GST_VIDEO_FRAME_WIDTH (out_frame); height = GST_VIDEO_FRAME_HEIGHT (out_frame); in = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0); out = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0); src_wrap = GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0) - (width << 2); dest_wrap = GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 0) - (width << 2); /* we basically copy the source to dest but we scale the alpha channel with * the mask */ for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { value = *maskp++; *out++ = (*in++ * ((CLAMP (value, min, max) - min) << 8) / border) >> 8; *out++ = *in++; *out++ = *in++; *out++ = *in++; } in += src_wrap; out += dest_wrap; } }
static void gst_color_effects_transform_rgb (GstColorEffects * filter, GstVideoFrame * frame) { gint i, j; gint width, height; gint pixel_stride, row_stride, row_wrap; guint32 r, g, b; guint32 luma; gint offsets[3]; guint8 *data; data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); offsets[0] = GST_VIDEO_FRAME_COMP_POFFSET (frame, 0); offsets[1] = GST_VIDEO_FRAME_COMP_POFFSET (frame, 1); offsets[2] = GST_VIDEO_FRAME_COMP_POFFSET (frame, 2); width = GST_VIDEO_FRAME_WIDTH (frame); height = GST_VIDEO_FRAME_HEIGHT (frame); row_stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0); pixel_stride = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 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; }
static GstFlowReturn gst_cairo_overlay_transform_frame_ip (GstVideoFilter * vfilter, GstVideoFrame * frame) { GstCairoOverlay *overlay = GST_CAIRO_OVERLAY (vfilter); cairo_surface_t *surface; cairo_t *cr; cairo_format_t format; switch (GST_VIDEO_FRAME_FORMAT (frame)) { case GST_VIDEO_FORMAT_ARGB: case GST_VIDEO_FORMAT_BGRA: format = CAIRO_FORMAT_ARGB32; break; case GST_VIDEO_FORMAT_xRGB: case GST_VIDEO_FORMAT_BGRx: format = CAIRO_FORMAT_RGB24; break; case GST_VIDEO_FORMAT_RGB16: format = CAIRO_FORMAT_RGB16_565; break; default: { GST_WARNING ("No matching cairo format for %s", gst_video_format_to_string (GST_VIDEO_FRAME_FORMAT (frame))); return GST_FLOW_ERROR; } } surface = cairo_image_surface_create_for_data (GST_VIDEO_FRAME_PLANE_DATA (frame, 0), format, GST_VIDEO_FRAME_WIDTH (frame), GST_VIDEO_FRAME_HEIGHT (frame), GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0)); if (G_UNLIKELY (!surface)) return GST_FLOW_ERROR; cr = cairo_create (surface); if (G_UNLIKELY (!cr)) { cairo_surface_destroy (surface); return GST_FLOW_ERROR; } g_signal_emit (overlay, gst_cairo_overlay_signals[SIGNAL_DRAW], 0, cr, GST_BUFFER_PTS (frame->buffer), GST_BUFFER_DURATION (frame->buffer), NULL); cairo_destroy (cr); cairo_surface_destroy (surface); return GST_FLOW_OK; }
static void gst_gamma_packed_rgb_ip (GstGamma * gamma, GstVideoFrame * frame) { gint i, j, height; gint width, stride, row_wrap; gint pixel_stride; const guint8 *table = gamma->gamma_table; gint offsets[3]; gint r, g, b; gint y, u, v; guint8 *data; data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0); width = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); height = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 0); offsets[0] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 0); offsets[1] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 1); offsets[2] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 2); pixel_stride = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 0); row_wrap = 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; } }
static void fill_frame_planar16_4_generic (GstVideoFrame * frame, opj_image_t * image) { gint x, y, w, h; guint16 *data_out, *tmp; const gint *data_in[4]; gint dstride; gint dx[4], dy[4], shift[4]; w = GST_VIDEO_FRAME_WIDTH (frame); h = GST_VIDEO_FRAME_HEIGHT (frame); data_out = (guint16 *) GST_VIDEO_FRAME_PLANE_DATA (frame, 0); dstride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0) / 2; data_in[0] = image->comps[0].data; data_in[1] = image->comps[1].data; data_in[2] = image->comps[2].data; data_in[3] = image->comps[3].data; dx[0] = image->comps[0].dx; dx[1] = image->comps[1].dx; dx[2] = image->comps[2].dx; dx[3] = image->comps[3].dx; dy[0] = image->comps[0].dy; dy[1] = image->comps[1].dy; dy[2] = image->comps[2].dy; dy[3] = image->comps[3].dy; shift[0] = 16 - image->comps[0].prec; shift[1] = 16 - image->comps[1].prec; shift[2] = 16 - image->comps[2].prec; shift[3] = 16 - image->comps[3].prec; for (y = 0; y < h; y++) { tmp = data_out; for (x = 0; x < w; x++) { tmp[0] = data_in[3][((y / dy[3]) * w + x) / dx[3]] << shift[3]; tmp[1] = data_in[0][((y / dy[0]) * w + x) / dx[0]] << shift[0]; tmp[2] = data_in[1][((y / dy[1]) * w + x) / dx[1]] << shift[1]; tmp[3] = data_in[2][((y / dy[2]) * w + x) / dx[2]] << shift[2]; tmp += 4; } data_out += dstride; } }
PassRefPtr<BitmapTexture> MediaPlayerPrivateGStreamerBase::updateTexture(TextureMapper* textureMapper) { WTF::GMutexLocker<GMutex> lock(m_sampleMutex); if (!GST_IS_SAMPLE(m_sample.get())) return nullptr; GstCaps* caps = gst_sample_get_caps(m_sample.get()); if (!caps) return nullptr; GstVideoInfo videoInfo; gst_video_info_init(&videoInfo); if (!gst_video_info_from_caps(&videoInfo, caps)) return nullptr; IntSize size = IntSize(GST_VIDEO_INFO_WIDTH(&videoInfo), GST_VIDEO_INFO_HEIGHT(&videoInfo)); RefPtr<BitmapTexture> texture = textureMapper->acquireTextureFromPool(size, GST_VIDEO_INFO_HAS_ALPHA(&videoInfo) ? BitmapTexture::SupportsAlpha : BitmapTexture::NoFlag); GstBuffer* buffer = gst_sample_get_buffer(m_sample.get()); #if GST_CHECK_VERSION(1, 1, 0) GstVideoGLTextureUploadMeta* meta; if ((meta = gst_buffer_get_video_gl_texture_upload_meta(buffer))) { if (meta->n_textures == 1) { // BRGx & BGRA formats use only one texture. const BitmapTextureGL* textureGL = static_cast<const BitmapTextureGL*>(texture.get()); guint ids[4] = { textureGL->id(), 0, 0, 0 }; if (gst_video_gl_texture_upload_meta_upload(meta, ids)) return texture; } } #endif // Right now the TextureMapper only supports chromas with one plane ASSERT(GST_VIDEO_INFO_N_PLANES(&videoInfo) == 1); GstVideoFrame videoFrame; if (!gst_video_frame_map(&videoFrame, &videoInfo, buffer, GST_MAP_READ)) return nullptr; int stride = GST_VIDEO_FRAME_PLANE_STRIDE(&videoFrame, 0); const void* srcData = GST_VIDEO_FRAME_PLANE_DATA(&videoFrame, 0); texture->updateContents(srcData, WebCore::IntRect(WebCore::IntPoint(0, 0), size), WebCore::IntPoint(0, 0), stride, BitmapTexture::UpdateCannotModifyOriginalImageData); gst_video_frame_unmap(&videoFrame); return texture; }
static void gst_chroma_hold_process_xrgb (GstVideoFrame * frame, gint width, gint height, GstChromaHold * self) { gint i, j; gint r, g, b; gint grey; gint h1, h2; gint tolerance = self->tolerance; gint p[4]; gint diff; gint row_wrap; guint8 *dest; dest = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); p[0] = GST_VIDEO_FRAME_COMP_POFFSET (frame, 3); p[1] = GST_VIDEO_FRAME_COMP_POFFSET (frame, 0); p[2] = GST_VIDEO_FRAME_COMP_POFFSET (frame, 1); p[3] = GST_VIDEO_FRAME_COMP_POFFSET (frame, 2); row_wrap = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0) - 4 * width; h1 = self->hue; for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { r = dest[p[1]]; g = dest[p[2]]; b = dest[p[3]]; h2 = rgb_to_hue (r, g, b); diff = hue_dist (h1, h2); if (h1 == G_MAXUINT || diff > tolerance) { grey = (13938 * r + 46869 * g + 4730 * b) >> 16; grey = CLAMP (grey, 0, 255); dest[p[1]] = grey; dest[p[2]] = grey; dest[p[3]] = grey; } dest += 4; } dest += row_wrap; }
static void fill_frame_planar8_3_generic (GstVideoFrame * frame, opj_image_t * image) { gint x, y, w, h; guint8 *data_out, *tmp; const gint *data_in[3]; gint dstride; gint dx[3], dy[3]; w = GST_VIDEO_FRAME_WIDTH (frame); h = GST_VIDEO_FRAME_HEIGHT (frame); data_out = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); dstride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0); data_in[0] = image->comps[0].data; data_in[1] = image->comps[1].data; data_in[2] = image->comps[2].data; dx[0] = image->comps[0].dx; dx[1] = image->comps[1].dx; dx[2] = image->comps[2].dx; dy[0] = image->comps[0].dy; dy[1] = image->comps[1].dy; dy[2] = image->comps[2].dy; for (y = 0; y < h; y++) { tmp = data_out; for (x = 0; x < w; x++) { tmp[0] = 0xff; tmp[1] = data_in[0][((y / dy[0]) * w + x) / dx[0]]; tmp[2] = data_in[1][((y / dy[1]) * w + x) / dx[1]]; tmp[3] = data_in[2][((y / dy[2]) * w + x) / dx[2]]; tmp += 4; } data_out += dstride; } }
static void fill_image_planar16_1 (opj_image_t * image, GstVideoFrame * frame) { gint x, y, w, h; const guint16 *data_in, *tmp; gint *data_out; gint sstride; w = GST_VIDEO_FRAME_COMP_WIDTH (frame, 0); h = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 0); data_in = (guint16 *) GST_VIDEO_FRAME_COMP_DATA (frame, 0); sstride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0) / 2; data_out = image->comps[0].data; for (y = 0; y < h; y++) { tmp = data_in; for (x = 0; x < w; x++) { *data_out = *tmp; data_out++; tmp++; } data_in += sstride; } }
static GstFlowReturn gst_aasink_show_frame (GstVideoSink * videosink, GstBuffer * buffer) { GstAASink *aasink; GstVideoFrame frame; aasink = GST_AASINK (videosink); GST_DEBUG ("show frame"); if (!gst_video_frame_map (&frame, &aasink->info, buffer, GST_MAP_READ)) goto invalid_frame; gst_aasink_scale (aasink, GST_VIDEO_FRAME_PLANE_DATA (&frame, 0), /* src */ aa_image (aasink->context), /* dest */ GST_VIDEO_INFO_WIDTH (&aasink->info), /* sw */ GST_VIDEO_INFO_HEIGHT (&aasink->info), /* sh */ GST_VIDEO_FRAME_PLANE_STRIDE (&frame, 0), /* ss */ aa_imgwidth (aasink->context), /* dw */ aa_imgheight (aasink->context)); /* dh */ aa_render (aasink->context, &aasink->ascii_parms, 0, 0, aa_imgwidth (aasink->context), aa_imgheight (aasink->context)); aa_flush (aasink->context); aa_getevent (aasink->context, FALSE); gst_video_frame_unmap (&frame); return GST_FLOW_OK; /* ERRORS */ invalid_frame: { GST_DEBUG_OBJECT (aasink, "invalid frame"); return GST_FLOW_ERROR; } }
static GstFlowReturn gst_decklink_video_sink_prepare (GstBaseSink * bsink, GstBuffer * buffer) { GstDecklinkVideoSink *self = GST_DECKLINK_VIDEO_SINK_CAST (bsink); GstVideoFrame vframe; IDeckLinkMutableVideoFrame *frame; guint8 *outdata, *indata; GstFlowReturn flow_ret; HRESULT ret; GstClockTime timestamp, duration; GstClockTime running_time, running_time_duration; gint i; GstClock *clock; GST_DEBUG_OBJECT (self, "Preparing buffer %p", buffer); // FIXME: Handle no timestamps if (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) { return GST_FLOW_ERROR; } timestamp = GST_BUFFER_TIMESTAMP (buffer); duration = GST_BUFFER_DURATION (buffer); if (duration == GST_CLOCK_TIME_NONE) { duration = gst_util_uint64_scale_int (GST_SECOND, self->info.fps_d, self->info.fps_n); } running_time = gst_segment_to_running_time (&GST_BASE_SINK_CAST (self)->segment, GST_FORMAT_TIME, timestamp); running_time_duration = gst_segment_to_running_time (&GST_BASE_SINK_CAST (self)->segment, GST_FORMAT_TIME, timestamp + duration) - running_time; // FIXME: https://bugzilla.gnome.org/show_bug.cgi?id=742916 // We need to drop late buffers here immediately instead of // potentially overflowing the internal queue of the hardware clock = gst_element_get_clock (GST_ELEMENT_CAST (self)); if (clock) { GstClockTime clock_running_time, base_time, clock_time, latency, max_lateness; base_time = gst_element_get_base_time (GST_ELEMENT_CAST (self)); clock_time = gst_clock_get_time (clock); if (base_time != GST_CLOCK_TIME_NONE && clock_time != GST_CLOCK_TIME_NONE) { clock_running_time = clock_time - base_time; latency = gst_base_sink_get_latency (GST_BASE_SINK_CAST (self)); max_lateness = gst_base_sink_get_max_lateness (GST_BASE_SINK_CAST (self)); if (clock_running_time > running_time + running_time_duration + latency + max_lateness) { GST_DEBUG_OBJECT (self, "Late buffer: %" GST_TIME_FORMAT " > %" GST_TIME_FORMAT, GST_TIME_ARGS (clock_running_time), GST_TIME_ARGS (running_time + running_time_duration)); if (self->last_render_time == GST_CLOCK_TIME_NONE || (self->last_render_time < clock_running_time && clock_running_time - self->last_render_time >= GST_SECOND)) { GST_DEBUG_OBJECT (self, "Rendering frame nonetheless because we had none for more than 1s"); running_time = clock_running_time; running_time_duration = 0; } else { GST_WARNING_OBJECT (self, "Dropping frame"); gst_object_unref (clock); return GST_FLOW_OK; } } } gst_object_unref (clock); } self->last_render_time = running_time; ret = self->output->output->CreateVideoFrame (self->info.width, self->info.height, self->info.stride[0], bmdFormat8BitYUV, bmdFrameFlagDefault, &frame); if (ret != S_OK) { GST_ELEMENT_ERROR (self, STREAM, FAILED, (NULL), ("Failed to create video frame: 0x%08x", ret)); return GST_FLOW_ERROR; } if (!gst_video_frame_map (&vframe, &self->info, buffer, GST_MAP_READ)) { GST_ERROR_OBJECT (self, "Failed to map video frame"); flow_ret = GST_FLOW_ERROR; goto out; } frame->GetBytes ((void **) &outdata); indata = (guint8 *) GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0); for (i = 0; i < self->info.height; i++) { memcpy (outdata, indata, GST_VIDEO_FRAME_WIDTH (&vframe) * 2); indata += GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 0); outdata += frame->GetRowBytes (); } gst_video_frame_unmap (&vframe); convert_to_internal_clock (self, &running_time, &running_time_duration); GST_LOG_OBJECT (self, "Scheduling video frame %p at %" GST_TIME_FORMAT " with duration %" GST_TIME_FORMAT, frame, GST_TIME_ARGS (running_time), GST_TIME_ARGS (running_time_duration)); ret = self->output->output->ScheduleVideoFrame (frame, running_time, running_time_duration, GST_SECOND); if (ret != S_OK) { GST_ELEMENT_ERROR (self, STREAM, FAILED, (NULL), ("Failed to schedule frame: 0x%08x", ret)); flow_ret = GST_FLOW_ERROR; goto out; } flow_ret = GST_FLOW_OK; out: frame->Release (); return flow_ret; }
static void deinterlace_frame_di_greedyh_planar (GstDeinterlaceMethod * method, const GstDeinterlaceField * history, guint history_count, GstVideoFrame * outframe, int cur_field_idx) { GstDeinterlaceMethodGreedyH *self = GST_DEINTERLACE_METHOD_GREEDY_H (method); GstDeinterlaceMethodGreedyHClass *klass = GST_DEINTERLACE_METHOD_GREEDY_H_GET_CLASS (self); gint InfoIsOdd; gint RowStride; gint FieldHeight; gint Pitch; const guint8 *L1; // ptr to Line1, of 3 const guint8 *L2; // ptr to Line2, the weave line const guint8 *L3; // ptr to Line3 const guint8 *L2P; // ptr to prev Line2 guint8 *Dest; gint i; ScanlineFunction scanline; if (cur_field_idx + 2 > history_count || cur_field_idx < 1) { GstDeinterlaceMethod *backup_method; backup_method = g_object_new (gst_deinterlace_method_linear_get_type (), NULL); gst_deinterlace_method_setup (backup_method, method->vinfo); gst_deinterlace_method_deinterlace_frame (backup_method, history, history_count, outframe, cur_field_idx); g_object_unref (backup_method); return; } cur_field_idx += 2; for (i = 0; i < 3; i++) { InfoIsOdd = (history[cur_field_idx - 1].flags == PICTURE_INTERLACED_BOTTOM); RowStride = GST_VIDEO_FRAME_PLANE_STRIDE (outframe, i); FieldHeight = GST_VIDEO_FRAME_HEIGHT (outframe) / 2; Pitch = RowStride * 2; if (i == 0) scanline = klass->scanline_planar_y; else scanline = klass->scanline_planar_uv; Dest = GST_VIDEO_FRAME_PLANE_DATA (outframe, i); L1 = GST_VIDEO_FRAME_PLANE_DATA (history[cur_field_idx - 2].frame, i); if (history[cur_field_idx - 2].flags & PICTURE_INTERLACED_BOTTOM) L1 += RowStride; L2 = GST_VIDEO_FRAME_PLANE_DATA (history[cur_field_idx - 1].frame, i); if (history[cur_field_idx - 1].flags & PICTURE_INTERLACED_BOTTOM) L2 += RowStride; L3 = L1 + Pitch; L2P = GST_VIDEO_FRAME_PLANE_DATA (history[cur_field_idx - 3].frame, i); if (history[cur_field_idx - 3].flags & PICTURE_INTERLACED_BOTTOM) L2P += RowStride; deinterlace_frame_di_greedyh_planar_plane (self, L1, L2, L3, L2P, Dest, RowStride, FieldHeight, Pitch, InfoIsOdd, scanline); } }
static int gst_libde265_dec_get_buffer (de265_decoder_context * ctx, struct de265_image_spec *spec, struct de265_image *img, void *userdata) { GstVideoDecoder *base = (GstVideoDecoder *) userdata; GstLibde265Dec *dec = GST_LIBDE265_DEC (base); GstVideoCodecFrame *frame = NULL; int i; int width = spec->width; int height = spec->height; GstFlowReturn ret; struct GstLibde265FrameRef *ref; GstVideoInfo *info; int frame_number; frame_number = (uintptr_t) de265_get_image_user_data (img) - 1; if (G_UNLIKELY (frame_number == -1)) { /* should not happen... */ GST_WARNING_OBJECT (base, "Frame has no number assigned!"); goto fallback; } frame = gst_video_decoder_get_frame (base, frame_number); if (G_UNLIKELY (frame == NULL)) { /* should not happen... */ GST_WARNING_OBJECT (base, "Couldn't get codec frame!"); goto fallback; } if (width % spec->alignment) { width += spec->alignment - (width % spec->alignment); } if (width != spec->visible_width || height != spec->visible_height) { /* clipping not supported for now */ goto fallback; } ret = _gst_libde265_image_available (base, width, height); if (G_UNLIKELY (ret != GST_FLOW_OK)) { GST_ERROR_OBJECT (dec, "Failed to notify about available image"); goto fallback; } ret = gst_video_decoder_allocate_output_frame (GST_VIDEO_DECODER (dec), frame); if (G_UNLIKELY (ret != GST_FLOW_OK)) { GST_ERROR_OBJECT (dec, "Failed to allocate output buffer"); goto fallback; } ref = (struct GstLibde265FrameRef *) g_malloc0 (sizeof (*ref)); g_assert (ref != NULL); ref->decoder = base; ref->frame = frame; gst_buffer_replace (&ref->buffer, frame->output_buffer); gst_buffer_replace (&frame->output_buffer, NULL); info = &dec->output_state->info; if (!gst_video_frame_map (&ref->vframe, info, ref->buffer, GST_MAP_READWRITE)) { GST_ERROR_OBJECT (dec, "Failed to map frame output buffer"); goto error; } ref->mapped = TRUE; if (GST_VIDEO_FRAME_PLANE_STRIDE (&ref->vframe, 0) < width * GST_VIDEO_FRAME_COMP_PSTRIDE (&ref->vframe, 0)) { GST_DEBUG_OBJECT (dec, "plane 0: pitch too small (%d/%d*%d)", GST_VIDEO_FRAME_PLANE_STRIDE (&ref->vframe, 0), width, GST_VIDEO_FRAME_COMP_PSTRIDE (&ref->vframe, 0)); goto error; } if (GST_VIDEO_FRAME_COMP_HEIGHT (&ref->vframe, 0) < height) { GST_DEBUG_OBJECT (dec, "plane 0: lines too few (%d/%d)", GST_VIDEO_FRAME_COMP_HEIGHT (&ref->vframe, 0), height); goto error; } for (i = 0; i < 3; i++) { uint8_t *data; int stride = GST_VIDEO_FRAME_PLANE_STRIDE (&ref->vframe, i); if (stride % spec->alignment) { GST_DEBUG_OBJECT (dec, "plane %d: pitch not aligned (%d%%%d)", i, stride, spec->alignment); goto error; } data = GST_VIDEO_FRAME_PLANE_DATA (&ref->vframe, i); if ((uintptr_t) (data) % spec->alignment) { GST_DEBUG_OBJECT (dec, "plane %d not aligned", i); goto error; } de265_set_image_plane (img, i, data, stride, ref); } return 1; error: gst_libde265_dec_release_frame_ref (ref); frame = NULL; fallback: if (frame != NULL) { gst_video_codec_frame_unref (frame); } return de265_get_default_image_allocation_functions ()->get_buffer (ctx, spec, img, userdata); }
static GstFlowReturn gst_decklink_video_sink_prepare (GstBaseSink * bsink, GstBuffer * buffer) { GstDecklinkVideoSink *self = GST_DECKLINK_VIDEO_SINK_CAST (bsink); GstVideoFrame vframe; IDeckLinkMutableVideoFrame *frame; guint8 *outdata, *indata; GstFlowReturn flow_ret; HRESULT ret; GstClockTime timestamp, duration; GstClockTime running_time, running_time_duration; GstClockTime latency, render_delay; GstClockTimeDiff ts_offset; gint i; GstDecklinkVideoFormat caps_format; BMDPixelFormat format; gint bpp; GstVideoTimeCodeMeta *tc_meta; GST_DEBUG_OBJECT (self, "Preparing buffer %p", buffer); // FIXME: Handle no timestamps if (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) { return GST_FLOW_ERROR; } caps_format = gst_decklink_type_from_video_format (self->info.finfo->format); format = gst_decklink_pixel_format_from_type (caps_format); bpp = gst_decklink_bpp_from_type (caps_format); timestamp = GST_BUFFER_TIMESTAMP (buffer); duration = GST_BUFFER_DURATION (buffer); if (duration == GST_CLOCK_TIME_NONE) { duration = gst_util_uint64_scale_int (GST_SECOND, self->info.fps_d, self->info.fps_n); } running_time = gst_segment_to_running_time (&GST_BASE_SINK_CAST (self)->segment, GST_FORMAT_TIME, timestamp); running_time_duration = gst_segment_to_running_time (&GST_BASE_SINK_CAST (self)->segment, GST_FORMAT_TIME, timestamp + duration) - running_time; /* See gst_base_sink_adjust_time() */ latency = gst_base_sink_get_latency (bsink); render_delay = gst_base_sink_get_render_delay (bsink); ts_offset = gst_base_sink_get_ts_offset (bsink); running_time += latency; if (ts_offset < 0) { ts_offset = -ts_offset; if ((GstClockTime) ts_offset < running_time) running_time -= ts_offset; else running_time = 0; } else { running_time += ts_offset; } if (running_time > render_delay) running_time -= render_delay; else running_time = 0; ret = self->output->output->CreateVideoFrame (self->info.width, self->info.height, self->info.stride[0], format, bmdFrameFlagDefault, &frame); if (ret != S_OK) { GST_ELEMENT_ERROR (self, STREAM, FAILED, (NULL), ("Failed to create video frame: 0x%08x", ret)); return GST_FLOW_ERROR; } if (!gst_video_frame_map (&vframe, &self->info, buffer, GST_MAP_READ)) { GST_ERROR_OBJECT (self, "Failed to map video frame"); flow_ret = GST_FLOW_ERROR; goto out; } frame->GetBytes ((void **) &outdata); indata = (guint8 *) GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0); for (i = 0; i < self->info.height; i++) { memcpy (outdata, indata, GST_VIDEO_FRAME_WIDTH (&vframe) * bpp); indata += GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 0); outdata += frame->GetRowBytes (); } gst_video_frame_unmap (&vframe); tc_meta = gst_buffer_get_video_time_code_meta (buffer); if (tc_meta) { BMDTimecodeFlags bflags = (BMDTimecodeFlags) 0; gchar *tc_str; if (((GstVideoTimeCodeFlags) (tc_meta->tc. config.flags)) & GST_VIDEO_TIME_CODE_FLAGS_DROP_FRAME) bflags = (BMDTimecodeFlags) (bflags | bmdTimecodeIsDropFrame); else bflags = (BMDTimecodeFlags) (bflags | bmdTimecodeFlagDefault); if (tc_meta->tc.field_count == 2) bflags = (BMDTimecodeFlags) (bflags | bmdTimecodeFieldMark); tc_str = gst_video_time_code_to_string (&tc_meta->tc); ret = frame->SetTimecodeFromComponents (self->timecode_format, (uint8_t) tc_meta->tc.hours, (uint8_t) tc_meta->tc.minutes, (uint8_t) tc_meta->tc.seconds, (uint8_t) tc_meta->tc.frames, bflags); if (ret != S_OK) { GST_ERROR_OBJECT (self, "Failed to set timecode %s to video frame: 0x%08x", tc_str, ret); flow_ret = GST_FLOW_ERROR; g_free (tc_str); goto out; } GST_DEBUG_OBJECT (self, "Set frame timecode to %s", tc_str); g_free (tc_str); } convert_to_internal_clock (self, &running_time, &running_time_duration); GST_LOG_OBJECT (self, "Scheduling video frame %p at %" GST_TIME_FORMAT " with duration %" GST_TIME_FORMAT, frame, GST_TIME_ARGS (running_time), GST_TIME_ARGS (running_time_duration)); ret = self->output->output->ScheduleVideoFrame (frame, running_time, running_time_duration, GST_SECOND); if (ret != S_OK) { GST_ELEMENT_ERROR (self, STREAM, FAILED, (NULL), ("Failed to schedule frame: 0x%08x", ret)); flow_ret = GST_FLOW_ERROR; goto out; } flow_ret = GST_FLOW_OK; out: frame->Release (); return flow_ret; }
static GstFlowReturn gst_rsvg_decode_image (GstRsvgDec * rsvg, GstBuffer * buffer, GstVideoCodecFrame * frame) { GstVideoDecoder *decoder = GST_VIDEO_DECODER (rsvg); GstFlowReturn ret = GST_FLOW_OK; cairo_t *cr; cairo_surface_t *surface; RsvgHandle *handle; GError *error = NULL; RsvgDimensionData dimension; gdouble scalex, scaley; GstMapInfo minfo; GstVideoFrame vframe; GstVideoCodecState *output_state; GST_LOG_OBJECT (rsvg, "parsing svg"); if (!gst_buffer_map (buffer, &minfo, GST_MAP_READ)) { GST_ERROR_OBJECT (rsvg, "Failed to get SVG image"); return GST_FLOW_ERROR; } handle = rsvg_handle_new_from_data (minfo.data, minfo.size, &error); if (!handle) { GST_ERROR_OBJECT (rsvg, "Failed to parse SVG image: %s", error->message); g_error_free (error); return GST_FLOW_ERROR; } rsvg_handle_get_dimensions (handle, &dimension); output_state = gst_video_decoder_get_output_state (decoder); if ((output_state == NULL) || GST_VIDEO_INFO_WIDTH (&output_state->info) != dimension.width || GST_VIDEO_INFO_HEIGHT (&output_state->info) != dimension.height) { /* Create the output state */ if (output_state) gst_video_codec_state_unref (output_state); output_state = gst_video_decoder_set_output_state (decoder, GST_RSVG_VIDEO_FORMAT, dimension.width, dimension.height, rsvg->input_state); } ret = gst_video_decoder_allocate_output_frame (decoder, frame); if (ret != GST_FLOW_OK) { g_object_unref (handle); gst_video_codec_state_unref (output_state); GST_ERROR_OBJECT (rsvg, "Buffer allocation failed %s", gst_flow_get_name (ret)); return ret; } GST_LOG_OBJECT (rsvg, "render image at %d x %d", GST_VIDEO_INFO_HEIGHT (&output_state->info), GST_VIDEO_INFO_WIDTH (&output_state->info)); if (!gst_video_frame_map (&vframe, &output_state->info, frame->output_buffer, GST_MAP_READWRITE)) { GST_ERROR_OBJECT (rsvg, "Failed to get SVG image"); g_object_unref (handle); gst_video_codec_state_unref (output_state); return GST_FLOW_ERROR; } surface = cairo_image_surface_create_for_data (GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0), CAIRO_FORMAT_ARGB32, GST_VIDEO_FRAME_WIDTH (&vframe), GST_VIDEO_FRAME_HEIGHT (&vframe), GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 0)); cr = cairo_create (surface); cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0); cairo_paint (cr); cairo_set_operator (cr, CAIRO_OPERATOR_OVER); cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0); scalex = scaley = 1.0; if (GST_VIDEO_INFO_WIDTH (&output_state->info) != dimension.width) { scalex = ((gdouble) GST_VIDEO_INFO_WIDTH (&output_state->info)) / ((gdouble) dimension.width); } if (GST_VIDEO_INFO_HEIGHT (&output_state->info) != dimension.height) { scaley = ((gdouble) GST_VIDEO_INFO_HEIGHT (&output_state->info)) / ((gdouble) dimension.height); } cairo_scale (cr, scalex, scaley); rsvg_handle_render_cairo (handle, cr); g_object_unref (handle); cairo_destroy (cr); cairo_surface_destroy (surface); /* Now unpremultiply Cairo's ARGB to match GStreamer's */ gst_rsvg_decode_unpremultiply (GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0), GST_VIDEO_FRAME_WIDTH (&vframe), GST_VIDEO_FRAME_HEIGHT (&vframe)); gst_video_codec_state_unref (output_state); gst_buffer_unmap (buffer, &minfo); gst_video_frame_unmap (&vframe); return ret; }
static void gst_validate_ssim_save_out (GstValidateSsim * self, GstBuffer * buffer, const gchar * ref_file, const gchar * file, const gchar * outfolder) { GstVideoFrame frame, converted; if (!g_file_test (outfolder, G_FILE_TEST_IS_DIR)) { if (g_mkdir_with_parents (outfolder, 0755) != 0) { GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR, "Could not create output directory %s", outfolder); return; } } if (self->priv->outconverter_info.converter == NULL || self->priv->width != self->priv->outconverter_info.out_info.width || self->priv->height != self->priv->outconverter_info.out_info.height) { if (self->priv->outconverter_info.converter) gst_video_converter_free (self->priv->outconverter_info.converter); gst_video_info_init (&self->priv->outconverter_info.in_info); gst_video_info_set_format (&self->priv->outconverter_info.in_info, GST_VIDEO_FORMAT_GRAY8, self->priv->width, self->priv->height); gst_video_info_init (&self->priv->outconverter_info.out_info); gst_video_info_set_format (&self->priv->outconverter_info.out_info, GST_VIDEO_FORMAT_RGBx, self->priv->width, self->priv->height); self->priv->outconverter_info.converter = gst_video_converter_new (&self->priv->outconverter_info.in_info, &self->priv->outconverter_info.out_info, NULL); } if (!gst_video_frame_map (&frame, &self->priv->outconverter_info.in_info, buffer, GST_MAP_READ)) { GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR, "Could not map output frame"); return; } if (gst_validate_ssim_convert (self, &self->priv->outconverter_info, &frame, &converted)) { cairo_status_t status; cairo_surface_t *surface; gchar *bn1 = g_path_get_basename (ref_file); gchar *bn2 = g_path_get_basename (file); gchar *fname = g_strdup_printf ("%s.VS.%s.result.png", bn1, bn2); gchar *outfile = g_build_path (G_DIR_SEPARATOR_S, outfolder, fname, NULL); surface = cairo_image_surface_create_for_data (GST_VIDEO_FRAME_PLANE_DATA (&converted, 0), CAIRO_FORMAT_RGB24, GST_VIDEO_FRAME_WIDTH (&converted), GST_VIDEO_FRAME_HEIGHT (&converted), GST_VIDEO_FRAME_PLANE_STRIDE (&converted, 0)); if ((status = cairo_surface_write_to_png (surface, outfile)) != CAIRO_STATUS_SUCCESS) { GST_VALIDATE_REPORT (self, GENERAL_INPUT_ERROR, "Could not save '%s', cairo status is '%s'", outfile, cairo_status_to_string (status)); } cairo_surface_destroy (surface); gst_video_frame_unmap (&frame); gst_video_frame_unmap (&converted); g_free (bn1); g_free (bn2); g_free (fname); g_free (outfile); } }