static void transform_ayuv_ayuv (GstVideoFrame * frame, const gint * matrix) { guint8 *data; gsize size; gint y, u, v; gint yc[4]; gint uc[4]; gint vc[4]; if (matrix == NULL) return; data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); size = GST_VIDEO_FRAME_SIZE (frame); memcpy (yc, matrix, 4 * sizeof (gint)); memcpy (uc, matrix + 4, 4 * sizeof (gint)); memcpy (vc, matrix + 8, 4 * sizeof (gint)); while (size > 0) { y = (data[1] * yc[0] + data[2] * yc[1] + data[3] * yc[2] + yc[3]) >> 8; u = (data[1] * uc[0] + data[2] * uc[1] + data[3] * uc[2] + uc[3]) >> 8; v = (data[1] * vc[0] + data[2] * vc[1] + data[3] * vc[2] + vc[3]) >> 8; data[1] = y; data[2] = u; data[3] = v; data += 4; size -= 4; } }
static void transform_rgba_argb (GstVideoFrame * frame, const gint * matrix) { guint8 *data; gsize size; gint r, g, b; data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0); size = GST_VIDEO_FRAME_SIZE (frame); while (size > 0) { r = data[0]; g = data[1]; b = data[2]; data[0] = data[3]; data[1] = r; data[2] = g; data[3] = b; data += 4; size -= 4; } }
static GstFlowReturn gst_vtenc_encode_frame (GstVTEnc * self, GstBuffer * buf) { GstVTApi *vt = self->ctx->vt; CMTime ts, duration; GstCoreMediaMeta *meta; CVPixelBufferRef pbuf = NULL; VTStatus vt_status; GstFlowReturn ret = GST_FLOW_OK; guint i; self->cur_inbuf = buf; ts = CMTimeMake (GST_TIME_AS_MSECONDS (GST_BUFFER_TIMESTAMP (buf)), 1000); duration = CMTimeMake (GST_TIME_AS_MSECONDS (GST_BUFFER_DURATION (buf)), 1000); meta = gst_buffer_get_core_media_meta (buf); if (meta != NULL) { pbuf = gst_core_media_buffer_get_pixel_buffer (buf); } if (pbuf == NULL) { GstVTEncFrame *frame; CVReturn cv_ret; frame = gst_vtenc_frame_new (buf, &self->video_info); if (!frame) goto cv_error; { const size_t num_planes = GST_VIDEO_FRAME_N_PLANES (&frame->videoframe); void *plane_base_addresses[GST_VIDEO_MAX_PLANES]; size_t plane_widths[GST_VIDEO_MAX_PLANES]; size_t plane_heights[GST_VIDEO_MAX_PLANES]; size_t plane_bytes_per_row[GST_VIDEO_MAX_PLANES]; OSType pixel_format_type; size_t i; for (i = 0; i < num_planes; i++) { plane_base_addresses[i] = GST_VIDEO_FRAME_PLANE_DATA (&frame->videoframe, i); plane_widths[i] = GST_VIDEO_FRAME_COMP_WIDTH (&frame->videoframe, i); plane_heights[i] = GST_VIDEO_FRAME_COMP_HEIGHT (&frame->videoframe, i); plane_bytes_per_row[i] = GST_VIDEO_FRAME_COMP_STRIDE (&frame->videoframe, i); plane_bytes_per_row[i] = GST_VIDEO_FRAME_COMP_STRIDE (&frame->videoframe, i); } switch (GST_VIDEO_INFO_FORMAT (&self->video_info)) { case GST_VIDEO_FORMAT_I420: pixel_format_type = kCVPixelFormatType_420YpCbCr8Planar; break; case GST_VIDEO_FORMAT_NV12: pixel_format_type = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange; break; default: goto cv_error; } cv_ret = CVPixelBufferCreateWithPlanarBytes (NULL, self->negotiated_width, self->negotiated_height, pixel_format_type, frame, GST_VIDEO_FRAME_SIZE (&frame->videoframe), num_planes, plane_base_addresses, plane_widths, plane_heights, plane_bytes_per_row, gst_pixel_buffer_release_cb, frame, NULL, &pbuf); if (cv_ret != kCVReturnSuccess) { gst_vtenc_frame_free (frame); goto cv_error; } } } GST_OBJECT_LOCK (self); self->expect_keyframe = CFDictionaryContainsKey (self->options, *(vt->kVTEncodeFrameOptionKey_ForceKeyFrame)); if (self->expect_keyframe) gst_vtenc_clear_cached_caps_downstream (self); vt_status = self->ctx->vt->VTCompressionSessionEncodeFrame (self->session, pbuf, ts, duration, self->options, NULL, NULL); if (vt_status != 0) { GST_WARNING_OBJECT (self, "VTCompressionSessionEncodeFrame returned %d", vt_status); } self->ctx->vt->VTCompressionSessionCompleteFrames (self->session, kCMTimeInvalid); GST_OBJECT_UNLOCK (self); CVPixelBufferRelease (pbuf); self->cur_inbuf = NULL; gst_buffer_unref (buf); if (self->cur_outbufs->len > 0) { meta = gst_buffer_get_core_media_meta (g_ptr_array_index (self->cur_outbufs, 0)); if (!gst_vtenc_negotiate_downstream (self, meta->sample_buf)) ret = GST_FLOW_NOT_NEGOTIATED; } for (i = 0; i != self->cur_outbufs->len; i++) { GstBuffer *buf = g_ptr_array_index (self->cur_outbufs, i); if (ret == GST_FLOW_OK) { ret = gst_pad_push (self->srcpad, buf); } else { gst_buffer_unref (buf); } } g_ptr_array_set_size (self->cur_outbufs, 0); return ret; cv_error: { self->cur_inbuf = NULL; gst_buffer_unref (buf); return GST_FLOW_ERROR; } }