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 Intels 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 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 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 * 81 mix_videoformat_new(void) { 82 MixVideoFormat *ret = g_object_new(MIX_TYPE_VIDEOFORMAT, NULL); 83 84 return ret; 85 } 86 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 * 168 mix_videoformat_ref(MixVideoFormat * mix) { 169 return (MixVideoFormat *) g_object_ref(G_OBJECT(mix)); 170 } 171 172 /* Default vmethods implementation */ 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 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 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 322 static MIX_RESULT mix_videofmt_flush_default(MixVideoFormat *mix) { 323 return MIX_RESULT_SUCCESS; 324 } 325 326 static MIX_RESULT mix_videofmt_eos_default(MixVideoFormat *mix) { 327 return MIX_RESULT_SUCCESS; 328 } 329 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 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 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 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 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 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 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