1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2025-12-20 14:16:06 +02:00
Files
FFmpeg/libavcodec/libsvtjpegxsdec.c
2025-12-14 18:22:04 -03:00

229 lines
7.7 KiB
C

/*
* Copyright(c) 2024 Intel Corporation
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* Copyright(c) 2024 Intel Corporation
* SPDX - License - Identifier: BSD - 2 - Clause - Patent
*/
#include <SvtJpegxsDec.h>
#include "libavutil/mem.h"
#include "libavutil/common.h"
#include "libavutil/cpu.h"
#include "libavutil/imgutils.h"
#include "libavutil/avassert.h"
#include "avcodec.h"
#include "codec_internal.h"
#include "decode.h"
#include "profiles.h"
typedef struct SvtJpegXsDecodeContext {
svt_jpeg_xs_image_config_t config;
svt_jpeg_xs_decoder_api_t decoder;
svt_jpeg_xs_frame_t input;
svt_jpeg_xs_frame_t output;
uint32_t decoder_initialized;
int proxy_mode;
} SvtJpegXsDecodeContext;
static int set_pix_fmt(void *logctx, const svt_jpeg_xs_image_config_t *config)
{
int ret = AVERROR_BUG;
switch (config->format) {
case COLOUR_FORMAT_PLANAR_YUV420:
if (config->bit_depth == 8)
return AV_PIX_FMT_YUV420P;
else if (config->bit_depth == 10)
return AV_PIX_FMT_YUV420P10LE;
else if (config->bit_depth == 12)
return AV_PIX_FMT_YUV420P12LE;
else
return AV_PIX_FMT_YUV420P14LE;
break;
case COLOUR_FORMAT_PLANAR_YUV422:
if (config->bit_depth == 8)
return AV_PIX_FMT_YUV422P;
else if (config->bit_depth == 10)
return AV_PIX_FMT_YUV422P10LE;
else if (config->bit_depth == 12)
return AV_PIX_FMT_YUV422P12LE;
else
return AV_PIX_FMT_YUV422P14LE;
break;
case COLOUR_FORMAT_PLANAR_YUV444_OR_RGB:
if (config->bit_depth == 8)
return AV_PIX_FMT_YUV444P;
else if (config->bit_depth == 10)
return AV_PIX_FMT_YUV444P10LE;
else if (config->bit_depth == 12)
return AV_PIX_FMT_YUV444P12LE;
else
return AV_PIX_FMT_YUV444P14LE;
break;
default:
av_log(logctx, AV_LOG_ERROR, "Unsupported pixel format.\n");
ret = AVERROR_INVALIDDATA;
break;
}
return ret;
}
static int svt_jpegxs_dec_decode(AVCodecContext* avctx, AVFrame* picture, int* got_frame, AVPacket* avpkt)
{
SvtJpegXsDecodeContext* svt_dec = avctx->priv_data;
SvtJxsErrorType_t err = SvtJxsErrorNone;
uint32_t frame_size;
int ret;
err = svt_jpeg_xs_decoder_get_single_frame_size_with_proxy(
avpkt->data, avpkt->size, &svt_dec->config, &frame_size, 1 /*quick search*/, svt_dec->decoder.proxy_mode);
if (err) {
av_log(avctx, AV_LOG_ERROR, "svt_jpeg_xs_decoder_get_single_frame_size_with_proxy failed, err=%d\n", err);
return AVERROR_EXTERNAL;
}
if (avpkt->size < frame_size) {
av_log(avctx, AV_LOG_ERROR, "Not enough data in a packet.\n");
return AVERROR(EINVAL);
}
if (avpkt->size > frame_size) {
av_log(avctx, AV_LOG_ERROR, "Single packet have data for more than one frame.\n");
return AVERROR(EINVAL);
}
ret = set_pix_fmt(avctx, &svt_dec->config);
if (ret < 0)
return ret;
if (!svt_dec->decoder_initialized || ret != avctx->pix_fmt ||
avctx->width != svt_dec->config.width || avctx->height != svt_dec->config.height) {
if (svt_dec->decoder_initialized)
svt_jpeg_xs_decoder_close(&svt_dec->decoder);
err = svt_jpeg_xs_decoder_init(SVT_JPEGXS_API_VER_MAJOR, SVT_JPEGXS_API_VER_MINOR,
&svt_dec->decoder, avpkt->data, avpkt->size, &svt_dec->config);
if (err) {
av_log(avctx, AV_LOG_ERROR, "svt_jpeg_xs_decoder_init failed, err=%d\n", err);
return AVERROR_EXTERNAL;
}
avctx->pix_fmt = ret;
ret = ff_set_dimensions(avctx, svt_dec->config.width, svt_dec->config.height);
if (ret < 0) {
av_log(avctx, AV_LOG_ERROR, "ff_set_dimensions failed, err=%d\n", ret);
return ret;
}
svt_dec->decoder_initialized = 1;
}
if (avctx->skip_frame == AVDISCARD_ALL)
return 0;
svt_dec->input.bitstream.buffer = avpkt->data;
svt_dec->input.bitstream.allocation_size = avpkt->size;
svt_dec->input.bitstream.used_size = avpkt->size;
svt_dec->input.user_prv_ctx_ptr = avpkt;
ret = ff_get_buffer(avctx, picture, 0);
if (ret < 0)
return ret;
unsigned pixel_shift = svt_dec->config.bit_depth <= 8 ? 0 : 1;
for (int comp = 0; comp < svt_dec->config.components_num; comp++) {
svt_dec->input.image.data_yuv[comp] = picture->data[comp];
svt_dec->input.image.stride[comp] = picture->linesize[comp] >> pixel_shift;
svt_dec->input.image.alloc_size[comp] = picture->linesize[comp] * svt_dec->config.components[comp].height;
}
err = svt_jpeg_xs_decoder_send_frame(&svt_dec->decoder, &svt_dec->input, 1 /*blocking*/);
if (err) {
av_log(avctx, AV_LOG_ERROR, "svt_jpeg_xs_decoder_send_frame failed, err=%d\n", err);
return AVERROR_EXTERNAL;
}
err = svt_jpeg_xs_decoder_get_frame(&svt_dec->decoder, &svt_dec->output, 1 /*blocking*/);
if (err) {
av_log(avctx, AV_LOG_ERROR, "svt_jpeg_xs_decoder_get_frame failed, err=%d\n", err);
return AVERROR_EXTERNAL;
}
if (svt_dec->output.user_prv_ctx_ptr != avpkt) {
av_log(avctx, AV_LOG_ERROR, "Returned different user_prv_ctx_ptr than expected\n");
return AVERROR_EXTERNAL;
}
*got_frame = 1;
return avpkt->size;
}
static av_cold int svt_jpegxs_dec_free(AVCodecContext* avctx)
{
SvtJpegXsDecodeContext* svt_dec = avctx->priv_data;
svt_jpeg_xs_decoder_close(&svt_dec->decoder);
return 0;
}
static av_cold int svt_jpegxs_dec_init(AVCodecContext* avctx)
{
SvtJpegXsDecodeContext* svt_dec = avctx->priv_data;
int log_level = av_log_get_level();
svt_dec->decoder.verbose = log_level < AV_LOG_DEBUG ? VERBOSE_ERRORS :
log_level == AV_LOG_DEBUG ? VERBOSE_SYSTEM_INFO : VERBOSE_WARNINGS;
if (avctx->lowres == 1)
svt_dec->decoder.proxy_mode = proxy_mode_half;
else if (avctx->lowres == 2)
svt_dec->decoder.proxy_mode = proxy_mode_quarter;
else
svt_dec->decoder.proxy_mode = proxy_mode_full;
int thread_count = avctx->thread_count ? avctx->thread_count : av_cpu_count();
svt_dec->decoder.threads_num = FFMIN(thread_count, 64);
svt_dec->decoder.use_cpu_flags = CPU_FLAGS_ALL;
return 0;
}
const FFCodec ff_libsvtjpegxs_decoder = {
.p.name = "libsvtjpegxs",
CODEC_LONG_NAME("SVT JPEG XS(Scalable Video Technology for JPEG XS) decoder"),
.p.type = AVMEDIA_TYPE_VIDEO,
.p.id = AV_CODEC_ID_JPEGXS,
.priv_data_size = sizeof(SvtJpegXsDecodeContext),
.init = svt_jpegxs_dec_init,
.close = svt_jpegxs_dec_free,
FF_CODEC_DECODE_CB(svt_jpegxs_dec_decode),
.p.capabilities = AV_CODEC_CAP_OTHER_THREADS | AV_CODEC_CAP_DR1,
.caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE |
FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM |
FF_CODEC_CAP_AUTO_THREADS,
.p.max_lowres = 2,
.p.wrapper_name = "libsvtjpegxs",
};