mirror of
https://github.com/obsproject/obs-studio.git
synced 2024-09-20 13:08:50 +02:00
libobs: Orient images based on EXIF metadata
This commit is contained in:
parent
56d673d55c
commit
6d0e61d40a
@ -144,6 +144,213 @@ static void *ffmpeg_image_copy_data_straight(struct ffmpeg_image *info,
|
||||
return data;
|
||||
}
|
||||
|
||||
static inline size_t get_dst_position(size_t src, const size_t w,
|
||||
const size_t h, const size_t x,
|
||||
const size_t y, int orient)
|
||||
{
|
||||
size_t res_x = 0;
|
||||
size_t res_y = 0;
|
||||
|
||||
if (orient == 2) {
|
||||
/*
|
||||
* Orientation 2: Flip X
|
||||
*
|
||||
* 888888 888888
|
||||
* 88 -> 88
|
||||
* 8888 -> 8888
|
||||
* 88 -> 88
|
||||
* 88 88
|
||||
*
|
||||
* (0, 0) -> (w, 0)
|
||||
* (0, h) -> (w, h)
|
||||
* (w, 0) -> (0, 0)
|
||||
* (w, h) -> (0, h)
|
||||
*
|
||||
* (w - x, y)
|
||||
*/
|
||||
|
||||
res_x = w - 1 - x;
|
||||
res_y = y;
|
||||
|
||||
} else if (orient == 3) {
|
||||
/*
|
||||
* Orientation 3: 180°
|
||||
*
|
||||
* 88 888888
|
||||
* 88 -> 88
|
||||
* 8888 -> 8888
|
||||
* 88 -> 88
|
||||
* 888888 88
|
||||
*
|
||||
* (0, 0) -> (w, h)
|
||||
* (0, h) -> (w, 0)
|
||||
* (w, 0) -> (0, h)
|
||||
* (w, h) -> (0, 0)
|
||||
*
|
||||
* (w - x, h - y)
|
||||
*/
|
||||
|
||||
res_x = w - 1 - x;
|
||||
res_y = h - 1 - y;
|
||||
|
||||
} else if (orient == 4) {
|
||||
/*
|
||||
* Orientation 4: Flip Y
|
||||
*
|
||||
* 88 888888
|
||||
* 88 -> 88
|
||||
* 8888 -> 8888
|
||||
* 88 -> 88
|
||||
* 888888 88
|
||||
*
|
||||
* (0, 0) -> (0, h)
|
||||
* (0, h) -> (0, 0)
|
||||
* (w, 0) -> (w, h)
|
||||
* (w, h) -> (w, 0)
|
||||
*
|
||||
* (x, h - y)
|
||||
*/
|
||||
|
||||
res_x = x;
|
||||
res_y = h - 1 - y;
|
||||
|
||||
} else if (orient == 5) {
|
||||
/*
|
||||
* Orientation 5: Flip Y + 90° CW
|
||||
*
|
||||
* 8888888888 888888
|
||||
* 88 88 -> 88
|
||||
* 88 -> 8888
|
||||
* -> 88
|
||||
* 88
|
||||
*
|
||||
* (0, 0) -> (0, 0)
|
||||
* (0, h) -> (w, 0)
|
||||
* (w, 0) -> (0, h)
|
||||
* (w, h) -> (w, h)
|
||||
*
|
||||
* (y, x)
|
||||
*/
|
||||
|
||||
res_x = y;
|
||||
res_y = x;
|
||||
|
||||
} else if (orient == 6) {
|
||||
/*
|
||||
* Orientation 6: 90° CW
|
||||
*
|
||||
* 88 888888
|
||||
* 88 88 -> 88
|
||||
* 8888888888 -> 8888
|
||||
* -> 88
|
||||
* 88
|
||||
*
|
||||
* (0, 0) -> (w, 0)
|
||||
* (0, h) -> (0, 0)
|
||||
* (w, 0) -> (w, h)
|
||||
* (w, h) -> (0, h)
|
||||
*
|
||||
* (w - y, x)
|
||||
*/
|
||||
|
||||
res_x = w - 1 - y;
|
||||
res_y = x;
|
||||
|
||||
} else if (orient == 7) {
|
||||
/*
|
||||
* Orientation 7: Flip Y + 90° CCW
|
||||
*
|
||||
* 88 888888
|
||||
* 88 88 -> 88
|
||||
* 8888888888 -> 8888
|
||||
* -> 88
|
||||
* 88
|
||||
*
|
||||
* (0, 0) -> (w, h)
|
||||
* (0, h) -> (0, h)
|
||||
* (w, 0) -> (w, 0)
|
||||
* (w, h) -> (0, 0)
|
||||
*
|
||||
* (w - y, h - x)
|
||||
*/
|
||||
|
||||
res_x = w - 1 - y;
|
||||
res_y = h - 1 - x;
|
||||
|
||||
} else if (orient == 8) {
|
||||
/*
|
||||
* Orientation 8: 90° CCW
|
||||
*
|
||||
* 8888888888 888888
|
||||
* 88 88 -> 88
|
||||
* 88 -> 8888
|
||||
* -> 88
|
||||
* 88
|
||||
*
|
||||
* (0, 0) -> (0, h)
|
||||
* (0, h) -> (w, h)
|
||||
* (w, 0) -> (0, 0)
|
||||
* (w, h) -> (w, 0)
|
||||
*
|
||||
* (y, h - x)
|
||||
*/
|
||||
|
||||
res_x = y;
|
||||
res_y = h - 1 - x;
|
||||
}
|
||||
|
||||
return (res_x + res_y * w) * 4;
|
||||
}
|
||||
|
||||
#define TILE_SIZE 16
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
static void *ffmpeg_image_orient(struct ffmpeg_image *info, void *in_data,
|
||||
int orient)
|
||||
{
|
||||
const size_t sx = (size_t)info->cx;
|
||||
const size_t sy = (size_t)info->cy;
|
||||
uint8_t *data = NULL;
|
||||
|
||||
if (orient == 0 || orient == 1)
|
||||
return in_data;
|
||||
|
||||
data = bmalloc(sx * 4 * sy);
|
||||
|
||||
if (orient >= 5 && orient < 9) {
|
||||
info->cx = (int)sy;
|
||||
info->cy = (int)sx;
|
||||
}
|
||||
|
||||
uint8_t *src = in_data;
|
||||
|
||||
size_t off_dst;
|
||||
size_t off_src = 0;
|
||||
for (size_t y0 = 0; y0 < sy; y0 += TILE_SIZE) {
|
||||
for (size_t x0 = 0; x0 < sx; x0 += TILE_SIZE) {
|
||||
size_t lim_x = MIN((size_t)sx, x0 + TILE_SIZE);
|
||||
size_t lim_y = MIN((size_t)sy, y0 + TILE_SIZE);
|
||||
|
||||
for (size_t y = y0; y < lim_y; y++) {
|
||||
for (size_t x = x0; x < lim_x; x++) {
|
||||
off_src = (x + y * sx) * 4;
|
||||
|
||||
off_dst = get_dst_position(off_src,
|
||||
info->cx,
|
||||
info->cy, x,
|
||||
y, orient);
|
||||
|
||||
memcpy(data + off_dst, src + off_src,
|
||||
4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bfree(in_data);
|
||||
return data;
|
||||
}
|
||||
|
||||
static void *ffmpeg_image_reformat_frame(struct ffmpeg_image *info,
|
||||
AVFrame *frame,
|
||||
enum gs_image_alpha_mode alpha_mode)
|
||||
@ -152,6 +359,19 @@ static void *ffmpeg_image_reformat_frame(struct ffmpeg_image *info,
|
||||
void *data = NULL;
|
||||
int ret = 0;
|
||||
|
||||
AVDictionary *dict = frame->metadata;
|
||||
AVDictionaryEntry *entry = NULL;
|
||||
|
||||
int orient = 0;
|
||||
|
||||
if (dict) {
|
||||
entry = av_dict_get(dict, "Orientation", NULL,
|
||||
AV_DICT_MATCH_CASE);
|
||||
if (entry && entry->value) {
|
||||
orient = atoi(entry->value);
|
||||
}
|
||||
}
|
||||
|
||||
if (info->format == AV_PIX_FMT_BGR0) {
|
||||
data = ffmpeg_image_copy_data_straight(info, frame);
|
||||
} else if (info->format == AV_PIX_FMT_RGBA ||
|
||||
@ -321,6 +541,8 @@ static void *ffmpeg_image_reformat_frame(struct ffmpeg_image *info,
|
||||
info->format = format;
|
||||
}
|
||||
|
||||
data = ffmpeg_image_orient(info, data, orient);
|
||||
|
||||
fail:
|
||||
return data;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user