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
25static GType _mix_videoframe_type = 0;
26static MixParamsClass *parent_class = NULL;
27
28#define _do_init { _mix_videoframe_type = g_define_type_id; }
29
30gboolean mix_videoframe_copy(MixParams * target, const MixParams * src);
31MixParams *mix_videoframe_dup(const MixParams * obj);
32gboolean mix_videoframe_equal(MixParams * first, MixParams * second);
33static void mix_videoframe_finalize(MixParams * obj);
34
35G_DEFINE_TYPE_WITH_CODE (MixVideoFrame, mix_videoframe, MIX_TYPE_PARAMS,
36		_do_init);
37
38#define VIDEOFRAME_PRIVATE(self) ((MixVideoFramePrivate *)((self)->reserved1))
39static 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
63static 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
79MixVideoFrame *
80mix_videoframe_new(void) {
81	MixVideoFrame *ret = (MixVideoFrame *) g_type_create_instance(
82			MIX_TYPE_VIDEOFRAME);
83	return ret;
84}
85
86void 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
99MixVideoFrame *
100mix_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
113void 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 */
164MixParams *
165mix_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 */
187gboolean 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 */
222gboolean 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. */
260MIX_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
267MIX_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
273MIX_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
280MIX_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
286MIX_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
294MIX_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
301MIX_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
308MIX_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
315MIX_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
322MIX_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
329MIX_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
337MIX_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
345MIX_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
356MIX_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
364MIX_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
374MIX_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
382MIX_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