mirror of
https://github.com/LostArtefacts/TRX.git
synced 2025-04-28 12:47:58 +03:00
picture: move to libtrx
This commit is contained in:
parent
9061c915c9
commit
84cc44df0a
11 changed files with 36 additions and 658 deletions
|
@ -233,7 +233,6 @@ sources = [
|
|||
'src/game/phase/phase_pause.c',
|
||||
'src/game/phase/phase_picture.c',
|
||||
'src/game/phase/phase_stats.c',
|
||||
'src/game/picture.c',
|
||||
'src/game/random.c',
|
||||
'src/game/requester.c',
|
||||
'src/game/room.c',
|
||||
|
@ -273,7 +272,6 @@ sources = [
|
|||
'src/specific/s_fmv.c',
|
||||
'src/specific/s_input.c',
|
||||
'src/specific/s_output.c',
|
||||
'src/specific/s_picture.c',
|
||||
'src/specific/s_shell.c',
|
||||
resources,
|
||||
]
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include "game/gamebuf.h"
|
||||
#include "game/overlay.h"
|
||||
#include "game/phase/phase.h"
|
||||
#include "game/picture.h"
|
||||
#include "game/random.h"
|
||||
#include "game/viewport.h"
|
||||
#include "global/const.h"
|
||||
|
@ -18,6 +17,8 @@
|
|||
#include "specific/s_output.h"
|
||||
#include "specific/s_shell.h"
|
||||
|
||||
#include <libtrx/engine/image.h>
|
||||
#include <libtrx/filesystem.h>
|
||||
#include <libtrx/memory.h>
|
||||
#include <libtrx/utils.h>
|
||||
|
||||
|
@ -59,7 +60,10 @@ static XYZ_32 m_LsVectorView = { 0 };
|
|||
static int32_t m_LightningCount = 0;
|
||||
static LIGHTNING m_LightningTable[MAX_LIGHTNINGS];
|
||||
|
||||
char *m_BackdropImagePath = NULL;
|
||||
static char *m_BackdropImagePath = NULL;
|
||||
static const char *m_ImageExtensions[] = {
|
||||
".png", ".jpg", ".jpeg", ".pcx", NULL,
|
||||
};
|
||||
|
||||
static void Output_DrawBlackOverlay(uint8_t alpha);
|
||||
|
||||
|
@ -950,18 +954,18 @@ void Output_LoadBackdropImage(const char *filename)
|
|||
}
|
||||
|
||||
const char *old_path = m_BackdropImagePath;
|
||||
m_BackdropImagePath = Memory_DupStr(filename);
|
||||
m_BackdropImagePath = File_GuessExtension(filename, m_ImageExtensions);
|
||||
Memory_FreePointer(&old_path);
|
||||
|
||||
PICTURE *orig_pic = Picture_CreateFromFile(m_BackdropImagePath);
|
||||
if (orig_pic) {
|
||||
PICTURE *scaled_pic = Picture_ScaleSmart(
|
||||
orig_pic, Viewport_GetWidth(), Viewport_GetHeight());
|
||||
if (scaled_pic) {
|
||||
S_Output_DownloadBackdropSurface(scaled_pic);
|
||||
Picture_Free(scaled_pic);
|
||||
IMAGE *orig_img = Image_CreateFromFile(m_BackdropImagePath);
|
||||
if (orig_img) {
|
||||
IMAGE *scaled_img = Image_ScaleSmart(
|
||||
orig_img, Viewport_GetWidth(), Viewport_GetHeight());
|
||||
if (scaled_img) {
|
||||
S_Output_DownloadBackdropSurface(scaled_img);
|
||||
Image_Free(scaled_img);
|
||||
}
|
||||
Picture_Free(orig_pic);
|
||||
Image_Free(orig_img);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,84 +0,0 @@
|
|||
#include "game/picture.h"
|
||||
|
||||
#include "specific/s_picture.h"
|
||||
|
||||
#include <libtrx/filesystem.h>
|
||||
#include <libtrx/memory.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
static const char *m_Extensions[] = {
|
||||
".png", ".jpg", ".jpeg", ".pcx", NULL,
|
||||
};
|
||||
|
||||
PICTURE *Picture_Create(int width, int height)
|
||||
{
|
||||
PICTURE *picture = Memory_Alloc(sizeof(PICTURE));
|
||||
picture->width = width;
|
||||
picture->height = height;
|
||||
picture->data = Memory_Alloc(width * height * sizeof(RGB_888));
|
||||
return picture;
|
||||
}
|
||||
|
||||
PICTURE *Picture_CreateFromFile(const char *path)
|
||||
{
|
||||
char *final_path = File_GuessExtension(path, m_Extensions);
|
||||
PICTURE *picture = S_Picture_CreateFromFile(final_path);
|
||||
Memory_FreePointer(&final_path);
|
||||
return picture;
|
||||
}
|
||||
|
||||
bool Picture_SaveToFile(const PICTURE *pic, const char *path)
|
||||
{
|
||||
assert(pic);
|
||||
assert(path);
|
||||
return S_Picture_SaveToFile(pic, path);
|
||||
}
|
||||
|
||||
PICTURE *Picture_ScaleLetterbox(
|
||||
const PICTURE *source_pic, size_t target_width, size_t target_height)
|
||||
{
|
||||
assert(source_pic);
|
||||
return S_Picture_ScaleLetterbox(source_pic, target_width, target_height);
|
||||
}
|
||||
|
||||
PICTURE *Picture_ScaleCrop(
|
||||
const PICTURE *source_pic, size_t target_width, size_t target_height)
|
||||
{
|
||||
assert(source_pic);
|
||||
return S_Picture_ScaleCrop(source_pic, target_width, target_height);
|
||||
}
|
||||
|
||||
PICTURE *Picture_ScaleSmart(
|
||||
const PICTURE *source_pic, size_t target_width, size_t target_height)
|
||||
{
|
||||
assert(source_pic);
|
||||
const float source_ratio = source_pic->width / (float)source_pic->height;
|
||||
const float target_ratio = target_width / (float)target_height;
|
||||
|
||||
// if the difference between aspect ratios is under 10%, just stretch it
|
||||
const float ar_diff =
|
||||
(source_ratio > target_ratio ? source_ratio / target_ratio
|
||||
: target_ratio / source_ratio)
|
||||
- 1.0f;
|
||||
if (ar_diff <= 0.1f) {
|
||||
return S_Picture_ScaleStretch(source_pic, target_width, target_height);
|
||||
}
|
||||
|
||||
// if the viewport is too wide, center the image
|
||||
if (source_ratio <= target_ratio) {
|
||||
return S_Picture_ScaleLetterbox(
|
||||
source_pic, target_width, target_height);
|
||||
}
|
||||
|
||||
// if the image is too wide, crop the image
|
||||
return S_Picture_ScaleCrop(source_pic, target_width, target_height);
|
||||
}
|
||||
|
||||
void Picture_Free(PICTURE *picture)
|
||||
{
|
||||
if (picture) {
|
||||
Memory_FreePointer(&picture->data);
|
||||
}
|
||||
Memory_FreePointer(&picture);
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "global/types.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
PICTURE *Picture_Create(int width, int height);
|
||||
PICTURE *Picture_CreateFromFile(const char *path);
|
||||
void Picture_Free(PICTURE *picture);
|
||||
|
||||
bool Picture_SaveToFile(const PICTURE *pic, const char *path);
|
||||
|
||||
PICTURE *Picture_ScaleFit(
|
||||
const PICTURE *source_pic, size_t target_width, size_t target_height);
|
||||
PICTURE *Picture_ScaleCover(
|
||||
const PICTURE *source_pic, size_t target_width, size_t target_height);
|
||||
PICTURE *Picture_ScaleSmart(
|
||||
const PICTURE *source_pic, size_t target_width, size_t target_height);
|
|
@ -1,8 +1,8 @@
|
|||
#include "gfx/screenshot.h"
|
||||
|
||||
#include "game/picture.h"
|
||||
#include "global/types.h"
|
||||
|
||||
#include <libtrx/engine/image.h>
|
||||
#include <libtrx/memory.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
@ -17,17 +17,17 @@ bool GFX_Screenshot_CaptureToFile(const char *path)
|
|||
GFX_Screenshot_CaptureToBuffer(
|
||||
NULL, &width, &height, 3, GL_RGB, GL_UNSIGNED_BYTE, true);
|
||||
|
||||
PICTURE *pic = Picture_Create(width, height);
|
||||
assert(pic);
|
||||
IMAGE *image = Image_Create(width, height);
|
||||
assert(image);
|
||||
|
||||
GFX_Screenshot_CaptureToBuffer(
|
||||
(uint8_t *)pic->data, &width, &height, 3, GL_RGB, GL_UNSIGNED_BYTE,
|
||||
(uint8_t *)image->data, &width, &height, 3, GL_RGB, GL_UNSIGNED_BYTE,
|
||||
true);
|
||||
|
||||
ret = Picture_SaveToFile(pic, path);
|
||||
ret = Image_SaveToFile(image, path);
|
||||
|
||||
if (pic) {
|
||||
Picture_Free(pic);
|
||||
if (image) {
|
||||
Image_Free(image);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -1985,12 +1985,6 @@ typedef struct SAMPLE_INFO {
|
|||
int16_t flags;
|
||||
} SAMPLE_INFO;
|
||||
|
||||
typedef struct PICTURE {
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
RGB_888 *data;
|
||||
} PICTURE;
|
||||
|
||||
typedef union INPUT_STATE {
|
||||
uint64_t any;
|
||||
struct {
|
||||
|
|
|
@ -475,9 +475,9 @@ void S_Output_DrawBackdropSurface(void)
|
|||
GFX_2D_Renderer_Render(m_Renderer2D);
|
||||
}
|
||||
|
||||
void S_Output_DownloadBackdropSurface(const PICTURE *pic)
|
||||
void S_Output_DownloadBackdropSurface(const IMAGE *const image)
|
||||
{
|
||||
if (!pic) {
|
||||
if (!image) {
|
||||
if (m_PictureSurface) {
|
||||
bool result = GFX_2D_Surface_Clear(m_PictureSurface);
|
||||
S_Output_CheckError(result);
|
||||
|
@ -490,8 +490,8 @@ void S_Output_DownloadBackdropSurface(const PICTURE *pic)
|
|||
// first, download the picture directly to a temporary surface
|
||||
{
|
||||
GFX_2D_SurfaceDesc surface_desc = {
|
||||
.width = pic->width,
|
||||
.height = pic->height,
|
||||
.width = image->width,
|
||||
.height = image->height,
|
||||
};
|
||||
picture_surface = GFX_2D_Surface_Create(&surface_desc);
|
||||
}
|
||||
|
@ -502,8 +502,8 @@ void S_Output_DownloadBackdropSurface(const PICTURE *pic)
|
|||
S_Output_CheckError(result);
|
||||
|
||||
uint32_t *output_ptr = surface_desc.pixels;
|
||||
RGB_888 *input_ptr = pic->data;
|
||||
for (int i = 0; i < pic->width * pic->height; i++) {
|
||||
IMAGE_PIXEL *input_ptr = image->data;
|
||||
for (int i = 0; i < image->width * image->height; i++) {
|
||||
uint8_t r = input_ptr->r;
|
||||
uint8_t g = input_ptr->g;
|
||||
uint8_t b = input_ptr->b;
|
||||
|
@ -525,8 +525,8 @@ void S_Output_DownloadBackdropSurface(const PICTURE *pic)
|
|||
|
||||
int32_t target_width = m_SurfaceWidth;
|
||||
int32_t target_height = m_SurfaceHeight;
|
||||
int32_t source_width = pic->width;
|
||||
int32_t source_height = pic->height;
|
||||
int32_t source_width = image->width;
|
||||
int32_t source_height = image->height;
|
||||
|
||||
// keep aspect ratio and fit inside, adding black bars on the sides
|
||||
const float source_ratio = source_width / (float)source_height;
|
||||
|
@ -541,8 +541,8 @@ void S_Output_DownloadBackdropSurface(const PICTURE *pic)
|
|||
GFX_BlitterRect source_rect = {
|
||||
.left = 0,
|
||||
.top = 0,
|
||||
.right = pic->width,
|
||||
.bottom = pic->height,
|
||||
.right = image->width,
|
||||
.bottom = image->height,
|
||||
};
|
||||
GFX_BlitterRect target_rect = {
|
||||
.left = (target_width - new_width) / 2,
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include "game/picture.h"
|
||||
#include "global/types.h"
|
||||
|
||||
#include <libtrx/engine/image.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
@ -27,7 +28,7 @@ RGB_888 S_Output_GetPaletteColor(uint8_t idx);
|
|||
|
||||
void S_Output_DownloadTextures(int32_t pages);
|
||||
void S_Output_SelectTexture(int tex_num);
|
||||
void S_Output_DownloadBackdropSurface(const PICTURE *pic);
|
||||
void S_Output_DownloadBackdropSurface(const IMAGE *image);
|
||||
void S_Output_DrawBackdropSurface(void);
|
||||
|
||||
void S_Output_DrawFlatTriangle(
|
||||
|
|
|
@ -1,500 +0,0 @@
|
|||
#include "specific/s_picture.h"
|
||||
|
||||
#include "game/picture.h"
|
||||
|
||||
#include <libtrx/filesystem.h>
|
||||
#include <libtrx/log.h>
|
||||
#include <libtrx/memory.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavcodec/codec.h>
|
||||
#include <libavcodec/codec_id.h>
|
||||
#include <libavcodec/packet.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavutil/avutil.h>
|
||||
#include <libavutil/error.h>
|
||||
#include <libavutil/frame.h>
|
||||
#include <libavutil/imgutils.h>
|
||||
#include <libavutil/mem.h>
|
||||
#include <libavutil/pixfmt.h>
|
||||
#include <libavutil/rational.h>
|
||||
#include <libswscale/swscale.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
PICTURE *S_Picture_CreateFromFile(const char *path)
|
||||
{
|
||||
int error_code;
|
||||
AVFormatContext *format_ctx = NULL;
|
||||
const AVCodec *codec = NULL;
|
||||
AVCodecContext *codec_ctx = NULL;
|
||||
AVFrame *frame = NULL;
|
||||
AVPacket *packet = NULL;
|
||||
struct SwsContext *sws_ctx = NULL;
|
||||
uint8_t *dst_data[4] = { 0 };
|
||||
int dst_linesize[4] = { 0 };
|
||||
PICTURE *target_pic = NULL;
|
||||
|
||||
char *full_path = File_GetFullPath(path);
|
||||
error_code = avformat_open_input(&format_ctx, full_path, NULL, NULL);
|
||||
Memory_FreePointer(&full_path);
|
||||
if (error_code != 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
error_code = avformat_find_stream_info(format_ctx, NULL);
|
||||
if (error_code < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
AVStream *video_stream = NULL;
|
||||
for (unsigned int i = 0; i < format_ctx->nb_streams; i++) {
|
||||
AVStream *current_stream = format_ctx->streams[i];
|
||||
if (current_stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
|
||||
video_stream = current_stream;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!video_stream) {
|
||||
error_code = AVERROR_STREAM_NOT_FOUND;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
codec = avcodec_find_decoder(video_stream->codecpar->codec_id);
|
||||
if (!codec) {
|
||||
error_code = AVERROR_DEMUXER_NOT_FOUND;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
codec_ctx = avcodec_alloc_context3(codec);
|
||||
if (!codec_ctx) {
|
||||
error_code = AVERROR(ENOMEM);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
error_code =
|
||||
avcodec_parameters_to_context(codec_ctx, video_stream->codecpar);
|
||||
if (error_code) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
error_code = avcodec_open2(codec_ctx, codec, NULL);
|
||||
if (error_code < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
packet = av_packet_alloc();
|
||||
av_new_packet(packet, 0);
|
||||
error_code = av_read_frame(format_ctx, packet);
|
||||
if (error_code < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
error_code = avcodec_send_packet(codec_ctx, packet);
|
||||
if (error_code < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
frame = av_frame_alloc();
|
||||
if (!frame) {
|
||||
error_code = AVERROR(ENOMEM);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
error_code = avcodec_receive_frame(codec_ctx, frame);
|
||||
if (error_code < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
target_pic = Picture_Create(frame->width, frame->height);
|
||||
|
||||
sws_ctx = sws_getContext(
|
||||
codec_ctx->width, codec_ctx->height, codec_ctx->pix_fmt,
|
||||
target_pic->width, target_pic->height, AV_PIX_FMT_RGB24, SWS_BILINEAR,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
if (!sws_ctx) {
|
||||
LOG_ERROR("Failed to get SWS context");
|
||||
error_code = AVERROR_EXTERNAL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
error_code = av_image_alloc(
|
||||
dst_data, dst_linesize, target_pic->width, target_pic->height,
|
||||
AV_PIX_FMT_RGB24, 1);
|
||||
if (error_code < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
sws_scale(
|
||||
sws_ctx, (const uint8_t *const *)frame->data, frame->linesize, 0,
|
||||
frame->height, dst_data, dst_linesize);
|
||||
|
||||
av_image_copy_to_buffer(
|
||||
(uint8_t *)target_pic->data,
|
||||
target_pic->width * target_pic->height * sizeof(RGB_888),
|
||||
(const uint8_t *const *)dst_data, dst_linesize, AV_PIX_FMT_RGB24,
|
||||
target_pic->width, target_pic->height, 1);
|
||||
|
||||
error_code = 0;
|
||||
goto success;
|
||||
|
||||
cleanup:
|
||||
if (target_pic) {
|
||||
Picture_Free(target_pic);
|
||||
target_pic = NULL;
|
||||
}
|
||||
|
||||
if (error_code) {
|
||||
LOG_ERROR(
|
||||
"Error while opening picture %s: %s", path, av_err2str(error_code));
|
||||
}
|
||||
|
||||
success:
|
||||
av_freep(&dst_data[0]);
|
||||
|
||||
if (sws_ctx) {
|
||||
sws_freeContext(sws_ctx);
|
||||
}
|
||||
|
||||
if (packet) {
|
||||
av_packet_free(&packet);
|
||||
}
|
||||
|
||||
if (frame) {
|
||||
av_frame_free(&frame);
|
||||
}
|
||||
|
||||
if (codec_ctx) {
|
||||
avcodec_close(codec_ctx);
|
||||
av_free(codec_ctx);
|
||||
codec_ctx = NULL;
|
||||
}
|
||||
|
||||
if (format_ctx) {
|
||||
avformat_close_input(&format_ctx);
|
||||
}
|
||||
|
||||
return target_pic;
|
||||
}
|
||||
|
||||
bool S_Picture_SaveToFile(const PICTURE *pic, const char *path)
|
||||
{
|
||||
assert(pic);
|
||||
assert(path);
|
||||
|
||||
bool ret = false;
|
||||
|
||||
int error_code = 0;
|
||||
const AVCodec *codec = NULL;
|
||||
AVCodecContext *codec_ctx = NULL;
|
||||
AVFrame *frame = NULL;
|
||||
AVPacket *packet = NULL;
|
||||
struct SwsContext *sws_ctx = NULL;
|
||||
MYFILE *fp = NULL;
|
||||
|
||||
enum AVPixelFormat source_pix_fmt = AV_PIX_FMT_RGB24;
|
||||
enum AVPixelFormat target_pix_fmt;
|
||||
enum AVCodecID codec_id;
|
||||
|
||||
if (strstr(path, ".jpg")) {
|
||||
target_pix_fmt = AV_PIX_FMT_YUVJ420P;
|
||||
codec_id = AV_CODEC_ID_MJPEG;
|
||||
} else if (strstr(path, ".png")) {
|
||||
target_pix_fmt = AV_PIX_FMT_RGB24;
|
||||
codec_id = AV_CODEC_ID_PNG;
|
||||
} else {
|
||||
LOG_ERROR("Cannot determine picture format based on path '%s'", path);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
fp = File_Open(path, FILE_OPEN_WRITE);
|
||||
if (!fp) {
|
||||
LOG_ERROR("Cannot create picture file: %s", path);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
codec = avcodec_find_encoder(codec_id);
|
||||
if (!codec) {
|
||||
error_code = AVERROR_MUXER_NOT_FOUND;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
codec_ctx = avcodec_alloc_context3(codec);
|
||||
if (!codec_ctx) {
|
||||
error_code = AVERROR(ENOMEM);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
codec_ctx->bit_rate = 400000;
|
||||
codec_ctx->width = pic->width;
|
||||
codec_ctx->height = pic->height;
|
||||
codec_ctx->time_base = (AVRational) { 1, 25 };
|
||||
codec_ctx->pix_fmt = target_pix_fmt;
|
||||
|
||||
if (codec_id == AV_CODEC_ID_MJPEG) {
|
||||
// 9 JPEG quality
|
||||
codec_ctx->flags |= AV_CODEC_FLAG_QSCALE;
|
||||
codec_ctx->global_quality = FF_QP2LAMBDA * 9;
|
||||
}
|
||||
|
||||
error_code = avcodec_open2(codec_ctx, codec, NULL);
|
||||
if (error_code < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
frame = av_frame_alloc();
|
||||
if (!frame) {
|
||||
error_code = AVERROR(ENOMEM);
|
||||
goto cleanup;
|
||||
}
|
||||
frame->format = codec_ctx->pix_fmt;
|
||||
frame->width = codec_ctx->width;
|
||||
frame->height = codec_ctx->height;
|
||||
frame->pts = 0;
|
||||
|
||||
error_code = av_image_alloc(
|
||||
frame->data, frame->linesize, codec_ctx->width, codec_ctx->height,
|
||||
codec_ctx->pix_fmt, 32);
|
||||
if (error_code < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
packet = av_packet_alloc();
|
||||
av_new_packet(packet, 0);
|
||||
|
||||
sws_ctx = sws_getContext(
|
||||
pic->width, pic->height, source_pix_fmt, frame->width, frame->height,
|
||||
target_pix_fmt, SWS_BILINEAR, NULL, NULL, NULL);
|
||||
|
||||
if (!sws_ctx) {
|
||||
LOG_ERROR("Failed to get SWS context");
|
||||
error_code = AVERROR_EXTERNAL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
uint8_t *src_planes[4];
|
||||
int src_linesize[4];
|
||||
av_image_fill_arrays(
|
||||
src_planes, src_linesize, (const uint8_t *)pic->data, source_pix_fmt,
|
||||
pic->width, pic->height, 1);
|
||||
|
||||
sws_scale(
|
||||
sws_ctx, (const uint8_t *const *)src_planes, src_linesize, 0,
|
||||
pic->height, frame->data, frame->linesize);
|
||||
|
||||
error_code = avcodec_send_frame(codec_ctx, frame);
|
||||
if (error_code < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
while (error_code >= 0) {
|
||||
error_code = avcodec_receive_packet(codec_ctx, packet);
|
||||
if (error_code == AVERROR(EAGAIN) || error_code == AVERROR_EOF) {
|
||||
error_code = 0;
|
||||
break;
|
||||
}
|
||||
if (error_code < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
File_WriteData(fp, packet->data, packet->size);
|
||||
av_packet_unref(packet);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (error_code) {
|
||||
LOG_ERROR(
|
||||
"Error while saving picture %s: %s", path, av_err2str(error_code));
|
||||
}
|
||||
|
||||
if (fp) {
|
||||
File_Close(fp);
|
||||
fp = NULL;
|
||||
}
|
||||
|
||||
if (sws_ctx) {
|
||||
sws_freeContext(sws_ctx);
|
||||
}
|
||||
|
||||
if (packet) {
|
||||
av_packet_free(&packet);
|
||||
}
|
||||
|
||||
if (codec) {
|
||||
avcodec_close(codec_ctx);
|
||||
av_free(codec_ctx);
|
||||
codec_ctx = NULL;
|
||||
}
|
||||
|
||||
if (frame) {
|
||||
av_freep(&frame->data[0]);
|
||||
av_frame_free(&frame);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
PICTURE *S_Picture_ScaleLetterbox(
|
||||
const PICTURE *source_pic, int target_width, int target_height)
|
||||
{
|
||||
assert(source_pic);
|
||||
assert(source_pic->data);
|
||||
|
||||
PICTURE *target_pic = NULL;
|
||||
int source_width = source_pic->width;
|
||||
int source_height = source_pic->height;
|
||||
|
||||
const float source_ratio = source_width / (float)source_height;
|
||||
const float target_ratio = target_width / (float)target_height;
|
||||
{
|
||||
int new_width = source_ratio < target_ratio
|
||||
? target_height * source_ratio
|
||||
: target_width;
|
||||
int new_height = source_ratio < target_ratio
|
||||
? target_height
|
||||
: target_width / source_ratio;
|
||||
target_width = new_width;
|
||||
target_height = new_height;
|
||||
}
|
||||
|
||||
struct SwsContext *sws_ctx = sws_getContext(
|
||||
source_width, source_height, AV_PIX_FMT_RGB24, target_width,
|
||||
target_height, AV_PIX_FMT_RGB24, SWS_BILINEAR, NULL, NULL, NULL);
|
||||
|
||||
if (!sws_ctx) {
|
||||
LOG_ERROR("Failed to get SWS context");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
target_pic = Picture_Create(target_width, target_height);
|
||||
|
||||
uint8_t *src_planes[4];
|
||||
uint8_t *dst_planes[4];
|
||||
int src_linesize[4];
|
||||
int dst_linesize[4];
|
||||
|
||||
av_image_fill_arrays(
|
||||
src_planes, src_linesize, (const uint8_t *)source_pic->data,
|
||||
AV_PIX_FMT_RGB24, source_width, source_height, 1);
|
||||
|
||||
av_image_fill_arrays(
|
||||
dst_planes, dst_linesize, (const uint8_t *)target_pic->data,
|
||||
AV_PIX_FMT_RGB24, target_pic->width, target_pic->height, 1);
|
||||
|
||||
sws_scale(
|
||||
sws_ctx, (const uint8_t *const *)src_planes, src_linesize, 0,
|
||||
source_height, (uint8_t *const *)dst_planes, dst_linesize);
|
||||
|
||||
cleanup:
|
||||
if (sws_ctx) {
|
||||
sws_freeContext(sws_ctx);
|
||||
}
|
||||
|
||||
return target_pic;
|
||||
}
|
||||
|
||||
PICTURE *S_Picture_ScaleCrop(
|
||||
const PICTURE *source_pic, int target_width, int target_height)
|
||||
{
|
||||
assert(source_pic);
|
||||
assert(source_pic->data);
|
||||
|
||||
PICTURE *target_pic = NULL;
|
||||
int source_width = source_pic->width;
|
||||
int source_height = source_pic->height;
|
||||
|
||||
const float source_ratio = source_width / (float)source_height;
|
||||
const float target_ratio = target_width / (float)target_height;
|
||||
|
||||
int crop_width = source_ratio < target_ratio ? source_width
|
||||
: source_height * target_ratio;
|
||||
int crop_height = source_ratio < target_ratio ? source_width / target_ratio
|
||||
: source_height;
|
||||
|
||||
struct SwsContext *sws_ctx = sws_getContext(
|
||||
crop_width, crop_height, AV_PIX_FMT_RGB24, target_width, target_height,
|
||||
AV_PIX_FMT_RGB24, SWS_BILINEAR, NULL, NULL, NULL);
|
||||
|
||||
if (!sws_ctx) {
|
||||
LOG_ERROR("Failed to get SWS context");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
target_pic = Picture_Create(target_width, target_height);
|
||||
|
||||
uint8_t *src_planes[4];
|
||||
uint8_t *dst_planes[4];
|
||||
int src_linesize[4];
|
||||
int dst_linesize[4];
|
||||
|
||||
av_image_fill_arrays(
|
||||
src_planes, src_linesize, (const uint8_t *)source_pic->data,
|
||||
AV_PIX_FMT_RGB24, source_width, source_height, 1);
|
||||
|
||||
src_planes[0] += ((source_height - crop_height) / 2) * src_linesize[0];
|
||||
src_planes[0] += ((source_width - crop_width) / 2) * sizeof(RGB_888);
|
||||
|
||||
av_image_fill_arrays(
|
||||
dst_planes, dst_linesize, (const uint8_t *)target_pic->data,
|
||||
AV_PIX_FMT_RGB24, target_pic->width, target_pic->height, 1);
|
||||
|
||||
sws_scale(
|
||||
sws_ctx, (const uint8_t *const *)src_planes, src_linesize, 0,
|
||||
crop_height, (uint8_t *const *)dst_planes, dst_linesize);
|
||||
|
||||
cleanup:
|
||||
if (sws_ctx) {
|
||||
sws_freeContext(sws_ctx);
|
||||
}
|
||||
|
||||
return target_pic;
|
||||
}
|
||||
|
||||
PICTURE *S_Picture_ScaleStretch(
|
||||
const PICTURE *source_pic, int target_width, int target_height)
|
||||
{
|
||||
assert(source_pic);
|
||||
assert(source_pic->data);
|
||||
|
||||
PICTURE *target_pic = NULL;
|
||||
int source_width = source_pic->width;
|
||||
int source_height = source_pic->height;
|
||||
|
||||
struct SwsContext *sws_ctx = sws_getContext(
|
||||
source_width, source_height, AV_PIX_FMT_RGB24, target_width,
|
||||
target_height, AV_PIX_FMT_RGB24, SWS_BILINEAR, NULL, NULL, NULL);
|
||||
|
||||
if (!sws_ctx) {
|
||||
LOG_ERROR("Failed to get SWS context");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
target_pic = Picture_Create(target_width, target_height);
|
||||
|
||||
uint8_t *src_planes[4];
|
||||
uint8_t *dst_planes[4];
|
||||
int src_linesize[4];
|
||||
int dst_linesize[4];
|
||||
|
||||
av_image_fill_arrays(
|
||||
src_planes, src_linesize, (const uint8_t *)source_pic->data,
|
||||
AV_PIX_FMT_RGB24, source_width, source_height, 1);
|
||||
|
||||
av_image_fill_arrays(
|
||||
dst_planes, dst_linesize, (const uint8_t *)target_pic->data,
|
||||
AV_PIX_FMT_RGB24, target_pic->width, target_pic->height, 1);
|
||||
|
||||
sws_scale(
|
||||
sws_ctx, (const uint8_t *const *)src_planes, src_linesize, 0,
|
||||
source_height, (uint8_t *const *)dst_planes, dst_linesize);
|
||||
|
||||
cleanup:
|
||||
if (sws_ctx) {
|
||||
sws_freeContext(sws_ctx);
|
||||
}
|
||||
|
||||
return target_pic;
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "global/types.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
PICTURE *S_Picture_CreateFromFile(const char *path);
|
||||
bool S_Picture_SaveToFile(const PICTURE *pic, const char *path);
|
||||
|
||||
PICTURE *S_Picture_ScaleLetterbox(
|
||||
const PICTURE *source_pic, int target_width, int target_height);
|
||||
PICTURE *S_Picture_ScaleCrop(
|
||||
const PICTURE *source_pic, int target_width, int target_height);
|
||||
PICTURE *S_Picture_ScaleStretch(
|
||||
const PICTURE *source_pic, int target_width, int target_height);
|
|
@ -1 +1 @@
|
|||
Subproject commit 444fd607a13d25abf1b11a488226c58af866b277
|
||||
Subproject commit ad9728191e112a4760671f76b69594756f58bd96
|
Loading…
Add table
Add a link
Reference in a new issue