1 /*
2  INTEL CONFIDENTIAL
3  Copyright 2009 Intel Corporation All Rights Reserved.
4  The source code contained or described herein and all documents related to the source code ("Material") are owned by Intel Corporation or its suppliers or licensors. Title to the Material remains with Intel Corporation or its suppliers and licensors. The Material contains trade secrets and proprietary and confidential information of Intel or its suppliers and licensors. The Material is protected by worldwide copyright and trade secret laws and treaty provisions. No part of the Material may be used, copied, reproduced, modified, published, uploaded, posted, transmitted, distributed, or disclosed in any way without Intel’s prior express written permission.
5 
6  No license under any patent, copyright, trade secret or other intellectual property right is granted to or conferred upon you by disclosure or delivery of the Materials, either expressly, by implication, inducement, estoppel or otherwise. Any license under such intellectual property rights must be express and approved by Intel in writing.
7  */
8 
9 /**
10  * SECTION:mixvideoframe
11  * @short_description: VideoConfig parameters
12  *
13  * A data object which stores videoconfig specific parameters.
14  */
15 
16 
17 #include <va/va.h>
18 #include <va/va_x11.h>
19 #include "mixvideolog.h"
20 #include "mixvideoframe.h"
21 #include "mixvideoframe_private.h"
22 
23 #define SAFE_FREE(p) if(p) { g_free(p); p = NULL; }
24 
25 static GType _mix_videoframe_type = 0;
26 static MixParamsClass *parent_class = NULL;
27 
28 #define _do_init { _mix_videoframe_type = g_define_type_id; }
29 
30 gboolean mix_videoframe_copy(MixParams * target, const MixParams * src);
31 MixParams *mix_videoframe_dup(const MixParams * obj);
32 gboolean mix_videoframe_equal(MixParams * first, MixParams * second);
33 static void mix_videoframe_finalize(MixParams * obj);
34 
35 G_DEFINE_TYPE_WITH_CODE (MixVideoFrame, mix_videoframe, MIX_TYPE_PARAMS,
36 		_do_init);
37 
38 #define VIDEOFRAME_PRIVATE(self) ((MixVideoFramePrivate *)((self)->reserved1))
mix_videoframe_init(MixVideoFrame * self)39 static void mix_videoframe_init(MixVideoFrame * self) {
40 	/* initialize properties here */
41 	self->frame_id = VA_INVALID_SURFACE;
42 	self->timestamp = 0;
43 	self->discontinuity = FALSE;
44 	self->frame_structure = VA_FRAME_PICTURE;
45 
46 	MixVideoFramePrivate *priv = MIX_VIDEOFRAME_GET_PRIVATE(self);
47 	self->reserved1 = priv;
48 	self->reserved2 = NULL;
49 	self->reserved3 = NULL;
50 	self->reserved4 = NULL;
51 
52 	/* set pool pointer in private structure to NULL */
53 	priv -> pool = NULL;
54 
55 	/* set stuff for skipped frames */
56 	priv -> is_skipped = FALSE;
57 	priv -> real_frame = NULL;
58 
59 	g_static_rec_mutex_init (&priv -> lock);
60 
61 }
62 
mix_videoframe_class_init(MixVideoFrameClass * klass)63 static void mix_videoframe_class_init(MixVideoFrameClass * klass) {
64 	MixParamsClass *mixparams_class = MIX_PARAMS_CLASS(klass);
65 
66 	/* setup static parent class */
67 	parent_class = (MixParamsClass *) g_type_class_peek_parent(klass);
68 
69 	mixparams_class->finalize = mix_videoframe_finalize;
70 	mixparams_class->copy = (MixParamsCopyFunction) mix_videoframe_copy;
71 	mixparams_class->dup = (MixParamsDupFunction) mix_videoframe_dup;
72 	mixparams_class->equal = (MixParamsEqualFunction) mix_videoframe_equal;
73 
74 	/* Register and allocate the space the private structure for this object */
75 	g_type_class_add_private(mixparams_class, sizeof(MixVideoFramePrivate));
76 
77 }
78 
79 MixVideoFrame *
mix_videoframe_new(void)80 mix_videoframe_new(void) {
81 	MixVideoFrame *ret = (MixVideoFrame *) g_type_create_instance(
82 			MIX_TYPE_VIDEOFRAME);
83 	return ret;
84 }
85 
mix_videoframe_finalize(MixParams * obj)86 void mix_videoframe_finalize(MixParams * obj) {
87 	/* clean up here. */
88 	MixVideoFrame *self = MIX_VIDEOFRAME (obj);
89 	MixVideoFramePrivate *priv = VIDEOFRAME_PRIVATE(self);
90 
91 	g_static_rec_mutex_free (&priv->lock);
92 
93 	/* Chain up parent */
94 	if (parent_class->finalize) {
95 		parent_class->finalize(obj);
96 	}
97 }
98 
99 MixVideoFrame *
mix_videoframe_ref(MixVideoFrame * obj)100 mix_videoframe_ref(MixVideoFrame * obj) {
101 
102 	MixVideoFrame *ret = NULL;
103 	MixVideoFramePrivate *priv = VIDEOFRAME_PRIVATE(obj);
104 	g_static_rec_mutex_lock(&priv->lock);
105 	LOG_I("obj %x, new refcount is %d\n", (guint) obj,
106 			MIX_PARAMS(obj)->refcount + 1);
107 
108 	ret = (MixVideoFrame *) mix_params_ref(MIX_PARAMS(obj));
109 	g_static_rec_mutex_unlock (&priv->lock);
110 	return ret;
111 }
112 
mix_videoframe_unref(MixVideoFrame * obj)113 void mix_videoframe_unref(MixVideoFrame * obj) {
114 
115 	if(obj == NULL) {
116 		LOG_E("obj is NULL\n");
117 		return;
118 	}
119 
120 	MixVideoFramePrivate *priv = VIDEOFRAME_PRIVATE(obj);
121 	g_static_rec_mutex_lock(&priv->lock);
122 
123 	LOG_I("obj %x, frame id %d, new refcount is %d\n", (guint) obj,
124 			(guint) obj->frame_id, MIX_PARAMS(obj)->refcount - 1);
125 
126 	// Check if we have reduced to 1, in which case we add ourselves to free pool
127 	// but only do this for real frames, not skipped frames
128 	if (((MIX_PARAMS(obj)->refcount - 1) == 1) && (!(priv -> is_skipped))) {
129 
130 		LOG_I("Adding obj %x, frame id %d back to pool\n", (guint) obj,
131 				(guint) obj->frame_id);
132 
133 		MixSurfacePool *pool = NULL;
134 		pool = priv -> pool;
135 		if(pool == NULL) {
136 			LOG_E("pool is NULL\n");
137 			g_static_rec_mutex_unlock (&priv->lock);
138 			return;
139 		}
140 		mix_surfacepool_put(pool, obj);
141 	}
142 
143 	//If this is a skipped frame that is being deleted, release the real frame
144 	if (((MIX_PARAMS(obj)->refcount - 1) == 0) && (priv -> is_skipped)) {
145 
146 		LOG_I("skipped frame obj %x, releasing real frame %x \n",
147 				(guint) obj, (guint) priv->real_frame);
148 
149 		mix_videoframe_unref(priv -> real_frame);
150 	}
151 
152 	// Unref through base class
153 	mix_params_unref(MIX_PARAMS(obj));
154 	g_static_rec_mutex_unlock (&priv->lock);
155 }
156 
157 /**
158  * mix_videoframe_dup:
159  * @obj: a #MixVideoFrame object
160  * @returns: a newly allocated duplicate of the object.
161  *
162  * Copy duplicate of the object.
163  */
164 MixParams *
mix_videoframe_dup(const MixParams * obj)165 mix_videoframe_dup(const MixParams * obj) {
166 	MixParams *ret = NULL;
167 
168 	if (MIX_IS_VIDEOFRAME(obj)) {
169 		MixVideoFrame *duplicate = mix_videoframe_new();
170 		if (mix_videoframe_copy(MIX_PARAMS(duplicate), MIX_PARAMS(obj))) {
171 			ret = MIX_PARAMS(duplicate);
172 		} else {
173 			mix_videoframe_unref(duplicate);
174 		}
175 	}
176 	return ret;
177 }
178 
179 /**
180  * mix_videoframe_copy:
181  * @target: copy to target
182  * @src: copy from src
183  * @returns: boolean indicates if copy is successful.
184  *
185  * Copy instance data from @src to @target.
186  */
mix_videoframe_copy(MixParams * target,const MixParams * src)187 gboolean mix_videoframe_copy(MixParams * target, const MixParams * src) {
188 	MixVideoFrame *this_target, *this_src;
189 
190 	if (MIX_IS_VIDEOFRAME(target) && MIX_IS_VIDEOFRAME(src)) {
191 		// Cast the base object to this child object
192 		this_target = MIX_VIDEOFRAME(target);
193 		this_src = MIX_VIDEOFRAME(src);
194 
195 		// Free the existing properties
196 
197 		// Duplicate string
198 		this_target->frame_id = this_src->frame_id;
199 		this_target->timestamp = this_src->timestamp;
200 		this_target->discontinuity = this_src->discontinuity;
201 		this_target->frame_structure = this_src->frame_structure;
202 
203 		// Now chainup base class
204 		if (parent_class->copy) {
205 			return parent_class->copy(MIX_PARAMS_CAST(target), MIX_PARAMS_CAST(
206 					src));
207 		} else {
208 			return TRUE;
209 		}
210 	}
211 	return FALSE;
212 }
213 
214 /**
215  * mix_videoframe_equal:
216  * @first: first object to compare
217  * @second: seond object to compare
218  * @returns: boolean indicates if instance are equal.
219  *
220  * Copy instance data from @src to @target.
221  */
mix_videoframe_equal(MixParams * first,MixParams * second)222 gboolean mix_videoframe_equal(MixParams * first, MixParams * second) {
223 	gboolean ret = FALSE;
224 	MixVideoFrame *this_first, *this_second;
225 
226 	if (MIX_IS_VIDEOFRAME(first) && MIX_IS_VIDEOFRAME(second)) {
227 		// Deep compare
228 		// Cast the base object to this child object
229 
230 		this_first = MIX_VIDEOFRAME(first);
231 		this_second = MIX_VIDEOFRAME(second);
232 
233 		/* TODO: add comparison for other properties */
234 		if (this_first->frame_id == this_second->frame_id
235 				&& this_first->timestamp == this_second->timestamp
236 				&& this_first->discontinuity == this_second->discontinuity
237 				&& this_first->frame_structure == this_second->frame_structure) {
238 			// members within this scope equal. chaining up.
239 			MixParamsClass *klass = MIX_PARAMS_CLASS(parent_class);
240 			if (klass->equal)
241 				ret = klass->equal(first, second);
242 			else
243 				ret = TRUE;
244 		}
245 	}
246 
247 	return ret;
248 }
249 
250 #define MIX_VIDEOFRAME_SETTER_CHECK_INPUT(obj) \
251 	if(!obj) return MIX_RESULT_NULL_PTR; \
252 	if(!MIX_IS_VIDEOFRAME(obj)) return MIX_RESULT_FAIL; \
253 
254 #define MIX_VIDEOFRAME_GETTER_CHECK_INPUT(obj, prop) \
255 	if(!obj || !prop) return MIX_RESULT_NULL_PTR; \
256 	if(!MIX_IS_VIDEOFRAME(obj)) return MIX_RESULT_FAIL; \
257 
258 
259 /* TODO: Add getters and setters for other properties. The following is just an exmaple, not implemented yet. */
mix_videoframe_set_frame_id(MixVideoFrame * obj,gulong frame_id)260 MIX_RESULT mix_videoframe_set_frame_id(MixVideoFrame * obj, gulong frame_id) {
261 	MIX_VIDEOFRAME_SETTER_CHECK_INPUT (obj);
262 	obj->frame_id = frame_id;
263 
264 	return MIX_RESULT_SUCCESS;
265 }
266 
mix_videoframe_get_frame_id(MixVideoFrame * obj,gulong * frame_id)267 MIX_RESULT mix_videoframe_get_frame_id(MixVideoFrame * obj, gulong * frame_id) {
268 	MIX_VIDEOFRAME_GETTER_CHECK_INPUT (obj, frame_id);
269 	*frame_id = obj->frame_id;
270 	return MIX_RESULT_SUCCESS;
271 }
272 
mix_videoframe_set_ci_frame_idx(MixVideoFrame * obj,guint ci_frame_idx)273 MIX_RESULT mix_videoframe_set_ci_frame_idx (MixVideoFrame * obj, guint ci_frame_idx) {
274 	MIX_VIDEOFRAME_SETTER_CHECK_INPUT (obj);
275 	obj->ci_frame_idx = ci_frame_idx;
276 
277 	return MIX_RESULT_SUCCESS;
278 }
279 
mix_videoframe_get_ci_frame_idx(MixVideoFrame * obj,guint * ci_frame_idx)280 MIX_RESULT mix_videoframe_get_ci_frame_idx (MixVideoFrame * obj, guint * ci_frame_idx) {
281 	MIX_VIDEOFRAME_GETTER_CHECK_INPUT (obj, ci_frame_idx);
282 	*ci_frame_idx = obj->ci_frame_idx;
283 	return MIX_RESULT_SUCCESS;
284 }
285 
mix_videoframe_set_timestamp(MixVideoFrame * obj,guint64 timestamp)286 MIX_RESULT mix_videoframe_set_timestamp(MixVideoFrame * obj, guint64 timestamp) {
287 	MIX_VIDEOFRAME_SETTER_CHECK_INPUT (obj);
288 
289 	obj->timestamp = timestamp;
290 
291 	return MIX_RESULT_SUCCESS;
292 }
293 
mix_videoframe_get_timestamp(MixVideoFrame * obj,guint64 * timestamp)294 MIX_RESULT mix_videoframe_get_timestamp(MixVideoFrame * obj,
295 		guint64 * timestamp) {
296 	MIX_VIDEOFRAME_GETTER_CHECK_INPUT (obj, timestamp);
297 	*timestamp = obj->timestamp;
298 	return MIX_RESULT_SUCCESS;
299 }
300 
mix_videoframe_set_discontinuity(MixVideoFrame * obj,gboolean discontinuity)301 MIX_RESULT mix_videoframe_set_discontinuity(MixVideoFrame * obj,
302 		gboolean discontinuity) {
303 	MIX_VIDEOFRAME_SETTER_CHECK_INPUT (obj);
304 	obj->discontinuity = discontinuity;
305 	return MIX_RESULT_SUCCESS;
306 }
307 
mix_videoframe_get_discontinuity(MixVideoFrame * obj,gboolean * discontinuity)308 MIX_RESULT mix_videoframe_get_discontinuity(MixVideoFrame * obj,
309 		gboolean * discontinuity) {
310 	MIX_VIDEOFRAME_GETTER_CHECK_INPUT (obj, discontinuity);
311 	*discontinuity = obj->discontinuity;
312 	return MIX_RESULT_SUCCESS;
313 }
314 
mix_videoframe_set_frame_structure(MixVideoFrame * obj,guint32 frame_structure)315 MIX_RESULT mix_videoframe_set_frame_structure(MixVideoFrame * obj,
316 		guint32 frame_structure) {
317 	MIX_VIDEOFRAME_SETTER_CHECK_INPUT (obj);
318 	obj->frame_structure = frame_structure;
319 	return MIX_RESULT_SUCCESS;
320 }
321 
mix_videoframe_get_frame_structure(MixVideoFrame * obj,guint32 * frame_structure)322 MIX_RESULT mix_videoframe_get_frame_structure(MixVideoFrame * obj,
323 		guint32* frame_structure) {
324 	MIX_VIDEOFRAME_GETTER_CHECK_INPUT (obj, frame_structure);
325 	*frame_structure = obj->frame_structure;
326 	return MIX_RESULT_SUCCESS;
327 }
328 
mix_videoframe_set_pool(MixVideoFrame * obj,MixSurfacePool * pool)329 MIX_RESULT mix_videoframe_set_pool(MixVideoFrame * obj, MixSurfacePool * pool) {
330 
331 	/* set pool pointer in private structure */
332 	VIDEOFRAME_PRIVATE(obj) -> pool = pool;
333 
334 	return MIX_RESULT_SUCCESS;
335 }
336 
mix_videoframe_set_frame_type(MixVideoFrame * obj,MixFrameType frame_type)337 MIX_RESULT mix_videoframe_set_frame_type(MixVideoFrame *obj,
338 		MixFrameType frame_type) {
339 
340 	VIDEOFRAME_PRIVATE(obj) -> frame_type = frame_type;
341 
342 	return MIX_RESULT_SUCCESS;
343 }
344 
mix_videoframe_get_frame_type(MixVideoFrame * obj,MixFrameType * frame_type)345 MIX_RESULT mix_videoframe_get_frame_type(MixVideoFrame *obj,
346 		MixFrameType *frame_type) {
347 
348 	MIX_VIDEOFRAME_GETTER_CHECK_INPUT(obj, frame_type);
349 
350 	*frame_type = VIDEOFRAME_PRIVATE(obj) -> frame_type;
351 
352 	return MIX_RESULT_SUCCESS;
353 
354 }
355 
mix_videoframe_set_is_skipped(MixVideoFrame * obj,gboolean is_skipped)356 MIX_RESULT mix_videoframe_set_is_skipped(MixVideoFrame *obj,
357 		gboolean is_skipped) {
358 
359 	VIDEOFRAME_PRIVATE(obj) -> is_skipped = is_skipped;
360 
361 	return MIX_RESULT_SUCCESS;
362 }
363 
mix_videoframe_get_is_skipped(MixVideoFrame * obj,gboolean * is_skipped)364 MIX_RESULT mix_videoframe_get_is_skipped(MixVideoFrame *obj,
365 		gboolean *is_skipped) {
366 
367 	MIX_VIDEOFRAME_GETTER_CHECK_INPUT(obj, is_skipped);
368 
369 	*is_skipped = VIDEOFRAME_PRIVATE(obj) -> is_skipped;
370 
371 	return MIX_RESULT_SUCCESS;
372 }
373 
mix_videoframe_set_real_frame(MixVideoFrame * obj,MixVideoFrame * real)374 MIX_RESULT mix_videoframe_set_real_frame(MixVideoFrame *obj,
375 		MixVideoFrame *real) {
376 
377 	VIDEOFRAME_PRIVATE(obj) -> real_frame = real;
378 
379 	return MIX_RESULT_SUCCESS;
380 }
381 
mix_videoframe_get_real_frame(MixVideoFrame * obj,MixVideoFrame ** real)382 MIX_RESULT mix_videoframe_get_real_frame(MixVideoFrame *obj,
383 		MixVideoFrame **real) {
384 
385 	MIX_VIDEOFRAME_GETTER_CHECK_INPUT(obj, real);
386 
387 	*real = VIDEOFRAME_PRIVATE(obj) -> real_frame;
388 
389 	return MIX_RESULT_SUCCESS;
390 }
391 
392