/*
* Copyright (C) 2011-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 "utils.h"
#include "common/common_def.h"
#include "common/log.h"
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <assert.h>
#include <ctype.h>
#include <sstream>
#include <string.h>
#include <sys/time.h>
#include <va/va.h>
namespace YamiMediaCodec{
uint32_t guessFourcc(const char* fileName)
{
static const char* possibleFourcc[] = {
"I420", "NV12", "YV12",
"P010",
"YUY2", "UYVY",
"RGBX", "RGBA", "BGRX", "BGRA",
"XRGB", "ARGB", "XBGR", "ABGR",
//RGB 565
"RG16",
//temprary format for RGB 10 bits
"R210",
//for jpeg
"444P", "422V", "422H", "IMC3"
};
const char* extension = strrchr(fileName, '.');
if (extension) {
extension++;
for (size_t i = 0; i < N_ELEMENTS(possibleFourcc); i++) {
const char* fourcc = possibleFourcc[i];
if (!strcasecmp(fourcc, extension)) {
uint32_t ret = YAMI_FOURCC(fourcc[0], fourcc[1], fourcc[2], fourcc[3]);
DEBUG_FOURCC("guessed input fourcc:", ret);
return ret;
}
}
}
WARNING("can't find fourcc for %s, return i420", extension);
return YAMI_FOURCC_I420;
}
//do not use sscanf to get int, the function will make guessResolutionOverflow failed
//see http://www.kumobius.com/2013/08/c-string-to-int/ for detials
static bool getInt(const char* tokStart, int& v)
{
std::istringstream iss(tokStart);
iss >> v;
return !iss.fail();
}
bool guessResolution(const char* filename, int& w, int& h)
{
enum {
STATE_START,
STATE_WIDTH,
STATE_X,
STATE_HEIGHT,
STATE_END,
};
int state = STATE_START;
const char* p = filename;
const char* tokStart = NULL;
w = h = 0;
while (*p != '\0') {
switch (state) {
case STATE_START:
{
if (isdigit(*p)) {
tokStart = p;
state = STATE_WIDTH;
}
break;
}
case STATE_WIDTH: {
if (*p == 'x' || *p == 'X') {
state = STATE_X;
if (!getInt(tokStart, w)) {
state = STATE_START;
}
} else if (!isdigit(*p)){
state = STATE_START;
}
break;
}
case STATE_X:
{
if (isdigit(*p)) {
tokStart = p;
state = STATE_HEIGHT;
} else {
state = STATE_START;
}
break;
}
case STATE_HEIGHT:
{
if (!isdigit(*p)) {
state = STATE_END;
if (!getInt(tokStart, h)) {
state = STATE_START;
}
}
break;
}
}
if (state == STATE_END)
break;
p++;
}
//conner case
if (*p == '\0' && state == STATE_HEIGHT) {
if (!getInt(tokStart, h))
return false;
}
return w > 0 && h > 0;
}
struct ResolutionEntry {
uint32_t fourcc;
uint32_t planes;
//multiple to half width
//if it equals 1, you need divide width with 2
//if it equals 4, you need multiple width with 2
uint32_t widthMultiple[3];
uint32_t heightMultiple[3];
};
const static ResolutionEntry resolutionEntrys[] = {
{ YAMI_FOURCC_I420, 3, { 2, 1, 1 }, { 2, 1, 1 } },
{ YAMI_FOURCC_YV12, 3, { 2, 1, 1 }, { 2, 1, 1 } },
{ YAMI_FOURCC_IMC3, 3, { 2, 1, 1 }, { 2, 1, 1 } },
{ YAMI_FOURCC_422H, 3, { 2, 1, 1 }, { 2, 2, 2 } },
{ YAMI_FOURCC_422V, 3, { 2, 2, 2 }, { 2, 1, 1 } },
{ YAMI_FOURCC_444P, 3, { 2, 2, 2 }, { 2, 2, 2 } },
{ YAMI_FOURCC_Y800, 1, { 2 }, { 2 } },
{ YAMI_FOURCC_YUY2, 1, { 4 }, { 2 } },
{ YAMI_FOURCC_UYVY, 1, { 4 }, { 2 } },
{ YAMI_FOURCC_RGBX, 1, { 8 }, { 2 } },
{ YAMI_FOURCC_RGBA, 1, { 8 }, { 2 } },
{ YAMI_FOURCC_BGRX, 1, { 8 }, { 2 } },
{ YAMI_FOURCC_BGRA, 1, { 8 }, { 2 } },
{ YAMI_FOURCC_XRGB, 1, { 8 }, { 2 } },
{ YAMI_FOURCC_ARGB, 1, { 8 }, { 2 } },
{ YAMI_FOURCC_XBGR, 1, { 8 }, { 2 } },
{ YAMI_FOURCC_ABGR, 1, { 8 }, { 2 } },
{ YAMI_FOURCC_RGB565, 1, { 4 }, { 2 } },
{ YAMI_FOURCC_R210, 1, { 8 }, { 2 } },
};
/* l is length in pixel*/
/* length[] are length in each plane*/
static void getPlaneLength(uint32_t l, uint32_t plane, const uint32_t multiple[3], uint32_t length[3])
{
for (uint32_t i = 0; i < plane; i++) {
length[i] = (l * multiple[i] + 1) >> 1;
}
}
bool getPlaneResolution(uint32_t fourcc, uint32_t pixelWidth, uint32_t pixelHeight, uint32_t byteWidth[3], uint32_t byteHeight[3], uint32_t& planes)
{
int w = pixelWidth;
int h = pixelHeight;
uint32_t* width = byteWidth;
uint32_t* height = byteHeight;
//NV12 is special since it need add one for width[1] when w is odd
if (fourcc == YAMI_FOURCC_NV12) {
width[0] = w;
height[0] = h;
width[1] = w + (w & 1);
height[1] = (h + 1) >> 1;
planes = 2;
return true;
}
if (fourcc == YAMI_FOURCC_P010) {
width[0] = w * 2;
height[0] = h;
width[1] = (w + (w & 1)) * 2;
height[1] = (h + 1) >> 1;
planes = 2;
return true;
}
for (size_t i = 0; i < N_ELEMENTS(resolutionEntrys); i++) {
const ResolutionEntry& e = resolutionEntrys[i];
if (e.fourcc == fourcc) {
planes = e.planes;
getPlaneLength(pixelWidth, planes, e.widthMultiple, width);
getPlaneLength(pixelHeight, planes, e.heightMultiple, height);
return true;
}
}
ERROR("do not support this format, fourcc %.4s", (char*)&fourcc);
planes = 0;
return false;
}
/// return system clock in ms
uint64_t getSystemTime()
{
struct timeval tv;
if (gettimeofday(&tv, NULL))
return 0;
return tv.tv_usec/1000+tv.tv_sec*1000;
}
double getFps(uint64_t current, uint64_t start, int frames)
{
uint64_t sysTime = current - start;
double fps = frames*1000.0/sysTime;
return fps;
}
FpsCalc::FpsCalc():m_frames(0) {}
void FpsCalc::addFrame()
{
if (m_frames == 0) {
m_start = getSystemTime();
} else if (m_frames == NET_FPS_START){
m_netStart = getSystemTime();
}
m_frames++;
}
void FpsCalc::log()
{
uint64_t current = getSystemTime();
if (m_frames > 0) {
printf("%d frame decoded, fps = %.2f. ", m_frames, getFps(current, m_start,m_frames));
}
if (m_frames > NET_FPS_START) {
printf("fps after %d frames = %.2f.", NET_FPS_START, getFps(current, m_netStart, m_frames-NET_FPS_START));
}
printf("\n");
}
void CalcFps::setAnchor()
{
m_timeStart = getSystemTime();
}
float CalcFps::fps(uint32_t frameCount)
{
if (!m_timeStart) {
fprintf(stderr, "anchor point isn't set, please call setAnchor first\n");
return 0.0f;
}
uint64_t sysTime = getSystemTime() - m_timeStart;
float fps = frameCount*1000.0/sysTime;
fprintf(stdout, "rendered frame count: %d in %" PRIu64 " ms; fps=%.2f\n",
frameCount, sysTime, fps);
return fps;
}
bool fillFrameRawData(VideoFrameRawData* frame, uint32_t fourcc, uint32_t width, uint32_t height, uint8_t* data)
{
memset(frame, 0, sizeof(*frame));
uint32_t planes;
uint32_t w[3], h[3];
if (!getPlaneResolution(fourcc, width, height, w, h, planes))
return false;
frame->fourcc = fourcc;
frame->width = width;
frame->height = height;
frame->handle = reinterpret_cast<intptr_t>(data);
frame->memoryType = VIDEO_DATA_MEMORY_TYPE_RAW_POINTER;
uint32_t offset = 0;
for (uint32_t i = 0; i < planes; i++) {
frame->pitch[i] = w[i];
frame->offset[i] = offset;
offset += w[i] * h[i];
}
return true;
}
};