/*
* Copyright (C) 2014 Intel Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "vaapi/vaapicontext.h"
#include "common/log.h"
#include "common/common_def.h"
#include "vaapi/vaapidisplay.h"
#include "vaapi/VaapiUtils.h"
#include "vaapi/vaapistreamable.h"
#include <algorithm>
#include <vector>
namespace YamiMediaCodec{
using std::vector;
static const VAProfile h264ProfileList[] = {VAProfileH264ConstrainedBaseline, VAProfileH264Main, VAProfileH264High};
//Driver may declare support higher profile but don't support lower profile.
//In this case, higher profile should be created.
//Note: creating higher va profile won't affect the detail encoding/decoding process of libva driver.
static bool checkH264Profile(VAProfile& profile, vector<VAProfile>& profileList)
{
vector<VAProfile>h264Profiles(h264ProfileList, h264ProfileList + N_ELEMENTS(h264ProfileList));
vector<VAProfile>::iterator start = std::find(h264Profiles.begin(), h264Profiles.end(), profile);
vector<VAProfile>::iterator result = std::find_first_of(profileList.begin(), profileList.end(), start, h264Profiles.end());
if (result != profileList.end()){
profile = *result;
return true;
}
return false;
}
static bool checkProfileCompatible(const DisplayPtr& display, VAProfile& profile)
{
int maxNumProfiles, numProfiles;
VAStatus vaStatus;
maxNumProfiles = vaMaxNumProfiles(display->getID());
vector<VAProfile> profileList(maxNumProfiles);
vaStatus = vaQueryConfigProfiles(display->getID(), &profileList[0], &numProfiles);
if (!checkVaapiStatus(vaStatus, "vaQueryConfigProfiles"))
return false;
assert((numProfiles > 0) && (numProfiles <= maxNumProfiles));
profileList.resize(numProfiles);
if (profile == VAProfileH264ConstrainedBaseline || profile == VAProfileH264Main){
if (!checkH264Profile(profile, profileList))
return false;
} else if (!std::count(profileList.begin(), profileList.end(), profile))
return false;
return true;
}
YamiStatus VaapiConfig::create(const DisplayPtr& display,
VAProfile profile, VAEntrypoint entry,
VAConfigAttrib* attribList, int numAttribs,
ConfigPtr& confg)
{
if (!display)
return YAMI_FAIL;
VAStatus vaStatus;
VAConfigID config;
if (!checkProfileCompatible(display, profile)){
ERROR("Unsupported profile %s.\n", toString(profile).c_str());
return YAMI_UNSUPPORTED;
}
vaStatus = vaCreateConfig(display->getID(), profile, entry, attribList, numAttribs, &config);
if (!checkVaapiStatus(vaStatus, "vaCreateConfig ")) {
ERROR("Unable to create config for profile: %s and entrypoint: %s.\n",
toString(profile).c_str(), toString(entry).c_str());
return YAMI_FAIL;
}
confg.reset(new VaapiConfig(display, config));
return YAMI_SUCCESS;
}
VaapiConfig::VaapiConfig(const DisplayPtr& display, VAConfigID config)
:m_display(display), m_config(config)
{
}
VaapiConfig::~VaapiConfig()
{
vaDestroyConfig(m_display->getID(), m_config);
}
ContextPtr VaapiContext::create(const ConfigPtr& config,
int width,int height,int flag,
VASurfaceID *render_targets,
int num_render_targets)
{
ContextPtr ret;
if (!config) {
ERROR("No display");
return ret;
}
VAStatus vaStatus;
VAContextID context;
vaStatus = vaCreateContext(config->m_display->getID(), config->m_config,
width, height, flag,
render_targets, num_render_targets, &context);
if (!checkVaapiStatus(vaStatus, "vaCreateContext "))
return ret;
ret.reset(new VaapiContext(config, context));
return ret;
}
VaapiContext::VaapiContext(const ConfigPtr& config, VAContextID context)
:m_config(config), m_context(context)
{
}
VaapiContext::~VaapiContext()
{
vaDestroyContext(m_config->m_display->getID(), m_context);
}
}