from_lavc_vid_conv: make iternal state opaque

Return just a pointer (that needs to be detroyed after that).

This is perhaps more convenient way and also it will allow eg. utlizing
GPU for the conversions.
This commit is contained in:
Martin Pulec
2024-03-01 08:54:30 +01:00
parent 1825e6a0da
commit dcf882cc61
5 changed files with 111 additions and 88 deletions

View File

@@ -4,7 +4,7 @@
* @author Martin Piatka <445597@mail.muni.cz>
*/
/*
* Copyright (c) 2013-2023 CESNET, z. s. p. o.
* Copyright (c) 2013-2024 CESNET, z. s. p. o.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,12 +44,6 @@
* Some conversions to RGBA ignore RGB-shifts - either fix that or deprecate RGB-shifts
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#include "config_unix.h"
#include "config_win32.h"
#endif // HAVE_CONFIG_H
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
@@ -2181,13 +2175,12 @@ static void vuyx_to_y416(char * __restrict dst_buffer, AVFrame * __restrict in_f
typedef void av_to_uv_convert_f(char * __restrict dst_buffer, AVFrame * __restrict in_frame, int width, int height, int pitch, const int * __restrict rgb_shift);
typedef av_to_uv_convert_f *av_to_uv_convert_fp;
struct av_to_uv_convert_state_priv {
struct av_to_uv_convert_state {
av_to_uv_convert_fp convert;
codec_t src_pixfmt;
codec_t dst_pixfmt;
decoder_t dec;
};
_Static_assert(sizeof(struct av_to_uv_convert_state_priv) <= sizeof ((struct av_to_uv_convert_state *) 0)->priv_data, "increase av_to_uv_convert_state::priv_data size");
struct av_to_uv_conversion {
enum AVPixelFormat av_codec;
@@ -2325,18 +2318,18 @@ static const struct av_to_uv_conversion av_to_uv_conversions[] = {
#define AV_TO_UV_CONVERSION_COUNT (sizeof av_to_uv_conversions / sizeof av_to_uv_conversions[0])
static const struct av_to_uv_conversion *av_to_uv_conversions_end = av_to_uv_conversions + AV_TO_UV_CONVERSION_COUNT;
static void set_decoder_mapped_to_uv(av_to_uv_convert_t *ret, decoder_t dec,
codec_t dst_pixfmt) {
struct av_to_uv_convert_state_priv *priv = (void *) ret->priv_data;
priv->dec = dec;
priv->dst_pixfmt = dst_pixfmt;
ret->valid = true;
static void
set_decoder_mapped_to_uv(av_to_uv_convert_t *s, decoder_t dec,
codec_t dst_pixfmt)
{
s->dec = dec;
s->dst_pixfmt = dst_pixfmt;
}
static void set_decoder_memcpy(av_to_uv_convert_t *ret, codec_t color_spec) {
struct av_to_uv_convert_state_priv *priv = (void *) ret->priv_data;
priv->dst_pixfmt = color_spec;
ret->valid = true;
static void
set_decoder_memcpy(av_to_uv_convert_t *s, codec_t color_spec)
{
s->dst_pixfmt = color_spec;
}
static QSORT_S_COMP_DEFINE(compare_convs, a, b, orig_c) {
@@ -2376,22 +2369,33 @@ static decoder_t get_av_and_uv_conversion(enum AVPixelFormat av_codec, codec_t u
return NULL;
}
av_to_uv_convert_t get_av_to_uv_conversion(int av_codec, codec_t uv_codec) {
av_to_uv_convert_t ret = { .valid = false };
struct av_to_uv_convert_state_priv *priv = (void *) ret.priv_data;
void
av_to_uv_conversion_destroy(av_to_uv_convert_t **s)
{
if (s == NULL || *s == NULL) {
return;
}
free(*s);
*s = NULL;
}
av_to_uv_convert_t *get_av_to_uv_conversion(int av_codec, codec_t uv_codec) {
av_to_uv_convert_t *ret = calloc(1, sizeof *ret);
codec_t mapped_pix_fmt = get_av_to_ug_pixfmt(av_codec);
if (mapped_pix_fmt == uv_codec) {
if (codec_is_planar(uv_codec)) {
log_msg(LOG_LEVEL_ERROR, "Planar pixfmts not support here, please report a bug!\n");
} else {
set_decoder_memcpy(&ret, uv_codec);
free(ret);
return NULL;
}
set_decoder_memcpy(ret, uv_codec);
return ret;
} else if (mapped_pix_fmt) {
}
if (mapped_pix_fmt != VC_NONE) {
decoder_t dec = get_decoder_from_to(mapped_pix_fmt, uv_codec);
if (dec) {
set_decoder_mapped_to_uv(&ret, dec, uv_codec);
set_decoder_mapped_to_uv(ret, dec, uv_codec);
return ret;
}
}
@@ -2400,25 +2404,24 @@ av_to_uv_convert_t get_av_to_uv_conversion(int av_codec, codec_t uv_codec) {
conversions < av_to_uv_conversions_end; conversions++) {
if (conversions->av_codec == av_codec &&
conversions->uv_codec == uv_codec) {
priv->convert = conversions->convert;
ret.valid = true;
ret->convert = conversions->convert;
watch_pixfmt_degrade(MOD_NAME, av_pixfmt_get_desc(av_codec), get_pixfmt_desc(uv_codec));
return ret;
}
}
av_to_uv_convert_fp av_convert = NULL;
codec_t intermediate;
codec_t intermediate = VC_NONE;
decoder_t dec = get_av_and_uv_conversion(av_codec, uv_codec,
&intermediate, &av_convert);
if (!dec) {
return ret;
free(ret);
return NULL;
}
priv->dec = dec;
priv->convert = av_convert;
priv->src_pixfmt = intermediate;
priv->dst_pixfmt = uv_codec;
ret.valid = true;
ret->dec = dec;
ret->convert = av_convert;
ret->src_pixfmt = intermediate;
ret->dst_pixfmt = uv_codec;
watch_pixfmt_degrade(MOD_NAME, av_pixfmt_get_desc(av_codec), get_pixfmt_desc(intermediate));
watch_pixfmt_degrade(MOD_NAME, get_pixfmt_desc(intermediate), get_pixfmt_desc(uv_codec));
@@ -2497,11 +2500,13 @@ enum AVPixelFormat lavd_get_av_to_ug_codec(const enum AVPixelFormat *fmt, codec_
return get_ug_codec_to_av(fmt, &c, use_hwaccel);
}
enum AVPixelFormat pick_av_convertible_to_ug(codec_t color_spec, av_to_uv_convert_t *av_conv) {
av_conv->valid = false;
enum AVPixelFormat
pick_av_convertible_to_ug(codec_t color_spec, av_to_uv_convert_t **av_conv)
{
*av_conv = calloc(1, sizeof **av_conv);
if (get_ug_to_av_pixfmt(color_spec) != AV_PIX_FMT_NONE) {
set_decoder_memcpy(av_conv, color_spec);
set_decoder_memcpy(*av_conv, color_spec);
return get_ug_to_av_pixfmt(color_spec);
}
@@ -2509,58 +2514,66 @@ enum AVPixelFormat pick_av_convertible_to_ug(codec_t color_spec, av_to_uv_conver
decoder_t dec;
if (out_desc.rgb) {
if (out_desc.depth > 8 && (dec = get_decoder_from_to(RG48, color_spec))) {
set_decoder_mapped_to_uv(av_conv, dec, color_spec);
set_decoder_mapped_to_uv(*av_conv, dec, color_spec);
return AV_PIX_FMT_RGB48LE;
} else if ((dec = get_decoder_from_to(RGB, color_spec))) {
set_decoder_mapped_to_uv(av_conv, dec, color_spec);
set_decoder_mapped_to_uv(*av_conv, dec, color_spec);
return AV_PIX_FMT_RGB24;
}
}
#if XV3X_PRESENT
if (out_desc.depth > 8 && (dec = get_decoder_from_to(Y416, color_spec))) {
set_decoder_mapped_to_uv(av_conv, dec, color_spec);
set_decoder_mapped_to_uv(*av_conv, dec, color_spec);
return AV_PIX_FMT_XV36;
}
#endif
if ((dec = get_decoder_from_to(UYVY, color_spec))) {
set_decoder_mapped_to_uv(av_conv, dec, color_spec);
set_decoder_mapped_to_uv(*av_conv, dec, color_spec);
return AV_PIX_FMT_UYVY422;
}
for (const struct av_to_uv_conversion *c = av_to_uv_conversions; c < av_to_uv_conversions_end; c++) {
if (c->uv_codec == color_spec) { // pick any (first usable)
av_conv->valid = true;
struct av_to_uv_convert_state_priv *priv = (void *) av_conv->priv_data;
memset(priv, 0, sizeof *priv);
priv->convert = c->convert;
memset(*av_conv, 0, sizeof **av_conv);
(*av_conv)->convert = c->convert;
return c->av_codec;
}
}
free(*av_conv);
*av_conv = NULL;
return AV_PIX_FMT_NONE;
}
void av_to_uv_convert(const av_to_uv_convert_t *state, char * __restrict dst_buffer, AVFrame * __restrict in_frame, int width, int height, int pitch, const int * __restrict rgb_shift) {
const struct av_to_uv_convert_state_priv *priv = (const void *) state->priv_data;
void
av_to_uv_convert(const av_to_uv_convert_t *s, char *__restrict dst_buffer,
AVFrame *__restrict in_frame, int width, int height, int pitch,
const int *__restrict rgb_shift)
{
unsigned char *dec_input = in_frame->data[0];
size_t src_linesize = in_frame->linesize[0];
unsigned char *tmp = NULL;
if (priv->convert) {
if (s->convert) {
DEBUG_TIMER_START(lavd_av_to_uv);
if (!priv->dec) {
priv->convert(dst_buffer, in_frame, width, height, pitch, rgb_shift);
if (!s->dec) {
s->convert(dst_buffer, in_frame, width, height, pitch, rgb_shift);
DEBUG_TIMER_STOP(lavd_av_to_uv);
return;
}
src_linesize = vc_get_linesize(width, priv->src_pixfmt);
dec_input = tmp = malloc(vc_get_datalen(width, height, priv->src_pixfmt) + MAX_PADDING);
int default_rgb_shift[] = { DEFAULT_R_SHIFT, DEFAULT_G_SHIFT, DEFAULT_B_SHIFT };
priv->convert((char *) dec_input, in_frame, width, height, src_linesize, default_rgb_shift);
src_linesize = vc_get_linesize(width, s->src_pixfmt);
dec_input = tmp = malloc(
vc_get_datalen(width, height, s->src_pixfmt) + MAX_PADDING);
int default_rgb_shift[] = { DEFAULT_R_SHIFT, DEFAULT_G_SHIFT,
DEFAULT_B_SHIFT };
s->convert((char *) dec_input, in_frame, width, height,
src_linesize, default_rgb_shift);
DEBUG_TIMER_STOP(lavd_av_to_uv);
}
if (priv->dec) {
if (s->dec) {
DEBUG_TIMER_START(lavd_dec);
int dst_size = vc_get_size(width, priv->dst_pixfmt);
int dst_size = vc_get_size(width, s->dst_pixfmt);
for (ptrdiff_t i = 0; i < height; ++i) {
priv->dec((unsigned char *) dst_buffer + i * pitch, dec_input + i * src_linesize, dst_size, rgb_shift[0], rgb_shift[1], rgb_shift[2]);
s->dec((unsigned char *) dst_buffer + i * pitch,
dec_input + i * src_linesize, dst_size,
rgb_shift[0], rgb_shift[1], rgb_shift[2]);
}
DEBUG_TIMER_STOP(lavd_dec);
free(tmp);
@@ -2568,7 +2581,7 @@ void av_to_uv_convert(const av_to_uv_convert_t *state, char * __restrict dst_buf
}
// memcpy only
int linesize = vc_get_linesize(width, priv->dst_pixfmt);
int linesize = vc_get_linesize(width, s->dst_pixfmt);
for (ptrdiff_t i = 0; i < height; ++i) {
memcpy(dst_buffer + i * pitch, in_frame->data[0] + i * in_frame->linesize[0], linesize);
}

View File

@@ -44,7 +44,6 @@
#include "libavcodec/lavc_common.h"
#ifndef __cplusplus
#include <stdalign.h>
#include <stdbool.h>
#endif
@@ -53,18 +52,16 @@ extern "C" {
#endif
struct av_to_uv_convert_state;
typedef struct av_to_uv_convert_state av_to_uv_convert_t;
typedef struct av_to_uv_convert_state {
alignas(8) char priv_data[24];
bool valid;
} av_to_uv_convert_t;
av_to_uv_convert_t *get_av_to_uv_conversion(int av_codec, codec_t uv_codec);
void av_to_uv_convert(const av_to_uv_convert_t *s, char * __restrict dst_buffer, AVFrame * __restrict in_frame, int width, int height, int pitch, const int * __restrict rgb_shift);
void av_to_uv_conversion_destroy(av_to_uv_convert_t **);
void av_to_uv_convert(const av_to_uv_convert_t *state, char * __restrict dst_buffer, AVFrame * __restrict in_frame, int width, int height, int pitch, const int * __restrict rgb_shift);
av_to_uv_convert_t get_av_to_uv_conversion(int av_codec, codec_t uv_codec);
codec_t get_best_ug_codec_to_av(const enum AVPixelFormat *fmt, bool use_hwaccel);
enum AVPixelFormat lavd_get_av_to_ug_codec(const enum AVPixelFormat *fmt, codec_t c, bool use_hwaccel);
enum AVPixelFormat pick_av_convertible_to_ug(codec_t color_spec, av_to_uv_convert_t *av_conv);
enum AVPixelFormat pick_av_convertible_to_ug(codec_t color_spec,
av_to_uv_convert_t **av_conv);
#ifdef __cplusplus
}

View File

@@ -103,7 +103,7 @@ struct vidcap_state_lavf_decoder {
int thread_type;
struct SwsContext *sws_ctx;
av_to_uv_convert_t conv_uv;
av_to_uv_convert_t *conv_uv;
bool failed;
bool loop;
@@ -200,6 +200,8 @@ static void vidcap_file_common_cleanup(struct vidcap_state_lavf_decoder *s) {
avformat_close_input(&s->fmt_ctx);
}
av_to_uv_conversion_destroy(&s->conv_uv);
flush_captured_data(s);
ring_buffer_destroy(s->audio_data);
@@ -422,9 +424,9 @@ static struct video_frame *process_video_pkt(struct vidcap_state_lavf_decoder *s
int video_dst_linesize[4] = {
vc_get_linesize(out->tiles[0].width, out->color_spec)};
uint8_t *dst[4] = {(uint8_t *)out->tiles[0].data};
if (s->conv_uv.valid) {
if (s->conv_uv) {
int rgb_shift[] = DEFAULT_RGB_SHIFT_INIT;
av_to_uv_convert(&s->conv_uv, out->tiles[0].data, frame,
av_to_uv_convert(s->conv_uv, out->tiles[0].data, frame,
out->tiles[0].width, out->tiles[0].height,
video_dst_linesize[0], rgb_shift);
} else {
@@ -695,7 +697,7 @@ static bool setup_video(struct vidcap_state_lavf_decoder *s) {
}
s->conv_uv = get_av_to_uv_conversion(s->vid_ctx->pix_fmt,
s->video_desc.color_spec);
if (s->conv_uv.valid) {
if (s->conv_uv) {
return true;
}
// else swscale needed

View File

@@ -3,7 +3,7 @@
* @author Martin Pulec <pulec@cesnet.cz>
*/
/*
* Copyright (c) 2013-2023 CESNET, z. s. p. o.
* Copyright (c) 2013-2024 CESNET, z. s. p. o.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -83,7 +83,7 @@ struct state_libavcodec_decompress {
int max_compressed_len;
codec_t out_codec;
struct {
av_to_uv_convert_t convert;
av_to_uv_convert_t *convert;
enum AVPixelFormat convert_in;
};
bool block_accel[HWACCEL_COUNT];
@@ -109,6 +109,8 @@ static enum AVPixelFormat get_format_callback(struct AVCodecContext *s, const en
static void deconfigure(struct state_libavcodec_decompress *s)
{
av_to_uv_conversion_destroy(&s->convert);
if(s->codec_ctx) {
lavd_flush(s->codec_ctx);
avcodec_free_context(&s->codec_ctx);
@@ -818,8 +820,9 @@ static _Bool reconfigure_convert_if_needed(struct state_libavcodec_decompress *s
if (s->convert_in == av_codec) {
return 1;
}
av_to_uv_conversion_destroy(&s->convert);
s->convert = get_av_to_uv_conversion(av_codec, out_codec);
if (s->convert.valid) {
if (s->convert != NULL) {
s->convert_in = av_codec;
return 1;
}
@@ -862,9 +865,12 @@ static _Bool reconfigure_convert_if_needed(struct state_libavcodec_decompress *s
* @param width frame width
* @param height frame height
*/
static void change_pixfmt(AVFrame *frame, unsigned char *dst, const av_to_uv_convert_t *convert,
codec_t out_codec, int width, int height,
int pitch, int rgb_shift[static restrict 3], struct state_libavcodec_decompress_sws *sws) {
static void
change_pixfmt(AVFrame *frame, unsigned char *dst, av_to_uv_convert_t *convert,
codec_t out_codec, int width, int height, int pitch,
int rgb_shift[static restrict 3],
struct state_libavcodec_decompress_sws *sws)
{
debug_file_dump("lavd-avframe", serialize_video_avframe, frame);
if (!sws->ctx) {
@@ -1092,8 +1098,9 @@ static decompress_status libavcodec_decompress(void *state, unsigned char *dst,
if (!reconfigure_convert_if_needed(s, s->frame->format, s->out_codec, s->desc.width, s->desc.height)) {
return DECODER_UNSUPP_PIXFMT;
}
change_pixfmt(s->frame, dst, &s->convert, s->out_codec, s->desc.width,
s->desc.height, s->pitch, s->rgb_shift, &s->sws);
change_pixfmt(s->frame, dst, s->convert, s->out_codec,
s->desc.width, s->desc.height, s->pitch,
s->rgb_shift, &s->sws);
}
time_ns_t t2 = get_time_in_ns();
log_msg(LOG_LEVEL_DEBUG, MOD_NAME "Decompressing %c frame took %f ms, pixfmt change %f ms.\n", av_get_picture_type_char(s->frame->pict_type),

View File

@@ -66,14 +66,15 @@ int ff_codec_conversions_test_yuv444pXXle_from_to_r10k()
struct to_lavc_vid_conv *from_conv = to_lavc_vid_conv_init(R10k, width, height, avfmt, 1);
auto to_conv = get_av_to_uv_conversion(avfmt, R10k);
assert(to_conv.valid && from_conv != nullptr);
assert(to_conv != nullptr && from_conv != nullptr);
TIMER(t0);
AVFrame *converted = to_lavc_vid_conv(from_conv, (char *) r10k_buf.data());
TIMER(t1);
av_to_uv_convert(&to_conv, reinterpret_cast<char*>(r10k_buf.data()), converted, width, height, vc_get_linesize(width, R10k), nullptr);
av_to_uv_convert(to_conv, reinterpret_cast<char*>(r10k_buf.data()), converted, width, height, vc_get_linesize(width, R10k), nullptr);
TIMER(t2);
to_lavc_vid_conv_destroy(&from_conv);
av_to_uv_conversion_destroy(&to_conv);
if (getenv("PERF") != nullptr) {
cout << "test_yuv444p16le_from_to_r10k: duration - enc " << tv_diff(t1, t0) << ", dec " <<tv_diff(t2, t1) << "\n";
@@ -133,13 +134,14 @@ int ff_codec_conversions_test_yuv444pXXle_from_to_r12l()
struct to_lavc_vid_conv *from_conv = to_lavc_vid_conv_init(R12L, width, height, avfmt, 1);
auto to_conv = get_av_to_uv_conversion(avfmt, R12L);
assert(to_conv.valid && from_conv != nullptr);
assert(to_conv != nullptr && from_conv != nullptr);
TIMER(t0);
struct AVFrame *converted = to_lavc_vid_conv(from_conv, (char *) r12l_buf.data());
TIMER(t1);
av_to_uv_convert(&to_conv, reinterpret_cast<char*>(r12l_buf.data()), converted, width, height, vc_get_linesize(width, R12L), nullptr);
av_to_uv_convert(to_conv, reinterpret_cast<char*>(r12l_buf.data()), converted, width, height, vc_get_linesize(width, R12L), nullptr);
TIMER(t2);
av_to_uv_conversion_destroy(&to_conv);
to_lavc_vid_conv_destroy(&from_conv);
if (getenv("PERF") != nullptr) {
@@ -189,13 +191,14 @@ static void yuv444p16le_rg48_encode_decode(int width, int height, char *in, char
struct to_lavc_vid_conv *from_conv = to_lavc_vid_conv_init(RG48, width, height, avfmt, 1);
auto to_conv = get_av_to_uv_conversion(avfmt, RG48);
assert(to_conv.valid && from_conv != nullptr);
assert(to_conv && from_conv != nullptr);
TIMER(t0);
struct AVFrame *converted = to_lavc_vid_conv(from_conv, in);
TIMER(t1);
av_to_uv_convert(&to_conv, reinterpret_cast<char*>(out), converted, width, height, vc_get_linesize(width, RG48), nullptr);
av_to_uv_convert(to_conv, reinterpret_cast<char*>(out), converted, width, height, vc_get_linesize(width, RG48), nullptr);
TIMER(t2);
av_to_uv_conversion_destroy(&to_conv);
to_lavc_vid_conv_destroy(&from_conv);
if (getenv("PERF") != nullptr) {
@@ -366,10 +369,11 @@ int ff_codec_conversions_test_pX10_from_to_v210()
struct to_lavc_vid_conv *from_conv = to_lavc_vid_conv_init(codec, width, height, c, 1);
auto to_conv = get_av_to_uv_conversion(c, codec);
assert(from_conv != nullptr);
assert(to_conv.valid);
assert(to_conv != nullptr);
struct AVFrame *converted = to_lavc_vid_conv(from_conv, (char *) in.data());
av_to_uv_convert(&to_conv, reinterpret_cast<char *>(out.data()), converted, width, height, vc_get_linesize(width, codec), nullptr);
av_to_uv_convert(to_conv, reinterpret_cast<char *>(out.data()), converted, width, height, vc_get_linesize(width, codec), nullptr);
av_to_uv_conversion_destroy(&to_conv);
to_lavc_vid_conv_destroy(&from_conv);
if (getenv("DEBUG_DUMP") != nullptr) {