blob: 7f34abd04af40a015c733b5bdeefdb356a8b00fa [file] [log] [blame]
/*
INTEL CONFIDENTIAL
Copyright 2009 Intel Corporation All Rights Reserved.
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.
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.
*/
#include <glib.h>
#include "mixvideolog.h"
#include "mixvideoformat.h"
#define MIXUNREF(obj, unref) if(obj) { unref(obj); obj = NULL; }
/* Default vmethods implementation */
static MIX_RESULT mix_videofmt_getcaps_default(MixVideoFormat *mix,
GString *msg);
static MIX_RESULT mix_videofmt_initialize_default(MixVideoFormat *mix,
MixVideoConfigParamsDec * config_params,
MixFrameManager * frame_mgr,
MixBufferPool * input_buf_pool,
MixSurfacePool ** surface_pool,
VADisplay vadisplay);
static MIX_RESULT
mix_videofmt_decode_default(MixVideoFormat *mix,
MixBuffer * bufin[], gint bufincnt,
MixVideoDecodeParams * decode_params);
static MIX_RESULT mix_videofmt_flush_default(MixVideoFormat *mix);
static MIX_RESULT mix_videofmt_eos_default(MixVideoFormat *mix);
static MIX_RESULT mix_videofmt_deinitialize_default(MixVideoFormat *mix);
static GObjectClass *parent_class = NULL;
static void mix_videoformat_finalize(GObject * obj);
G_DEFINE_TYPE (MixVideoFormat, mix_videoformat, G_TYPE_OBJECT);
static void mix_videoformat_init(MixVideoFormat * self) {
/* public member initialization */
/* These are all public because MixVideoFormat objects are completely internal to MixVideo,
no need for private members */
self->initialized = FALSE;
self->va_initialized = FALSE;
self->framemgr = NULL;
self->surfacepool = NULL;
self->inputbufpool = NULL;
self->inputbufqueue = NULL;
self->va_display = NULL;
self->va_context = VA_INVALID_ID;
self->va_config = VA_INVALID_ID;
self->va_surfaces = NULL;
self->va_num_surfaces = 0;
self->mime_type = NULL;
self->frame_rate_num = 0;
self->frame_rate_denom = 0;
self->picture_width = 0;
self->picture_height = 0;
self->parse_in_progress = FALSE;
self->current_timestamp = (guint64)-1;
self->end_picture_pending = FALSE;
self->video_frame = NULL;
self->extra_surfaces = 0;
self->config_params = NULL;
}
static void mix_videoformat_class_init(MixVideoFormatClass * klass) {
GObjectClass *gobject_class = (GObjectClass *) klass;
/* parent class for later use */
parent_class = g_type_class_peek_parent(klass);
gobject_class->finalize = mix_videoformat_finalize;
/* setup vmethods with base implementation */
klass->getcaps = mix_videofmt_getcaps_default;
klass->initialize = mix_videofmt_initialize_default;
klass->decode = mix_videofmt_decode_default;
klass->flush = mix_videofmt_flush_default;
klass->eos = mix_videofmt_eos_default;
klass->deinitialize = mix_videofmt_deinitialize_default;
}
MixVideoFormat *
mix_videoformat_new(void) {
MixVideoFormat *ret = g_object_new(MIX_TYPE_VIDEOFORMAT, NULL);
return ret;
}
void mix_videoformat_finalize(GObject * obj) {
/* clean up here. */
VAStatus va_status;
MixVideoFormat *mix = MIX_VIDEOFORMAT(obj);
MixInputBufferEntry *buf_entry = NULL;
if(mix->objectlock) {
g_mutex_free(mix->objectlock);
mix->objectlock = NULL;
}
if (mix->mime_type)
{
if (mix->mime_type->str)
g_string_free(mix->mime_type, TRUE);
else
g_string_free(mix->mime_type, FALSE);
}
//MiVideo object calls the _deinitialize() for frame manager
MIXUNREF(mix->framemgr, mix_framemanager_unref);
if (mix->surfacepool)
{
mix_surfacepool_deinitialize(mix->surfacepool);
MIXUNREF(mix->surfacepool, mix_surfacepool_unref);
}
if (mix->config_params)
{
mix_videoconfigparams_unref(mix->config_params);
mix->config_params = NULL;
}
//libVA cleanup (vaTerminate is called from MixVideo object)
if (mix->va_display) {
if (mix->va_context != VA_INVALID_ID)
{
va_status = vaDestroyContext(mix->va_display, mix->va_context);
if (va_status != VA_STATUS_SUCCESS) {
LOG_W( "Failed vaDestroyContext\n");
}
mix->va_context = VA_INVALID_ID;
}
if (mix->va_config != VA_INVALID_ID)
{
va_status = vaDestroyConfig(mix->va_display, mix->va_config);
if (va_status != VA_STATUS_SUCCESS) {
LOG_W( "Failed vaDestroyConfig\n");
}
mix->va_config = VA_INVALID_ID;
}
if (mix->va_surfaces)
{
va_status = vaDestroySurfaces(mix->va_display, mix->va_surfaces, mix->va_num_surfaces);
if (va_status != VA_STATUS_SUCCESS) {
LOG_W( "Failed vaDestroySurfaces\n");
}
g_free(mix->va_surfaces);
mix->va_surfaces = NULL;
mix->va_num_surfaces = 0;
}
}
if (mix->video_frame)
{
mix_videoframe_unref(mix->video_frame);
mix->video_frame = NULL;
}
//Deinit input buffer queue
while (!g_queue_is_empty(mix->inputbufqueue))
{
buf_entry = g_queue_pop_head(mix->inputbufqueue);
mix_buffer_unref(buf_entry->buf);
g_free(buf_entry);
}
g_queue_free(mix->inputbufqueue);
//MixBuffer pool is deallocated in MixVideo object
mix->inputbufpool = NULL;
/* Chain up parent */
if (parent_class->finalize) {
parent_class->finalize(obj);
}
}
MixVideoFormat *
mix_videoformat_ref(MixVideoFormat * mix) {
return (MixVideoFormat *) g_object_ref(G_OBJECT(mix));
}
/* Default vmethods implementation */
static MIX_RESULT mix_videofmt_getcaps_default(MixVideoFormat *mix,
GString *msg) {
g_print("mix_videofmt_getcaps_default\n");
return MIX_RESULT_SUCCESS;
}
static MIX_RESULT mix_videofmt_initialize_default(MixVideoFormat *mix,
MixVideoConfigParamsDec * config_params,
MixFrameManager * frame_mgr,
MixBufferPool * input_buf_pool,
MixSurfacePool ** surface_pool,
VADisplay va_display) {
LOG_V( "Begin\n");
MIX_RESULT res = MIX_RESULT_SUCCESS;
MixInputBufferEntry *buf_entry = NULL;
if (!mix || !config_params || !frame_mgr || !input_buf_pool || !surface_pool || !va_display)
{
LOG_E( "NUll pointer passed in\n");
return (MIX_RESULT_NULL_PTR);
}
// Create object lock
// Note that g_thread_init() has already been called by mix_video_init()
if (mix->objectlock) //If already exists, then deallocate old one (we are being re-initialized)
{
g_mutex_free(mix->objectlock);
mix->objectlock = NULL;
}
mix->objectlock = g_mutex_new();
if (!mix->objectlock) {
LOG_E( "!mix->objectlock\n");
return (MIX_RESULT_NO_MEMORY);
}
g_mutex_lock(mix->objectlock);
//Clean up any previous framemgr
MIXUNREF(mix->framemgr, mix_framemanager_unref);
mix->framemgr = frame_mgr;
mix_framemanager_ref(mix->framemgr);
if (mix->config_params)
{
mix_videoconfigparams_unref(mix->config_params);
}
mix->config_params = config_params;
mix_videoconfigparams_ref(mix->config_params);
mix->va_display = va_display;
if (mix->mime_type) //Clean up any previous mime_type
{
if (mix->mime_type->str)
g_string_free(mix->mime_type, TRUE);
else
g_string_free(mix->mime_type, FALSE);
}
gchar *mime_tmp = NULL;
res = mix_videoconfigparamsdec_get_mime_type(config_params, &mime_tmp);
if (mime_tmp)
{
mix->mime_type = g_string_new(mime_tmp);
g_free(mime_tmp);
if (!mix->mime_type) //new failed
{
res = MIX_RESULT_NO_MEMORY;
LOG_E( "Could not duplicate mime_type\n");
goto cleanup;
}
} //else there is no mime_type; leave as NULL
res = mix_videoconfigparamsdec_get_frame_rate(config_params, &(mix->frame_rate_num), &(mix->frame_rate_denom));
if (res != MIX_RESULT_SUCCESS)
{
LOG_E( "Error getting frame_rate\n");
goto cleanup;
}
res = mix_videoconfigparamsdec_get_picture_res(config_params, &(mix->picture_width), &(mix->picture_height));
if (res != MIX_RESULT_SUCCESS)
{
LOG_E( "Error getting picture_res\n");
goto cleanup;
}
if (mix->inputbufqueue)
{
//Deinit previous input buffer queue
while (!g_queue_is_empty(mix->inputbufqueue))
{
buf_entry = g_queue_pop_head(mix->inputbufqueue);
mix_buffer_unref(buf_entry->buf);
g_free(buf_entry);
}
g_queue_free(mix->inputbufqueue);
}
//MixBuffer pool is cleaned up in MixVideo object
mix->inputbufpool = NULL;
mix->inputbufpool = input_buf_pool;
mix->inputbufqueue = g_queue_new();
if (!mix->inputbufqueue) //New failed
{
res = MIX_RESULT_NO_MEMORY;
LOG_E( "Could not duplicate mime_type\n");
goto cleanup;
}
// surface pool, VA context/config and parser handle are initialized by
// derived classes
cleanup:
if (res != MIX_RESULT_SUCCESS) {
MIXUNREF(mix->framemgr, mix_framemanager_unref);
if (mix->mime_type)
{
if (mix->mime_type->str)
g_string_free(mix->mime_type, TRUE);
else
g_string_free(mix->mime_type, FALSE);
mix->mime_type = NULL;
}
if (mix->objectlock)
g_mutex_unlock(mix->objectlock);
g_mutex_free(mix->objectlock);
mix->objectlock = NULL;
mix->frame_rate_num = 0;
mix->frame_rate_denom = 1;
mix->picture_width = 0;
mix->picture_height = 0;
} else {
//Normal unlock
if (mix->objectlock)
g_mutex_unlock(mix->objectlock);
}
LOG_V( "End\n");
return res;
}
static MIX_RESULT mix_videofmt_decode_default(MixVideoFormat *mix,
MixBuffer * bufin[], gint bufincnt,
MixVideoDecodeParams * decode_params) {
return MIX_RESULT_SUCCESS;
}
static MIX_RESULT mix_videofmt_flush_default(MixVideoFormat *mix) {
return MIX_RESULT_SUCCESS;
}
static MIX_RESULT mix_videofmt_eos_default(MixVideoFormat *mix) {
return MIX_RESULT_SUCCESS;
}
static MIX_RESULT mix_videofmt_deinitialize_default(MixVideoFormat *mix) {
//All teardown is being done in _finalize()
return MIX_RESULT_SUCCESS;
}
/* mixvideoformat class methods implementation */
MIX_RESULT mix_videofmt_getcaps(MixVideoFormat *mix, GString *msg) {
MixVideoFormatClass *klass = MIX_VIDEOFORMAT_GET_CLASS(mix);
g_print("mix_videofmt_getcaps\n");
if (klass->getcaps) {
return klass->getcaps(mix, msg);
}
return MIX_RESULT_NOTIMPL;
}
MIX_RESULT mix_videofmt_initialize(MixVideoFormat *mix,
MixVideoConfigParamsDec * config_params,
MixFrameManager * frame_mgr,
MixBufferPool * input_buf_pool,
MixSurfacePool ** surface_pool,
VADisplay va_display) {
MixVideoFormatClass *klass = MIX_VIDEOFORMAT_GET_CLASS(mix);
if (klass->initialize) {
return klass->initialize(mix, config_params, frame_mgr,
input_buf_pool, surface_pool, va_display);
}
return MIX_RESULT_FAIL;
}
MIX_RESULT mix_videofmt_decode(MixVideoFormat *mix, MixBuffer * bufin[],
gint bufincnt, MixVideoDecodeParams * decode_params) {
MixVideoFormatClass *klass = MIX_VIDEOFORMAT_GET_CLASS(mix);
if (klass->decode) {
return klass->decode(mix, bufin, bufincnt, decode_params);
}
return MIX_RESULT_FAIL;
}
MIX_RESULT mix_videofmt_flush(MixVideoFormat *mix) {
MixVideoFormatClass *klass = MIX_VIDEOFORMAT_GET_CLASS(mix);
if (klass->flush) {
return klass->flush(mix);
}
return MIX_RESULT_FAIL;
}
MIX_RESULT mix_videofmt_eos(MixVideoFormat *mix) {
MixVideoFormatClass *klass = MIX_VIDEOFORMAT_GET_CLASS(mix);
if (klass->eos) {
return klass->eos(mix);
}
return MIX_RESULT_FAIL;
}
MIX_RESULT mix_videofmt_deinitialize(MixVideoFormat *mix) {
MixVideoFormatClass *klass = MIX_VIDEOFORMAT_GET_CLASS(mix);
if (klass->deinitialize) {
return klass->deinitialize(mix);
}
return MIX_RESULT_FAIL;
}