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 #include <glib.h>
9 #include "mixvideolog.h"
10 
11 #include "mixvideoformat.h"
12 
13 #define MIXUNREF(obj, unref) if(obj) { unref(obj); obj = NULL; }
14 
15 
16 /* Default vmethods implementation */
17 static MIX_RESULT mix_videofmt_getcaps_default(MixVideoFormat *mix,
18 		GString *msg);
19 static MIX_RESULT mix_videofmt_initialize_default(MixVideoFormat *mix,
20 		MixVideoConfigParamsDec * config_params,
21                 MixFrameManager * frame_mgr,
22 		MixBufferPool * input_buf_pool,
23 		MixSurfacePool ** surface_pool,
24                 VADisplay vadisplay);
25 static MIX_RESULT
26 		mix_videofmt_decode_default(MixVideoFormat *mix,
27 		MixBuffer * bufin[], gint bufincnt,
28                 MixVideoDecodeParams * decode_params);
29 static MIX_RESULT mix_videofmt_flush_default(MixVideoFormat *mix);
30 static MIX_RESULT mix_videofmt_eos_default(MixVideoFormat *mix);
31 static MIX_RESULT mix_videofmt_deinitialize_default(MixVideoFormat *mix);
32 
33 static GObjectClass *parent_class = NULL;
34 
35 static void mix_videoformat_finalize(GObject * obj);
36 G_DEFINE_TYPE (MixVideoFormat, mix_videoformat, G_TYPE_OBJECT);
37 
mix_videoformat_init(MixVideoFormat * self)38 static void mix_videoformat_init(MixVideoFormat * self) {
39 
40 	/* public member initialization */
41 	/* These are all public because MixVideoFormat objects are completely internal to MixVideo,
42 		no need for private members  */
43 
44 	self->initialized = FALSE;
45 	self->framemgr = NULL;
46 	self->surfacepool = NULL;
47 	self->inputbufpool = NULL;
48 	self->inputbufqueue = NULL;
49 	self->va_display = NULL;
50 	self->va_context = VA_INVALID_ID;
51 	self->va_config = VA_INVALID_ID;
52 	self->va_surfaces = NULL;
53 	self->va_num_surfaces = 0;
54 	self->mime_type = NULL;
55 	self->frame_rate_num = 0;
56 	self->frame_rate_denom = 0;
57 	self->picture_width = 0;
58 	self->picture_height = 0;
59 	self->parse_in_progress = FALSE;
60 	self->current_timestamp = 0;
61 }
62 
mix_videoformat_class_init(MixVideoFormatClass * klass)63 static void mix_videoformat_class_init(MixVideoFormatClass * klass) {
64 	GObjectClass *gobject_class = (GObjectClass *) klass;
65 
66 	/* parent class for later use */
67 	parent_class = g_type_class_peek_parent(klass);
68 
69 	gobject_class->finalize = mix_videoformat_finalize;
70 
71 	/* setup vmethods with base implementation */
72 	klass->getcaps = mix_videofmt_getcaps_default;
73 	klass->initialize = mix_videofmt_initialize_default;
74 	klass->decode = mix_videofmt_decode_default;
75 	klass->flush = mix_videofmt_flush_default;
76 	klass->eos = mix_videofmt_eos_default;
77 	klass->deinitialize = mix_videofmt_deinitialize_default;
78 }
79 
80 MixVideoFormat *
mix_videoformat_new(void)81 mix_videoformat_new(void) {
82 	MixVideoFormat *ret = g_object_new(MIX_TYPE_VIDEOFORMAT, NULL);
83 
84 	return ret;
85 }
86 
mix_videoformat_finalize(GObject * obj)87 void mix_videoformat_finalize(GObject * obj) {
88 	/* clean up here. */
89 	VAStatus va_status;
90 
91 	MixVideoFormat *mix = MIX_VIDEOFORMAT(obj);
92 	MixInputBufferEntry *buf_entry = NULL;
93 
94         if(mix->objectlock) {
95                 g_mutex_free(mix->objectlock);
96                 mix->objectlock = NULL;
97         }
98 
99 	if (mix->mime_type)
100 	{
101 		if (mix->mime_type->str)
102 			g_string_free(mix->mime_type, TRUE);
103 		else
104 			g_string_free(mix->mime_type, FALSE);
105 	}
106 
107 	//MiVideo object calls the _deinitialize() for frame manager
108 	MIXUNREF(mix->framemgr, mix_framemanager_unref);
109 
110 	if (mix->surfacepool)
111 	{
112 	  mix_surfacepool_deinitialize(mix->surfacepool);
113 	  MIXUNREF(mix->surfacepool, mix_surfacepool_unref);
114 	}
115 
116 	//libVA cleanup (vaTerminate is called from MixVideo object)
117 	if (mix->va_display) {
118 		if (mix->va_context != VA_INVALID_ID)
119 		{
120 			va_status = vaDestroyConfig(mix->va_display, mix->va_config);
121 			if (va_status != VA_STATUS_SUCCESS) {
122 			LOG_W( "Failed vaDestroyConfig\n");
123 			}
124 			mix->va_config = VA_INVALID_ID;
125 		}
126 		if (mix->va_context != VA_INVALID_ID)
127 		{
128 			va_status = vaDestroyContext(mix->va_display, mix->va_context);
129 			if (va_status != VA_STATUS_SUCCESS) {
130 				LOG_W( "Failed vaDestroyContext\n");
131 			}
132 			mix->va_context = VA_INVALID_ID;
133 		}
134 		if (mix->va_surfaces)
135 		{
136 			va_status = vaDestroySurfaces(mix->va_display, mix->va_surfaces, mix->va_num_surfaces);
137 			if (va_status != VA_STATUS_SUCCESS) {
138 				LOG_W( "Failed vaDestroySurfaces\n");
139 			}
140 			g_free(mix->va_surfaces);
141 			mix->va_surfaces = NULL;
142 			mix->va_num_surfaces = 0;
143 		}
144 	}
145 
146 
147 	//Deinit input buffer queue
148 
149 	while (!g_queue_is_empty(mix->inputbufqueue))
150 	{
151 		buf_entry = g_queue_pop_head(mix->inputbufqueue);
152 		mix_buffer_unref(buf_entry->buf);
153 		g_free(buf_entry);
154 	}
155 
156 	g_queue_free(mix->inputbufqueue);
157 
158 	//MixBuffer pool is deallocated in MixVideo object
159 	mix->inputbufpool = NULL;
160 
161 	/* Chain up parent */
162 	if (parent_class->finalize) {
163 		parent_class->finalize(obj);
164 	}
165 }
166 
167 MixVideoFormat *
mix_videoformat_ref(MixVideoFormat * mix)168 mix_videoformat_ref(MixVideoFormat * mix) {
169 	return (MixVideoFormat *) g_object_ref(G_OBJECT(mix));
170 }
171 
172 /* Default vmethods implementation */
mix_videofmt_getcaps_default(MixVideoFormat * mix,GString * msg)173 static MIX_RESULT mix_videofmt_getcaps_default(MixVideoFormat *mix,
174 		GString *msg) {
175 	g_print("mix_videofmt_getcaps_default\n");
176 	return MIX_RESULT_SUCCESS;
177 }
178 
mix_videofmt_initialize_default(MixVideoFormat * mix,MixVideoConfigParamsDec * config_params,MixFrameManager * frame_mgr,MixBufferPool * input_buf_pool,MixSurfacePool ** surface_pool,VADisplay va_display)179 static MIX_RESULT mix_videofmt_initialize_default(MixVideoFormat *mix,
180 		MixVideoConfigParamsDec * config_params,
181                 MixFrameManager * frame_mgr,
182 		MixBufferPool * input_buf_pool,
183 		MixSurfacePool ** surface_pool,
184                 VADisplay va_display) {
185 
186 	LOG_V(	"Begin\n");
187 
188 	MIX_RESULT res = MIX_RESULT_SUCCESS;
189 	MixInputBufferEntry *buf_entry = NULL;
190 
191 	if (!mix || !config_params || !frame_mgr || !input_buf_pool || !surface_pool || !va_display)
192 	{
193 		LOG_E( "NUll pointer passed in\n");
194 		return (MIX_RESULT_NULL_PTR);
195 	}
196 
197 	// Create object lock
198 	// Note that g_thread_init() has already been called by mix_video_init()
199 	if (mix->objectlock)  //If already exists, then deallocate old one (we are being re-initialized)
200 	{
201                 g_mutex_free(mix->objectlock);
202                 mix->objectlock = NULL;
203 	}
204 	mix->objectlock = g_mutex_new();
205 	if (!mix->objectlock) {
206 		LOG_E( "!mix->objectlock\n");
207 		return (MIX_RESULT_NO_MEMORY);
208 	}
209 
210 	g_mutex_lock(mix->objectlock);
211 
212 	//Clean up any previous framemgr
213 	MIXUNREF(mix->framemgr, mix_framemanager_unref);
214 	mix->framemgr = frame_mgr;
215 	mix_framemanager_ref(mix->framemgr);
216 
217 	mix->va_display = va_display;
218 
219 	if (mix->mime_type)  //Clean up any previous mime_type
220 	{
221 		if (mix->mime_type->str)
222 			g_string_free(mix->mime_type, TRUE);
223 		else
224 			g_string_free(mix->mime_type, FALSE);
225 	}
226 	gchar *mime_tmp = NULL;
227 	res = mix_videoconfigparamsdec_get_mime_type(config_params, &mime_tmp);
228 	if (mime_tmp)
229 	{
230 		mix->mime_type = g_string_new(mime_tmp);
231 		g_free(mime_tmp);
232 		if (!mix->mime_type) //new failed
233 		{
234 			res = MIX_RESULT_NO_MEMORY;
235 			LOG_E( "Could not duplicate mime_type\n");
236 			goto cleanup;
237 		}
238 	}  //else there is no mime_type; leave as NULL
239 
240 	res = mix_videoconfigparamsdec_get_frame_rate(config_params, &(mix->frame_rate_num), &(mix->frame_rate_denom));
241 	if (res != MIX_RESULT_SUCCESS)
242 	{
243 		LOG_E( "Error getting frame_rate\n");
244 		goto cleanup;
245 	}
246 	res = mix_videoconfigparamsdec_get_picture_res(config_params, &(mix->picture_width), &(mix->picture_height));
247 	if (res != MIX_RESULT_SUCCESS)
248 	{
249 		LOG_E( "Error getting picture_res\n");
250 		goto cleanup;
251 	}
252 
253 	if (mix->inputbufqueue)
254 	{
255 		//Deinit previous input buffer queue
256 
257 		while (!g_queue_is_empty(mix->inputbufqueue))
258 		{
259 			buf_entry = g_queue_pop_head(mix->inputbufqueue);
260 			mix_buffer_unref(buf_entry->buf);
261 			g_free(buf_entry);
262 		}
263 
264 		g_queue_free(mix->inputbufqueue);
265 	}
266 
267 	//MixBuffer pool is cleaned up in MixVideo object
268 	mix->inputbufpool = NULL;
269 
270 	mix->inputbufpool = input_buf_pool;
271 	mix->inputbufqueue = g_queue_new();
272 	if (!mix->inputbufqueue)  //New failed
273 	{
274 		res = MIX_RESULT_NO_MEMORY;
275 		LOG_E( "Could not duplicate mime_type\n");
276 		goto cleanup;
277 	}
278 
279 	// surface pool, VA context/config and parser handle are initialized by
280 	// derived classes
281 
282 
283 	cleanup:
284 	if (res != MIX_RESULT_SUCCESS) {
285 
286 		MIXUNREF(mix->framemgr, mix_framemanager_unref);
287 		if (mix->mime_type)
288 		{
289 			if (mix->mime_type->str)
290 				g_string_free(mix->mime_type, TRUE);
291 			else
292 				g_string_free(mix->mime_type, FALSE);
293 			mix->mime_type = NULL;
294 		}
295 
296 		if (mix->objectlock)
297 			g_mutex_unlock(mix->objectlock);
298                 g_mutex_free(mix->objectlock);
299                 mix->objectlock = NULL;
300 		mix->frame_rate_num = 0;
301 		mix->frame_rate_denom = 1;
302 		mix->picture_width = 0;
303 		mix->picture_height = 0;
304 
305 	} else {
306 	//Normal unlock
307 		if (mix->objectlock)
308 			g_mutex_unlock(mix->objectlock);
309 	}
310 
311 	LOG_V( "End\n");
312 
313 	return res;
314 }
315 
mix_videofmt_decode_default(MixVideoFormat * mix,MixBuffer * bufin[],gint bufincnt,MixVideoDecodeParams * decode_params)316 static MIX_RESULT mix_videofmt_decode_default(MixVideoFormat *mix,
317 		MixBuffer * bufin[], gint bufincnt,
318                 MixVideoDecodeParams * decode_params) {
319 	return MIX_RESULT_SUCCESS;
320 }
321 
mix_videofmt_flush_default(MixVideoFormat * mix)322 static MIX_RESULT mix_videofmt_flush_default(MixVideoFormat *mix) {
323 	return MIX_RESULT_SUCCESS;
324 }
325 
mix_videofmt_eos_default(MixVideoFormat * mix)326 static MIX_RESULT mix_videofmt_eos_default(MixVideoFormat *mix) {
327 	return MIX_RESULT_SUCCESS;
328 }
329 
mix_videofmt_deinitialize_default(MixVideoFormat * mix)330 static MIX_RESULT mix_videofmt_deinitialize_default(MixVideoFormat *mix) {
331 
332 	//All teardown is being done in _finalize()
333 
334 	return MIX_RESULT_SUCCESS;
335 }
336 
337 /* mixvideoformat class methods implementation */
338 
mix_videofmt_getcaps(MixVideoFormat * mix,GString * msg)339 MIX_RESULT mix_videofmt_getcaps(MixVideoFormat *mix, GString *msg) {
340 	MixVideoFormatClass *klass = MIX_VIDEOFORMAT_GET_CLASS(mix);
341 	g_print("mix_videofmt_getcaps\n");
342 	if (klass->getcaps) {
343 		return klass->getcaps(mix, msg);
344 	}
345 	return MIX_RESULT_NOTIMPL;
346 }
347 
mix_videofmt_initialize(MixVideoFormat * mix,MixVideoConfigParamsDec * config_params,MixFrameManager * frame_mgr,MixBufferPool * input_buf_pool,MixSurfacePool ** surface_pool,VADisplay va_display)348 MIX_RESULT mix_videofmt_initialize(MixVideoFormat *mix,
349 		MixVideoConfigParamsDec * config_params,
350                 MixFrameManager * frame_mgr,
351 		MixBufferPool * input_buf_pool,
352 		MixSurfacePool ** surface_pool,
353 		VADisplay va_display) {
354 	MixVideoFormatClass *klass = MIX_VIDEOFORMAT_GET_CLASS(mix);
355 
356 	if (klass->initialize) {
357 		return klass->initialize(mix, config_params, frame_mgr,
358 					input_buf_pool, surface_pool, va_display);
359 	}
360 
361 	return MIX_RESULT_FAIL;
362 
363 }
364 
mix_videofmt_decode(MixVideoFormat * mix,MixBuffer * bufin[],gint bufincnt,MixVideoDecodeParams * decode_params)365 MIX_RESULT mix_videofmt_decode(MixVideoFormat *mix, MixBuffer * bufin[],
366                 gint bufincnt, MixVideoDecodeParams * decode_params) {
367 
368 	MixVideoFormatClass *klass = MIX_VIDEOFORMAT_GET_CLASS(mix);
369 	if (klass->decode) {
370 		return klass->decode(mix, bufin, bufincnt, decode_params);
371 	}
372 
373 	return MIX_RESULT_FAIL;
374 }
375 
mix_videofmt_flush(MixVideoFormat * mix)376 MIX_RESULT mix_videofmt_flush(MixVideoFormat *mix) {
377 	MixVideoFormatClass *klass = MIX_VIDEOFORMAT_GET_CLASS(mix);
378 	if (klass->flush) {
379 		return klass->flush(mix);
380 	}
381 
382 	return MIX_RESULT_FAIL;
383 }
384 
mix_videofmt_eos(MixVideoFormat * mix)385 MIX_RESULT mix_videofmt_eos(MixVideoFormat *mix) {
386 	MixVideoFormatClass *klass = MIX_VIDEOFORMAT_GET_CLASS(mix);
387 	if (klass->eos) {
388 		return klass->eos(mix);
389 	}
390 
391 	return MIX_RESULT_FAIL;
392 }
393 
mix_videofmt_deinitialize(MixVideoFormat * mix)394 MIX_RESULT mix_videofmt_deinitialize(MixVideoFormat *mix) {
395 	MixVideoFormatClass *klass = MIX_VIDEOFORMAT_GET_CLASS(mix);
396 	if (klass->deinitialize) {
397 		return klass->deinitialize(mix);
398 	}
399 
400 	return MIX_RESULT_FAIL;
401 }
402