auto import from //branches/cupcake/...@137873
This commit is contained in:
parent
e131c20ca3
commit
102e25e367
25
libcopybit/Android.mk
Normal file
25
libcopybit/Android.mk
Normal file
@ -0,0 +1,25 @@
|
||||
# Copyright (C) 2008 The Android Open Source Project
|
||||
#
|
||||
# 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.
|
||||
|
||||
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
# HAL module implemenation, not prelinked and stored in
|
||||
# hw/<COPYPIX_HARDWARE_MODULE_ID>.<ro.board.platform>.so
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_PRELINK_MODULE := false
|
||||
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
|
||||
LOCAL_SHARED_LIBRARIES := liblog
|
||||
LOCAL_SRC_FILES := copybit.c
|
||||
LOCAL_MODULE := copybit.msm7k
|
||||
include $(BUILD_SHARED_LIBRARY)
|
398
libcopybit/copybit.c
Normal file
398
libcopybit/copybit.c
Normal file
@ -0,0 +1,398 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#define LOG_TAG "copybit"
|
||||
|
||||
#include <cutils/log.h>
|
||||
|
||||
#include <linux/msm_mdp.h>
|
||||
#include <linux/fb.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <hardware/copybit.h>
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/** State information for each device instance */
|
||||
struct copybit_context_t {
|
||||
struct copybit_device_t device;
|
||||
int mFD;
|
||||
uint8_t mAlpha;
|
||||
uint8_t mFlags;
|
||||
};
|
||||
|
||||
/**
|
||||
* Common hardware methods
|
||||
*/
|
||||
|
||||
static int open_copybit(const struct hw_module_t* module, const char* name,
|
||||
struct hw_device_t** device);
|
||||
|
||||
static struct hw_module_methods_t copybit_module_methods = {
|
||||
.open = open_copybit
|
||||
};
|
||||
|
||||
/*
|
||||
* The COPYBIT Module
|
||||
*/
|
||||
const struct copybit_module_t HAL_MODULE_INFO_SYM = {
|
||||
.common = {
|
||||
.tag = HARDWARE_MODULE_TAG,
|
||||
.version_major = 1,
|
||||
.version_minor = 0,
|
||||
.id = COPYBIT_HARDWARE_MODULE_ID,
|
||||
.name = "QCT MSM7K COPYBIT Module",
|
||||
.author = "Google, Inc.",
|
||||
.methods = ©bit_module_methods,
|
||||
}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/** min of int a, b */
|
||||
static inline int min(int a, int b) {
|
||||
return (a<b) ? a : b;
|
||||
}
|
||||
|
||||
/** max of int a, b */
|
||||
static inline int max(int a, int b) {
|
||||
return (a>b) ? a : b;
|
||||
}
|
||||
|
||||
/** scale each parameter by mul/div. Assume div isn't 0 */
|
||||
static inline void MULDIV(uint32_t *a, uint32_t *b, int mul, int div) {
|
||||
if (mul != div) {
|
||||
*a = (mul * *a) / div;
|
||||
*b = (mul * *b) / div;
|
||||
}
|
||||
}
|
||||
|
||||
/** Determine the intersection of lhs & rhs store in out */
|
||||
static void intersect(struct copybit_rect_t *out,
|
||||
const struct copybit_rect_t *lhs,
|
||||
const struct copybit_rect_t *rhs) {
|
||||
out->l = max(lhs->l, rhs->l);
|
||||
out->t = max(lhs->t, rhs->t);
|
||||
out->r = min(lhs->r, rhs->r);
|
||||
out->b = min(lhs->b, rhs->b);
|
||||
}
|
||||
|
||||
/** convert COPYBIT_FORMAT to MDP format */
|
||||
static int get_format(int format) {
|
||||
switch (format) {
|
||||
case COPYBIT_FORMAT_RGBA_8888: return MDP_RGBA_8888;
|
||||
case COPYBIT_FORMAT_BGRA_8888: return MDP_BGRA_8888;
|
||||
case COPYBIT_FORMAT_RGB_565: return MDP_RGB_565;
|
||||
case COPYBIT_FORMAT_YCbCr_422_SP: return MDP_Y_CBCR_H2V1;
|
||||
case COPYBIT_FORMAT_YCbCr_420_SP: return MDP_Y_CBCR_H2V2;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** convert from copybit image to mdp image structure */
|
||||
static void set_image(struct mdp_img *img,
|
||||
const struct copybit_image_t *rhs) {
|
||||
img->width = rhs->w;
|
||||
img->height = rhs->h;
|
||||
img->format = get_format(rhs->format);
|
||||
img->offset = rhs->offset;
|
||||
img->memory_id = rhs->fd;
|
||||
}
|
||||
|
||||
/** setup rectangles */
|
||||
static void set_rects(struct copybit_context_t *dev,
|
||||
struct mdp_blit_req *e,
|
||||
const struct copybit_rect_t *dst,
|
||||
const struct copybit_rect_t *src,
|
||||
const struct copybit_rect_t *scissor) {
|
||||
struct copybit_rect_t clip;
|
||||
intersect(&clip, scissor, dst);
|
||||
|
||||
e->dst_rect.x = clip.l;
|
||||
e->dst_rect.y = clip.t;
|
||||
e->dst_rect.w = clip.r - clip.l;
|
||||
e->dst_rect.h = clip.b - clip.t;
|
||||
|
||||
uint32_t W, H;
|
||||
if (dev->mFlags & COPYBIT_TRANSFORM_ROT_90) {
|
||||
e->src_rect.x = (clip.t - dst->t) + src->t;
|
||||
e->src_rect.y = (dst->r - clip.r) + src->l;
|
||||
e->src_rect.w = (clip.b - clip.t);
|
||||
e->src_rect.h = (clip.r - clip.l);
|
||||
W = dst->b - dst->t;
|
||||
H = dst->r - dst->l;
|
||||
} else {
|
||||
e->src_rect.x = (clip.l - dst->l) + src->l;
|
||||
e->src_rect.y = (clip.t - dst->t) + src->t;
|
||||
e->src_rect.w = (clip.r - clip.l);
|
||||
e->src_rect.h = (clip.b - clip.t);
|
||||
W = dst->r - dst->l;
|
||||
H = dst->b - dst->t;
|
||||
}
|
||||
MULDIV(&e->src_rect.x, &e->src_rect.w, src->r - src->l, W);
|
||||
MULDIV(&e->src_rect.y, &e->src_rect.h, src->b - src->t, H);
|
||||
if (dev->mFlags & COPYBIT_TRANSFORM_FLIP_V) {
|
||||
e->src_rect.y = e->src.height - (e->src_rect.y + e->src_rect.h);
|
||||
}
|
||||
if (dev->mFlags & COPYBIT_TRANSFORM_FLIP_H) {
|
||||
e->src_rect.x = e->src.width - (e->src_rect.x + e->src_rect.w);
|
||||
}
|
||||
}
|
||||
|
||||
/** setup mdp request */
|
||||
static void set_infos(struct copybit_context_t *dev, struct mdp_blit_req *req) {
|
||||
req->alpha = dev->mAlpha;
|
||||
req->transp_mask = MDP_TRANSP_NOP;
|
||||
req->flags = dev->mFlags;
|
||||
}
|
||||
|
||||
/** copy the bits */
|
||||
static int msm_copybit(struct copybit_context_t *dev, void const *list)
|
||||
{
|
||||
int err = ioctl(dev->mFD, MSMFB_BLIT,
|
||||
(struct mdp_blit_req_list const*)list);
|
||||
LOGE_IF(err<0, "copyBits failed (%s)", strerror(errno));
|
||||
if (err == 0)
|
||||
return 0;
|
||||
else
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Set a parameter to value */
|
||||
static int set_parameter_copybit(
|
||||
struct copybit_device_t *dev,
|
||||
int name,
|
||||
int value)
|
||||
{
|
||||
struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
|
||||
int status = 0;
|
||||
if (ctx) {
|
||||
switch(name) {
|
||||
case COPYBIT_ROTATION_DEG:
|
||||
switch (value) {
|
||||
case 0:
|
||||
ctx->mFlags &= ~0x7;
|
||||
break;
|
||||
case 90:
|
||||
ctx->mFlags &= ~0x7;
|
||||
ctx->mFlags |= MDP_ROT_90;
|
||||
break;
|
||||
case 180:
|
||||
ctx->mFlags &= ~0x7;
|
||||
ctx->mFlags |= MDP_ROT_180;
|
||||
break;
|
||||
case 270:
|
||||
ctx->mFlags &= ~0x7;
|
||||
ctx->mFlags |= MDP_ROT_270;
|
||||
break;
|
||||
default:
|
||||
LOGE("Invalid value for COPYBIT_ROTATION_DEG");
|
||||
status = -EINVAL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case COPYBIT_PLANE_ALPHA:
|
||||
if (value < 0) value = 0;
|
||||
if (value >= 256) value = 255;
|
||||
ctx->mAlpha = value;
|
||||
break;
|
||||
case COPYBIT_DITHER:
|
||||
if (value == COPYBIT_ENABLE) {
|
||||
ctx->mFlags |= MDP_DITHER;
|
||||
} else if (value == COPYBIT_DISABLE) {
|
||||
ctx->mFlags &= ~MDP_DITHER;
|
||||
}
|
||||
break;
|
||||
case COPYBIT_TRANSFORM:
|
||||
ctx->mFlags &= ~0x7;
|
||||
ctx->mFlags |= value & 0x7;
|
||||
break;
|
||||
default:
|
||||
status = -EINVAL;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
status = -EINVAL;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/** Get a static info value */
|
||||
static int get(struct copybit_device_t *dev, int name)
|
||||
{
|
||||
struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
|
||||
int value;
|
||||
if (ctx) {
|
||||
switch(name) {
|
||||
case COPYBIT_MINIFICATION_LIMIT:
|
||||
value = 4;
|
||||
break;
|
||||
case COPYBIT_MAGNIFICATION_LIMIT:
|
||||
value = 4;
|
||||
break;
|
||||
case COPYBIT_SCALING_FRAC_BITS:
|
||||
value = 32;
|
||||
break;
|
||||
case COPYBIT_ROTATION_STEP_DEG:
|
||||
value = 90;
|
||||
break;
|
||||
default:
|
||||
value = -EINVAL;
|
||||
}
|
||||
} else {
|
||||
value = -EINVAL;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/** do a stretch blit type operation */
|
||||
static int stretch_copybit(
|
||||
struct copybit_device_t *dev,
|
||||
struct copybit_image_t const *dst,
|
||||
struct copybit_image_t const *src,
|
||||
struct copybit_rect_t const *dst_rect,
|
||||
struct copybit_rect_t const *src_rect,
|
||||
struct copybit_region_t const *region)
|
||||
{
|
||||
struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
|
||||
int status = 0;
|
||||
if (ctx) {
|
||||
struct {
|
||||
uint32_t count;
|
||||
struct mdp_blit_req req[12];
|
||||
} list;
|
||||
|
||||
if (ctx->mAlpha < 255) {
|
||||
switch (src->format) {
|
||||
// we don't support plane alpha with RGBA formats
|
||||
case COPYBIT_FORMAT_RGBA_8888:
|
||||
case COPYBIT_FORMAT_BGRA_8888:
|
||||
case COPYBIT_FORMAT_RGBA_5551:
|
||||
case COPYBIT_FORMAT_RGBA_4444:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
const uint32_t maxCount = sizeof(list.req)/sizeof(list.req[0]);
|
||||
const struct copybit_rect_t bounds = { 0, 0, dst->w, dst->h };
|
||||
struct copybit_rect_t clip;
|
||||
list.count = 0;
|
||||
status = 0;
|
||||
while ((status == 0) && region->next(region, &clip)) {
|
||||
intersect(&clip, &bounds, &clip);
|
||||
set_infos(ctx, &list.req[list.count]);
|
||||
set_image(&list.req[list.count].dst, dst);
|
||||
set_image(&list.req[list.count].src, src);
|
||||
set_rects(ctx, &list.req[list.count], dst_rect, src_rect, &clip);
|
||||
if (++list.count == maxCount) {
|
||||
status = msm_copybit(ctx, &list);
|
||||
list.count = 0;
|
||||
}
|
||||
}
|
||||
if ((status == 0) && list.count) {
|
||||
status = msm_copybit(ctx, &list);
|
||||
}
|
||||
} else {
|
||||
status = -EINVAL;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/** Perform a blit type operation */
|
||||
static int blit_copybit(
|
||||
struct copybit_device_t *dev,
|
||||
struct copybit_image_t const *dst,
|
||||
struct copybit_image_t const *src,
|
||||
struct copybit_region_t const *region)
|
||||
{
|
||||
struct copybit_rect_t dr = { 0, 0, dst->w, dst->h };
|
||||
struct copybit_rect_t sr = { 0, 0, src->w, src->h };
|
||||
return stretch_copybit(dev, dst, src, &dr, &sr, region);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/** Close the copybit device */
|
||||
static int close_copybit(struct hw_device_t *dev)
|
||||
{
|
||||
struct copybit_context_t* ctx = (struct copybit_context_t*)dev;
|
||||
if (ctx) {
|
||||
close(ctx->mFD);
|
||||
free(ctx);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Open a new instance of a copybit device using name */
|
||||
static int open_copybit(const struct hw_module_t* module, const char* name,
|
||||
struct hw_device_t** device)
|
||||
{
|
||||
int status = -EINVAL;
|
||||
struct copybit_context_t *ctx = malloc(sizeof(struct copybit_context_t));
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
|
||||
ctx->device.common.tag = HARDWARE_DEVICE_TAG;
|
||||
ctx->device.common.version = 0;
|
||||
ctx->device.common.module = module;
|
||||
ctx->device.common.close = close_copybit;
|
||||
ctx->device.set_parameter = set_parameter_copybit;
|
||||
ctx->device.get = get;
|
||||
ctx->device.blit = blit_copybit;
|
||||
ctx->device.stretch = stretch_copybit;
|
||||
ctx->mAlpha = MDP_ALPHA_NOP;
|
||||
ctx->mFlags = 0;
|
||||
ctx->mFD = open("/dev/graphics/fb0", O_RDWR, 0);
|
||||
|
||||
if (ctx->mFD < 0) {
|
||||
status = errno;
|
||||
LOGE("Error opening frame buffer errno=%d (%s)",
|
||||
status, strerror(status));
|
||||
status = -status;
|
||||
} else {
|
||||
struct fb_fix_screeninfo finfo;
|
||||
if (ioctl(ctx->mFD, FBIOGET_FSCREENINFO, &finfo) == 0) {
|
||||
if (strcmp(finfo.id, "msmfb") == 0) {
|
||||
/* Success */
|
||||
status = 0;
|
||||
} else {
|
||||
LOGE("Error not msm frame buffer");
|
||||
status = -EINVAL;
|
||||
}
|
||||
} else {
|
||||
LOGE("Error executing ioctl for screen info");
|
||||
status = -errno;
|
||||
}
|
||||
}
|
||||
|
||||
if (status == 0) {
|
||||
*device = &ctx->device.common;
|
||||
} else {
|
||||
close_copybit(&ctx->device.common);
|
||||
}
|
||||
return status;
|
||||
}
|
16
yuv420sp2rgb/Android.mk
Normal file
16
yuv420sp2rgb/Android.mk
Normal file
@ -0,0 +1,16 @@
|
||||
# Copyright 2005 Google Inc. All Rights Reserved.
|
||||
#
|
||||
# Android.mk for apriori
|
||||
#
|
||||
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
ifeq ($(TARGET_ARCH),arm)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := yuv420sp2rgb.c cmdline.c debug.c
|
||||
|
||||
LOCAL_MODULE := yuv420sp2rgb
|
||||
|
||||
include $(BUILD_HOST_EXECUTABLE)
|
||||
endif
|
147
yuv420sp2rgb/cmdline.c
Normal file
147
yuv420sp2rgb/cmdline.c
Normal file
@ -0,0 +1,147 @@
|
||||
#include <debug.h>
|
||||
#include <cmdline.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
extern char *optarg;
|
||||
extern int optind, opterr, optopt;
|
||||
|
||||
static struct option long_options[] = {
|
||||
{"output", required_argument, 0, 'o'},
|
||||
{"height", required_argument, 0, 'h'},
|
||||
{"width", required_argument, 0, 'w'},
|
||||
{"gray", no_argument, 0, 'g'},
|
||||
{"type", required_argument, 0, 't'},
|
||||
{"rotate", required_argument, 0, 'r'},
|
||||
{"verbose", no_argument, 0, 'V'},
|
||||
{"help", no_argument, 0, 1},
|
||||
{0, 0, 0, 0},
|
||||
};
|
||||
|
||||
/* This array must parallel long_options[] */
|
||||
static const char *descriptions[] = {
|
||||
"output file",
|
||||
"image height in pixels",
|
||||
"image width in pixels",
|
||||
"process the luma plane only",
|
||||
"encode as one of { 'ppm', 'rgb', or 'argb' }",
|
||||
"rotate (90, -90, 180 degrees)",
|
||||
"print verbose output",
|
||||
"print this help screen",
|
||||
};
|
||||
|
||||
void print_help(const char *name) {
|
||||
fprintf(stdout,
|
||||
"Converts yuv 4:2:0 to rgb24 and generates a PPM file.\n"
|
||||
"invokation:\n"
|
||||
"\t%s infile --height <height> --width <width> --output <outfile> [ --gray ] [ --rotate <degrees> ] [ --verbose ]\n"
|
||||
"\t%s infile --help\n",
|
||||
name, name);
|
||||
fprintf(stdout, "options:\n");
|
||||
struct option *opt = long_options;
|
||||
const char **desc = descriptions;
|
||||
while (opt->name) {
|
||||
fprintf(stdout, "\t-%c/--%s%s: %s\n",
|
||||
isprint(opt->val) ? opt->val : ' ',
|
||||
opt->name,
|
||||
(opt->has_arg ? " (argument)" : ""),
|
||||
*desc);
|
||||
opt++;
|
||||
desc++;
|
||||
}
|
||||
}
|
||||
|
||||
int get_options(int argc, char **argv,
|
||||
char **outfile,
|
||||
int *height,
|
||||
int *width,
|
||||
int *gray,
|
||||
char **type,
|
||||
int *rotate,
|
||||
int *verbose) {
|
||||
int c;
|
||||
|
||||
ASSERT(outfile); *outfile = NULL;
|
||||
ASSERT(height); *height = -1;
|
||||
ASSERT(width); *width = -1;
|
||||
ASSERT(gray); *gray = 0;
|
||||
ASSERT(rotate); *rotate = 0;
|
||||
ASSERT(verbose); *verbose = 0;
|
||||
ASSERT(type); *type = NULL;
|
||||
|
||||
while (1) {
|
||||
/* getopt_long stores the option index here. */
|
||||
int option_index = 0;
|
||||
|
||||
c = getopt_long (argc, argv,
|
||||
"Vgo:h:w:r:t:",
|
||||
long_options,
|
||||
&option_index);
|
||||
/* Detect the end of the options. */
|
||||
if (c == -1) break;
|
||||
|
||||
if (isgraph(c)) {
|
||||
INFO ("option -%c with value `%s'\n", c, (optarg ?: "(null)"));
|
||||
}
|
||||
|
||||
#define SET_STRING_OPTION(name) do { \
|
||||
ASSERT(optarg); \
|
||||
(*name) = strdup(optarg); \
|
||||
} while(0)
|
||||
|
||||
#define SET_INT_OPTION(val) do { \
|
||||
ASSERT(optarg); \
|
||||
if (strlen(optarg) >= 2 && optarg[0] == '0' && optarg[1] == 'x') { \
|
||||
FAILIF(1 != sscanf(optarg+2, "%x", val), \
|
||||
"Expecting a hexadecimal argument!\n"); \
|
||||
} else { \
|
||||
FAILIF(1 != sscanf(optarg, "%d", val), \
|
||||
"Expecting a decimal argument!\n"); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
switch (c) {
|
||||
case 0:
|
||||
/* If this option set a flag, do nothing else now. */
|
||||
if (long_options[option_index].flag != 0)
|
||||
break;
|
||||
INFO ("option %s", long_options[option_index].name);
|
||||
if (optarg)
|
||||
INFO (" with arg %s", optarg);
|
||||
INFO ("\n");
|
||||
break;
|
||||
case 1: print_help(argv[0]); exit(1); break;
|
||||
case 'o':
|
||||
SET_STRING_OPTION(outfile);
|
||||
break;
|
||||
case 't':
|
||||
SET_STRING_OPTION(type);
|
||||
break;
|
||||
case 'h':
|
||||
SET_INT_OPTION(height);
|
||||
break;
|
||||
case 'w':
|
||||
SET_INT_OPTION(width);
|
||||
break;
|
||||
case 'r':
|
||||
SET_INT_OPTION(rotate);
|
||||
break;
|
||||
case 'g': *gray = 1; break;
|
||||
case 'V': *verbose = 1; break;
|
||||
case '?':
|
||||
/* getopt_long already printed an error message. */
|
||||
break;
|
||||
|
||||
#undef SET_STRING_OPTION
|
||||
#undef SET_INT_OPTION
|
||||
|
||||
default:
|
||||
FAILIF(1, "Unknown option");
|
||||
}
|
||||
}
|
||||
|
||||
return optind;
|
||||
}
|
15
yuv420sp2rgb/cmdline.h
Normal file
15
yuv420sp2rgb/cmdline.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef CMDLINE_H
|
||||
#define CMDLINE_H
|
||||
|
||||
void print_help(const char *executable_name);
|
||||
|
||||
extern int get_options(int argc, char **argv,
|
||||
char **outfile,
|
||||
int *height,
|
||||
int *width,
|
||||
int *gray,
|
||||
char **type,
|
||||
int *rotate,
|
||||
int *verbose);
|
||||
|
||||
#endif/*CMDLINE_H*/
|
38
yuv420sp2rgb/debug.c
Normal file
38
yuv420sp2rgb/debug.c
Normal file
@ -0,0 +1,38 @@
|
||||
#include <debug.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#define NUM_COLS (32)
|
||||
|
||||
int dump_hex_buffer(FILE *s, void *b, size_t len, size_t elsize) {
|
||||
int num_nonprintable = 0;
|
||||
int i, last;
|
||||
char *pchr = (char *)b;
|
||||
fputc('\n', s);
|
||||
fprintf(s, "%p: ", b);
|
||||
for (i = last = 0; i < len; i++) {
|
||||
if (!elsize) {
|
||||
if (i && !(i % 4)) fprintf(s, " ");
|
||||
if (i && !(i % 8)) fprintf(s, " ");
|
||||
} else {
|
||||
if (i && !(i % elsize)) fprintf(s, " ");
|
||||
}
|
||||
|
||||
if (i && !(i % NUM_COLS)) {
|
||||
while (last < i) {
|
||||
if (isprint(pchr[last]))
|
||||
fputc(pchr[last], s);
|
||||
else {
|
||||
fputc('.', s);
|
||||
num_nonprintable++;
|
||||
}
|
||||
last++;
|
||||
}
|
||||
fprintf(s, " (%d)\n%p: ", i, b);
|
||||
}
|
||||
fprintf(s, "%02x", (unsigned char)pchr[i]);
|
||||
}
|
||||
if (i && (i % NUM_COLS)) fputs("\n", s);
|
||||
return num_nonprintable;
|
||||
}
|
||||
|
90
yuv420sp2rgb/debug.h
Normal file
90
yuv420sp2rgb/debug.h
Normal file
@ -0,0 +1,90 @@
|
||||
#ifndef DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define unlikely(expr) __builtin_expect (expr, 0)
|
||||
#define likely(expr) __builtin_expect (expr, 1)
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
#define FAILIF(cond, msg...) do { \
|
||||
if (unlikely(cond)) { \
|
||||
fprintf(stderr, "%s(%d): ", __FILE__, __LINE__); \
|
||||
fprintf(stderr, ##msg); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/* Debug enabled */
|
||||
#define ASSERT(x) do { \
|
||||
if (unlikely(!(x))) { \
|
||||
fprintf(stderr, \
|
||||
"ASSERTION FAILURE %s:%d: [%s]\n", \
|
||||
__FILE__, __LINE__, #x); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#else
|
||||
|
||||
#define FAILIF(cond, msg...) do { \
|
||||
if (unlikely(cond)) { \
|
||||
fprintf(stderr, ##msg); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/* No debug */
|
||||
#define ASSERT(x) do { } while(0)
|
||||
|
||||
#endif/* DEBUG */
|
||||
|
||||
#define FAILIF_LIBELF(cond, function) \
|
||||
FAILIF(cond, "%s(): %s\n", #function, elf_errmsg(elf_errno()));
|
||||
|
||||
static inline void *MALLOC(unsigned int size) {
|
||||
void *m = malloc(size);
|
||||
FAILIF(NULL == m, "malloc(%d) failed!\n", size);
|
||||
return m;
|
||||
}
|
||||
|
||||
static inline void *CALLOC(unsigned int num_entries, unsigned int entry_size) {
|
||||
void *m = calloc(num_entries, entry_size);
|
||||
FAILIF(NULL == m, "calloc(%d, %d) failed!\n", num_entries, entry_size);
|
||||
return m;
|
||||
}
|
||||
|
||||
static inline void *REALLOC(void *ptr, unsigned int size) {
|
||||
void *m = realloc(ptr, size);
|
||||
FAILIF(NULL == m, "realloc(%p, %d) failed!\n", ptr, size);
|
||||
return m;
|
||||
}
|
||||
|
||||
static inline void FREE(void *ptr) {
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
static inline void FREEIF(void *ptr) {
|
||||
if (ptr) FREE(ptr);
|
||||
}
|
||||
|
||||
#define PRINT(x...) do { \
|
||||
extern int quiet_flag; \
|
||||
if(likely(!quiet_flag)) \
|
||||
fprintf(stdout, ##x); \
|
||||
} while(0)
|
||||
|
||||
#define ERROR PRINT
|
||||
|
||||
#define INFO(x...) do { \
|
||||
extern int verbose_flag; \
|
||||
if(unlikely(verbose_flag)) \
|
||||
fprintf(stdout, ##x); \
|
||||
} while(0)
|
||||
|
||||
/* Prints a hex and ASCII dump of the selected buffer to the selected stream. */
|
||||
int dump_hex_buffer(FILE *s, void *b, size_t l, size_t elsize);
|
||||
|
||||
#endif/*DEBUG_H*/
|
337
yuv420sp2rgb/yuv420sp2rgb.c
Normal file
337
yuv420sp2rgb/yuv420sp2rgb.c
Normal file
@ -0,0 +1,337 @@
|
||||
#include <stdio.h>
|
||||
#include <debug.h>
|
||||
#include <cmdline.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef max
|
||||
#define max(a,b) ({typeof(a) _a = (a); typeof(b) _b = (b); _a > _b ? _a : _b; })
|
||||
#define min(a,b) ({typeof(a) _a = (a); typeof(b) _b = (b); _a < _b ? _a : _b; })
|
||||
#endif
|
||||
|
||||
#define CONVERT_TYPE_PPM 0
|
||||
#define CONVERT_TYPE_RGB 1
|
||||
#define CONVERT_TYPE_ARGB 2
|
||||
|
||||
/*
|
||||
YUV 4:2:0 image with a plane of 8 bit Y samples followed by an interleaved
|
||||
U/V plane containing 8 bit 2x2 subsampled chroma samples.
|
||||
except the interleave order of U and V is reversed.
|
||||
|
||||
H V
|
||||
Y Sample Period 1 1
|
||||
U (Cb) Sample Period 2 2
|
||||
V (Cr) Sample Period 2 2
|
||||
*/
|
||||
|
||||
typedef struct rgb_context {
|
||||
unsigned char *buffer;
|
||||
int width;
|
||||
int height;
|
||||
int rotate;
|
||||
int i;
|
||||
int j;
|
||||
int size; /* for debugging */
|
||||
} rgb_context;
|
||||
|
||||
typedef void (*rgb_cb)(
|
||||
unsigned char r,
|
||||
unsigned char g,
|
||||
unsigned char b,
|
||||
rgb_context *ctx);
|
||||
|
||||
const int bytes_per_pixel = 2;
|
||||
|
||||
static void color_convert_common(
|
||||
unsigned char *pY, unsigned char *pUV,
|
||||
int width, int height,
|
||||
unsigned char *buffer,
|
||||
int size, /* buffer size in bytes */
|
||||
int gray,
|
||||
int rotate,
|
||||
rgb_cb cb)
|
||||
{
|
||||
int i, j;
|
||||
int nR, nG, nB;
|
||||
int nY, nU, nV;
|
||||
rgb_context ctx;
|
||||
|
||||
ctx.buffer = buffer;
|
||||
ctx.size = size; /* debug */
|
||||
ctx.width = width;
|
||||
ctx.height = height;
|
||||
ctx.rotate = rotate;
|
||||
|
||||
if (gray) {
|
||||
for (i = 0; i < height; i++) {
|
||||
for (j = 0; j < width; j++) {
|
||||
nB = *(pY + i * width + j);
|
||||
ctx.i = i;
|
||||
ctx.j = j;
|
||||
cb(nB, nB, nB, &ctx);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// YUV 4:2:0
|
||||
for (i = 0; i < height; i++) {
|
||||
for (j = 0; j < width; j++) {
|
||||
nY = *(pY + i * width + j);
|
||||
nV = *(pUV + (i/2) * width + bytes_per_pixel * (j/2));
|
||||
nU = *(pUV + (i/2) * width + bytes_per_pixel * (j/2) + 1);
|
||||
|
||||
// Yuv Convert
|
||||
nY -= 16;
|
||||
nU -= 128;
|
||||
nV -= 128;
|
||||
|
||||
if (nY < 0)
|
||||
nY = 0;
|
||||
|
||||
// nR = (int)(1.164 * nY + 2.018 * nU);
|
||||
// nG = (int)(1.164 * nY - 0.813 * nV - 0.391 * nU);
|
||||
// nB = (int)(1.164 * nY + 1.596 * nV);
|
||||
|
||||
nB = (int)(1192 * nY + 2066 * nU);
|
||||
nG = (int)(1192 * nY - 833 * nV - 400 * nU);
|
||||
nR = (int)(1192 * nY + 1634 * nV);
|
||||
|
||||
nR = min(262143, max(0, nR));
|
||||
nG = min(262143, max(0, nG));
|
||||
nB = min(262143, max(0, nB));
|
||||
|
||||
nR >>= 10; nR &= 0xff;
|
||||
nG >>= 10; nG &= 0xff;
|
||||
nB >>= 10; nB &= 0xff;
|
||||
|
||||
ctx.i = i;
|
||||
ctx.j = j;
|
||||
cb(nR, nG, nB, &ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rgb16_cb(
|
||||
unsigned char r,
|
||||
unsigned char g,
|
||||
unsigned char b,
|
||||
rgb_context *ctx)
|
||||
{
|
||||
unsigned short *rgb16 = (unsigned short *)ctx->buffer;
|
||||
*(rgb16 + ctx->i * ctx->width + ctx->j) = b | (g << 5) | (r << 11);
|
||||
}
|
||||
|
||||
static void common_rgb_cb(
|
||||
unsigned char r,
|
||||
unsigned char g,
|
||||
unsigned char b,
|
||||
rgb_context *ctx,
|
||||
int alpha)
|
||||
{
|
||||
unsigned char *out = ctx->buffer;
|
||||
int offset = 0;
|
||||
int bpp;
|
||||
int i = 0;
|
||||
switch(ctx->rotate) {
|
||||
case 0: /* no rotation */
|
||||
offset = ctx->i * ctx->width + ctx->j;
|
||||
break;
|
||||
case 1: /* 90 degrees */
|
||||
offset = ctx->height * (ctx->j + 1) - ctx->i;
|
||||
break;
|
||||
case 2: /* 180 degrees */
|
||||
offset = (ctx->height - 1 - ctx->i) * ctx->width + ctx->j;
|
||||
break;
|
||||
case 3: /* 270 degrees */
|
||||
offset = (ctx->width - 1 - ctx->j) * ctx->height + ctx->i;
|
||||
break;
|
||||
default:
|
||||
FAILIF(1, "Unexpected roation value %d!\n", ctx->rotate);
|
||||
}
|
||||
|
||||
bpp = 3 + !!alpha;
|
||||
offset *= bpp;
|
||||
FAILIF(offset < 0, "point (%d, %d) generates a negative offset.\n", ctx->i, ctx->j);
|
||||
FAILIF(offset + bpp > ctx->size, "point (%d, %d) at offset %d exceeds the size %d of the buffer.\n",
|
||||
ctx->i, ctx->j,
|
||||
offset,
|
||||
ctx->size);
|
||||
|
||||
out += offset;
|
||||
|
||||
if (alpha) out[i++] = 0xff;
|
||||
out[i++] = r;
|
||||
out[i++] = g;
|
||||
out[i] = b;
|
||||
}
|
||||
|
||||
static void rgb24_cb(
|
||||
unsigned char r,
|
||||
unsigned char g,
|
||||
unsigned char b,
|
||||
rgb_context *ctx)
|
||||
{
|
||||
return common_rgb_cb(r,g,b,ctx,0);
|
||||
}
|
||||
|
||||
static void argb_cb(
|
||||
unsigned char r,
|
||||
unsigned char g,
|
||||
unsigned char b,
|
||||
rgb_context *ctx)
|
||||
{
|
||||
return common_rgb_cb(r,g,b,ctx,1);
|
||||
}
|
||||
|
||||
static void convert(const char *infile,
|
||||
const char *outfile,
|
||||
int height,
|
||||
int width,
|
||||
int gray,
|
||||
int type,
|
||||
int rotate)
|
||||
{
|
||||
void *in, *out;
|
||||
int ifd, ofd, rc;
|
||||
int psz = getpagesize();
|
||||
static char header[1024];
|
||||
int header_size;
|
||||
size_t outsize;
|
||||
|
||||
int bpp = 3;
|
||||
switch (type) {
|
||||
case CONVERT_TYPE_PPM:
|
||||
if (rotate & 1)
|
||||
header_size = snprintf(header, sizeof(header), "P6\n%d %d\n255\n", height, width);
|
||||
else
|
||||
header_size = snprintf(header, sizeof(header), "P6\n%d %d\n255\n", width, height);
|
||||
case CONVERT_TYPE_RGB:
|
||||
PRINT("encoding raw RGB24\n");
|
||||
header_size = 0;
|
||||
break;
|
||||
case CONVERT_TYPE_ARGB:
|
||||
PRINT("encoding raw ARGB\n");
|
||||
header_size = 0;
|
||||
bpp = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
outsize = header_size + width * height * bpp;
|
||||
outsize = (outsize + psz - 1) & ~(psz - 1);
|
||||
|
||||
INFO("Opening input file %s\n", infile);
|
||||
ifd = open(infile, O_RDONLY);
|
||||
FAILIF(ifd < 0, "open(%s) failed: %s (%d)\n",
|
||||
infile, strerror(errno), errno);
|
||||
|
||||
INFO("Opening output file %s\n", outfile);
|
||||
ofd = open(outfile, O_RDWR | O_CREAT, 0664);
|
||||
FAILIF(ofd < 0, "open(%s) failed: %s (%d)\n",
|
||||
outfile, strerror(errno), errno);
|
||||
|
||||
INFO("Memory-mapping input file %s\n", infile);
|
||||
in = mmap(0, width * height * 3 / 2, PROT_READ, MAP_PRIVATE, ifd, 0);
|
||||
FAILIF(in == MAP_FAILED, "could not mmap input file: %s (%d)\n",
|
||||
strerror(errno), errno);
|
||||
|
||||
INFO("Truncating output file %s to %d bytes\n", outfile, outsize);
|
||||
FAILIF(ftruncate(ofd, outsize) < 0,
|
||||
"Could not truncate output file to required size: %s (%d)\n",
|
||||
strerror(errno), errno);
|
||||
|
||||
INFO("Memory mapping output file %s\n", outfile);
|
||||
out = mmap(0, outsize, PROT_WRITE, MAP_SHARED, ofd, 0);
|
||||
FAILIF(out == MAP_FAILED, "could not mmap output file: %s (%d)\n",
|
||||
strerror(errno), errno);
|
||||
|
||||
INFO("PPM header (%d) bytes:\n%s\n", header_size, header);
|
||||
FAILIF(write(ofd, header, header_size) != header_size,
|
||||
"Error wrinting PPM header: %s (%d)\n",
|
||||
strerror(errno), errno);
|
||||
|
||||
INFO("Converting %dx%d YUV 4:2:0 to RGB24...\n", width, height);
|
||||
color_convert_common(in, in + width * height,
|
||||
width, height,
|
||||
out + header_size, outsize - header_size,
|
||||
gray, rotate,
|
||||
type == CONVERT_TYPE_ARGB ? argb_cb : rgb24_cb);
|
||||
}
|
||||
|
||||
int verbose_flag;
|
||||
int quiet_flag;
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
char *infile, *outfile, *type;
|
||||
int height, width, gray, rotate;
|
||||
int cmdline_error = 0;
|
||||
|
||||
/* Parse command-line arguments. */
|
||||
|
||||
int first = get_options(argc, argv,
|
||||
&outfile,
|
||||
&height,
|
||||
&width,
|
||||
&gray,
|
||||
&type,
|
||||
&rotate,
|
||||
&verbose_flag);
|
||||
|
||||
if (first == argc) {
|
||||
ERROR("You must specify an input file!\n");
|
||||
cmdline_error++;
|
||||
}
|
||||
if (!outfile) {
|
||||
ERROR("You must specify an output file!\n");
|
||||
cmdline_error++;
|
||||
}
|
||||
if (height < 0 || width < 0) {
|
||||
ERROR("You must specify both image height and width!\n");
|
||||
cmdline_error++;
|
||||
}
|
||||
|
||||
FAILIF(rotate % 90, "Rotation angle must be a multiple of 90 degrees!\n");
|
||||
|
||||
rotate /= 90;
|
||||
rotate %= 4;
|
||||
if (rotate < 0) rotate += 4;
|
||||
|
||||
if (cmdline_error) {
|
||||
print_help(argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
infile = argv[first];
|
||||
|
||||
INFO("input file: [%s]\n", infile);
|
||||
INFO("output file: [%s]\n", outfile);
|
||||
INFO("height: %d\n", height);
|
||||
INFO("width: %d\n", width);
|
||||
INFO("gray only: %d\n", gray);
|
||||
INFO("encode as: %s\n", type);
|
||||
INFO("rotation: %d\n", rotate);
|
||||
|
||||
/* Convert the image */
|
||||
|
||||
int conv_type;
|
||||
if (!strcmp(type, "ppm"))
|
||||
conv_type = CONVERT_TYPE_PPM;
|
||||
else if (!strcmp(type, "rgb"))
|
||||
conv_type = CONVERT_TYPE_RGB;
|
||||
else if (!strcmp(type, "argb"))
|
||||
conv_type = CONVERT_TYPE_ARGB;
|
||||
else FAILIF(1, "Unknown encoding type %s.\n", type);
|
||||
|
||||
convert(infile, outfile,
|
||||
height, width, gray,
|
||||
conv_type,
|
||||
rotate);
|
||||
|
||||
free(outfile);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user