Compare commits
2 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9b8d85a96f | ||
|
|
8a48f8d46d |
33 changed files with 709 additions and 169 deletions
|
|
@ -20,10 +20,9 @@ libavcodec/.*ffv1.* @lynne @michaelni
|
|||
libavcodec/golomb.* @michaelni
|
||||
libavcodec/.*h266.* @frankplow @NuoMi @jianhuaw
|
||||
libavcodec/h26x/.* @frankplow @NuoMi @jianhuaw
|
||||
libavcodec/.*jpegxl.* @lynne @Traneptora
|
||||
libavcodec/.*jxl.* @lynne @Traneptora
|
||||
libavcodec/.*jpegxl.* @lynne
|
||||
libavcodec/.*jxl.* @lynne
|
||||
libavcodec/.*opus.* @lynne
|
||||
libavcodec/.*png.* @Traneptora
|
||||
libavcodec/.*prores.* @lynne
|
||||
libavcodec/rangecoder.* @michaelni
|
||||
libavcodec/ratecontrol.* @michaelni
|
||||
|
|
@ -46,8 +45,6 @@ libavfilter/vsrc_mandelbrot.* @michaelni
|
|||
# avformat
|
||||
# =======
|
||||
libavformat/iamf.* @jamrial
|
||||
libavformat/.*jpegxl.* @Traneptora
|
||||
libavformat/.*jxl.* @Traneptora
|
||||
|
||||
# avutil
|
||||
# ======
|
||||
|
|
|
|||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -46,3 +46,4 @@
|
|||
/libavfilter/vulkan/*.c
|
||||
/.*/
|
||||
!/.forgejo/
|
||||
*.orig
|
||||
|
|
@ -8,7 +8,6 @@ version 8.0:
|
|||
- Whisper filter
|
||||
- Drop support for OpenSSL < 1.1.0
|
||||
- Enable TLS peer certificate verification by default (on next major version bump)
|
||||
- Drop support for OpenSSL < 1.1.1
|
||||
- yasm support dropped, users need to use nasm
|
||||
- VVC VAAPI decoder
|
||||
- RealVideo 6.0 decoder
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@
|
|||
#include "libavutil/internal.h"
|
||||
#include "libavutil/mem.h"
|
||||
#include "libavutil/time.h"
|
||||
#include "libavutil/wchar_filename.h"
|
||||
|
||||
typedef struct pthread_t {
|
||||
void *handle;
|
||||
|
|
@ -210,38 +209,4 @@ static inline int pthread_setcancelstate(int state, int *oldstate)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int win32_thread_setname(const char *name)
|
||||
{
|
||||
#if !HAVE_UWP
|
||||
typedef HRESULT (WINAPI *SetThreadDescriptionFn)(HANDLE, PCWSTR);
|
||||
|
||||
// Although SetThreadDescription lives in kernel32.dll, on Windows Server 2016,
|
||||
// Windows 10 LTSB 2016 and Windows 10 version 1607, it was only available in
|
||||
// kernelbase.dll. So, load it from there for maximum coverage.
|
||||
HMODULE kernelbase = GetModuleHandleW(L"kernelbase.dll");
|
||||
if (!kernelbase)
|
||||
return AVERROR(ENOSYS);
|
||||
|
||||
SetThreadDescriptionFn pSetThreadDescription =
|
||||
(SetThreadDescriptionFn)GetProcAddress(kernelbase, "SetThreadDescription");
|
||||
if (!pSetThreadDescription)
|
||||
return AVERROR(ENOSYS);
|
||||
|
||||
wchar_t *wname;
|
||||
if (utf8towchar(name, &wname) < 0)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
HRESULT hr = pSetThreadDescription(GetCurrentThread(), wname);
|
||||
av_free(wname);
|
||||
return SUCCEEDED(hr) ? 0 : AVERROR(EINVAL);
|
||||
#else
|
||||
// UWP is not supported because we cannot use LoadLibrary/GetProcAddress to
|
||||
// detect the availability of the SetThreadDescription API. There is a small
|
||||
// gap in Windows builds 1507-1607 where it was not available. UWP allows
|
||||
// querying the availability of APIs with QueryOptionalDelayLoadedAPI, but it
|
||||
// requires /DELAYLOAD:kernel32.dll during linking, and we cannot enforce that.
|
||||
return AVERROR(ENOSYS);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* COMPAT_W32PTHREADS_H */
|
||||
|
|
|
|||
12
configure
vendored
12
configure
vendored
|
|
@ -212,6 +212,7 @@ External library support:
|
|||
--enable-jni enable JNI support [no]
|
||||
--enable-ladspa enable LADSPA audio filtering [no]
|
||||
--enable-lcms2 enable ICC profile support via LittleCMS 2 [no]
|
||||
--enable-libaac-next enable AAC encoding using libaac-next [no]
|
||||
--enable-libaom enable AV1 video encoding/decoding via libaom [no]
|
||||
--enable-libaribb24 enable ARIB text and caption decoding via libaribb24 [no]
|
||||
--enable-libaribcaption enable ARIB text and caption decoding via libaribcaption [no]
|
||||
|
|
@ -1901,6 +1902,7 @@ EXTERNAL_LIBRARY_NONFREE_LIST="
|
|||
|
||||
EXTERNAL_LIBRARY_VERSION3_LIST="
|
||||
gmp
|
||||
libaac_next
|
||||
libaribb24
|
||||
liblensfun
|
||||
libopencore_amrnb
|
||||
|
|
@ -3592,6 +3594,9 @@ hevc_videotoolbox_encoder_deps="pthreads"
|
|||
hevc_videotoolbox_encoder_select="atsc_a53 videotoolbox_encoder"
|
||||
prores_videotoolbox_encoder_deps="pthreads"
|
||||
prores_videotoolbox_encoder_select="videotoolbox_encoder"
|
||||
libaac_next_decoder_deps="libaac_next"
|
||||
libaac_next_encoder_deps="libaac_next"
|
||||
libaac_next_encoder_select="audio_frame_queue"
|
||||
libaom_av1_decoder_deps="libaom"
|
||||
libaom_av1_encoder_deps="libaom"
|
||||
libaom_av1_encoder_select="extract_extradata_bsf dovi_rpuenc"
|
||||
|
|
@ -5174,7 +5179,7 @@ probe_cc(){
|
|||
# but we can force it back to gnu mode and get the version from there.
|
||||
_ident=$($_cc -flavor gnu --version 2>/dev/null)
|
||||
_ld_o='-out:$@'
|
||||
_flags_filter=msvc_flags_link
|
||||
_flags_filter=msvc_flags
|
||||
_ld_lib='%.lib'
|
||||
_ld_path='-libpath:'
|
||||
elif VSLANG=1033 $_cc -nologo- 2>&1 | grep -q ^Microsoft || { $_cc -v 2>&1 | grep -q clang && $_cc -? > /dev/null 2>&1; }; then
|
||||
|
|
@ -7016,6 +7021,7 @@ enabled gnutls && require_pkg_config gnutls gnutls gnutls/gnutls.h gn
|
|||
enabled jni && { [ $target_os = "android" ] && check_headers jni.h && enabled pthreads || die "ERROR: jni not found"; }
|
||||
enabled ladspa && require_headers "ladspa.h dlfcn.h"
|
||||
enabled lcms2 && require_pkg_config lcms2 "lcms2 >= 2.13" lcms2.h cmsCreateContext
|
||||
enabled libaac_next && require_pkg_config libaac_next "libaac >= 1.0.0" libaac.h aac_encode_open
|
||||
enabled libaom && require_pkg_config libaom "aom >= 2.0.0" aom/aom_codec.h aom_codec_version
|
||||
enabled liboapv && require_pkg_config liboapv "oapv >= 0.2.0.0" "oapv/oapv.h" oapve_encode
|
||||
enabled libaribb24 && { check_pkg_config libaribb24 "aribb24 > 1.0.3" "aribb24/aribb24.h" arib_instance_new ||
|
||||
|
|
@ -7260,10 +7266,10 @@ enabled omx && require_headers OMX_Core.h && \
|
|||
enabled openssl && { { check_pkg_config openssl "openssl >= 3.0.0" openssl/ssl.h OPENSSL_init_ssl &&
|
||||
{ enabled gplv3 || ! enabled gpl || enabled nonfree || die "ERROR: OpenSSL >=3.0.0 requires --enable-version3"; }; } ||
|
||||
{ enabled gpl && ! enabled nonfree && die "ERROR: OpenSSL <3.0.0 is incompatible with the gpl"; } ||
|
||||
check_pkg_config openssl "openssl >= 1.1.1" openssl/ssl.h OPENSSL_init_ssl ||
|
||||
check_pkg_config openssl "openssl >= 1.1.0" openssl/ssl.h OPENSSL_init_ssl ||
|
||||
check_lib openssl openssl/ssl.h OPENSSL_init_ssl -lssl -lcrypto ||
|
||||
check_lib openssl openssl/ssl.h OPENSSL_init_ssl -lssl -lcrypto -lws2_32 -lgdi32 ||
|
||||
die "ERROR: openssl (>= 1.1.1) not found"; }
|
||||
die "ERROR: openssl (>= 1.1.0) not found"; }
|
||||
enabled pocketsphinx && require_pkg_config pocketsphinx pocketsphinx pocketsphinx/pocketsphinx.h ps_init
|
||||
enabled rkmpp && { require_pkg_config rkmpp rockchip_mpp rockchip/rk_mpi.h mpp_create &&
|
||||
require_pkg_config rockchip_mpp "rockchip_mpp >= 1.3.7" rockchip/rk_mpi.h mpp_create &&
|
||||
|
|
|
|||
|
|
@ -1144,6 +1144,8 @@ OBJS-$(CONFIG_ALAC_AT_ENCODER) += audiotoolboxenc.o
|
|||
OBJS-$(CONFIG_ILBC_AT_ENCODER) += audiotoolboxenc.o
|
||||
OBJS-$(CONFIG_PCM_ALAW_AT_ENCODER) += audiotoolboxenc.o
|
||||
OBJS-$(CONFIG_PCM_MULAW_AT_ENCODER) += audiotoolboxenc.o
|
||||
OBJS-$(CONFIG_LIBAAC_NEXT_ENCODER) += libaac_nextenc.o
|
||||
OBJS-$(CONFIG_LIBAAC_NEXT_DECODER) += libaac_nextdec.o
|
||||
OBJS-$(CONFIG_LIBAOM_AV1_DECODER) += libaomdec.o libaom.o
|
||||
OBJS-$(CONFIG_LIBAOM_AV1_ENCODER) += libaomenc.o libaom.o
|
||||
OBJS-$(CONFIG_LIBARIBB24_DECODER) += libaribb24.o ass.o
|
||||
|
|
|
|||
|
|
@ -766,6 +766,8 @@ extern const FFCodec ff_pcm_mulaw_at_encoder;
|
|||
extern const FFCodec ff_pcm_mulaw_at_decoder;
|
||||
extern const FFCodec ff_qdmc_at_decoder;
|
||||
extern const FFCodec ff_qdm2_at_decoder;
|
||||
extern const FFCodec ff_libaac_next_encoder;
|
||||
extern const FFCodec ff_libaac_next_decoder;
|
||||
extern FFCodec ff_libaom_av1_encoder;
|
||||
/* preferred over libaribb24 */
|
||||
extern const FFCodec ff_libaribcaption_decoder;
|
||||
|
|
|
|||
|
|
@ -762,7 +762,6 @@ static const FFCodecDefault d3d12va_encode_hevc_defaults[] = {
|
|||
{ "b_qoffset", "0" },
|
||||
{ "qmin", "-1" },
|
||||
{ "qmax", "-1" },
|
||||
{ "refs", "0" },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -666,11 +666,6 @@ int ff_hw_base_init_gop_structure(FFHWBaseEncodeContext *ctx, AVCodecContext *av
|
|||
ctx->ref_l0 = FFMIN(ref_l0, MAX_PICTURE_REFERENCES);
|
||||
ctx->ref_l1 = FFMIN(ref_l1, MAX_PICTURE_REFERENCES);
|
||||
|
||||
if (avctx->refs > 0) {
|
||||
ctx->ref_l0 = FFMIN(ctx->ref_l0, avctx->refs);
|
||||
ctx->ref_l1 = FFMIN(ctx->ref_l1, avctx->refs);
|
||||
}
|
||||
|
||||
if (flags & FF_HW_FLAG_INTRA_ONLY || avctx->gop_size <= 1) {
|
||||
av_log(avctx, AV_LOG_VERBOSE, "Using intra frames only.\n");
|
||||
ctx->gop_size = 1;
|
||||
|
|
|
|||
170
libavcodec/libaac_nextdec.c
Normal file
170
libavcodec/libaac_nextdec.c
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* Libaac-next decoder (libxaac based)
|
||||
* Copyright (c) 2025 Wrapper
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Interface to libaac-next decoder.
|
||||
*/
|
||||
|
||||
#include "avcodec.h"
|
||||
#include <libaac.h>
|
||||
#include "libavcodec/codec_id.h"
|
||||
#include "libavutil/channel_layout.h"
|
||||
#include "libavutil/error.h"
|
||||
#include "libavutil/log.h"
|
||||
#include "libavutil/opt.h"
|
||||
#include "avcodec.h"
|
||||
#include "codec_internal.h"
|
||||
#include "decode.h"
|
||||
#include "libavutil/samplefmt.h"
|
||||
#include "libavutil/mem.h"
|
||||
|
||||
typedef struct {
|
||||
AVClass *class;
|
||||
AACDecode *decoder;
|
||||
int error_conceal;
|
||||
int esbr;
|
||||
unsigned char *decode_buffer;
|
||||
} libaacDecodeCTX;
|
||||
|
||||
static const AVChannelLayout aac_ch_layouts[6] = {
|
||||
AV_CHANNEL_LAYOUT_MONO,
|
||||
AV_CHANNEL_LAYOUT_STEREO,
|
||||
AV_CHANNEL_LAYOUT_SURROUND,
|
||||
AV_CHANNEL_LAYOUT_4POINT0,
|
||||
AV_CHANNEL_LAYOUT_5POINT0_BACK,
|
||||
AV_CHANNEL_LAYOUT_5POINT1_BACK,
|
||||
};
|
||||
|
||||
static const AVOption aac_dec_options[] = {
|
||||
{ "conceal", "Error concealment", offsetof(libaacDecodeCTX, error_conceal), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM },
|
||||
{ "esbr", "Enable the use of Enhanced SBR", offsetof(libaacDecodeCTX, esbr), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static const AVClass aac_dec_class = {
|
||||
.class_name = "libaac",
|
||||
.item_name = av_default_item_name,
|
||||
.option = aac_dec_options,
|
||||
.version = LIBAVUTIL_VERSION_INT,
|
||||
};
|
||||
|
||||
static void aac_dec_error_handler(uint32_t errorCode, const char *section, const char *errorMsg, bool isFatal, void *handle) {
|
||||
AVCodecContext *ctx = (AVCodecContext *)handle;
|
||||
av_log(ctx, AV_LOG_ERROR, "%s: %s (0x%08X)\n", section, errorMsg, errorCode);
|
||||
}
|
||||
|
||||
static av_cold int libaac_decode_init(AVCodecContext *avctx)
|
||||
{
|
||||
libaacDecodeCTX *s = avctx->priv_data;
|
||||
AACDecodeSettings cfg = {0};
|
||||
|
||||
cfg.bitsPerSamples = 16;
|
||||
cfg.errorConceal = s->error_conceal;
|
||||
cfg.eSBR = s->esbr;
|
||||
cfg.frameSize = 0;
|
||||
cfg.asc = avctx->extradata;
|
||||
cfg.ascSize = avctx->extradata_size;
|
||||
cfg.errorHandleCtx = avctx;
|
||||
cfg.errorHandler = aac_dec_error_handler;
|
||||
|
||||
s->decoder = aac_decode_open(cfg);
|
||||
if (!s->decoder)
|
||||
{
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
s->decode_buffer = av_mallocz(4096 * 8);
|
||||
if (!s->decode_buffer)
|
||||
{
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
avctx->sample_fmt = AV_SAMPLE_FMT_S16;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static av_cold int libaac_decode_close(AVCodecContext *avctx)
|
||||
{
|
||||
libaacDecodeCTX *s = avctx->priv_data;
|
||||
|
||||
if (s->decoder)
|
||||
aac_decode_close(s->decoder);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int libaac_decode_frame(AVCodecContext *avctx, AVFrame *frame,
|
||||
int *got_frame_ptr, AVPacket *avpkt)
|
||||
{
|
||||
libaacDecodeCTX *s = avctx->priv_data;
|
||||
uint32_t decode_size, read_size;
|
||||
int ret;
|
||||
|
||||
ret = aac_decode(s->decoder, avpkt->data, avpkt->size, s->decode_buffer, &decode_size, &read_size);
|
||||
if (ret < 0)
|
||||
return AVERROR_EXTERNAL;
|
||||
|
||||
avctx->sample_rate = s->decoder->sampleRate;
|
||||
avctx->profile = s->decoder->aot - 1;
|
||||
avctx->ch_layout = aac_ch_layouts[s->decoder->noChannels - 1];
|
||||
avctx->frame_size = 1024;
|
||||
|
||||
if (decode_size <= 0)
|
||||
return AVERROR_EOF;
|
||||
|
||||
frame->nb_samples = decode_size / av_get_bytes_per_sample(avctx->sample_fmt) / avctx->ch_layout.nb_channels;
|
||||
|
||||
if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
|
||||
return ret;
|
||||
|
||||
av_log(avctx, AV_LOG_TRACE, "aac decode size: %d, decode buf: %d\n", decode_size, avctx->ch_layout.nb_channels * frame->nb_samples * av_get_bytes_per_sample(avctx->sample_fmt));
|
||||
memcpy(frame->data[0], s->decode_buffer, decode_size);
|
||||
|
||||
*got_frame_ptr = 1;
|
||||
return read_size;
|
||||
}
|
||||
|
||||
static av_cold void libaac_decode_flush(AVCodecContext *avctx)
|
||||
{
|
||||
libaacDecodeCTX *s = avctx->priv_data;
|
||||
|
||||
if (!s->decoder)
|
||||
return;
|
||||
|
||||
aac_decode_flush_buffer(s->decoder);
|
||||
}
|
||||
|
||||
const FFCodec ff_libaac_next_decoder = {
|
||||
.p.name = "libaac",
|
||||
CODEC_LONG_NAME("custom libxaac-based AAC decoder"),
|
||||
.p.type = AVMEDIA_TYPE_AUDIO,
|
||||
.p.id = AV_CODEC_ID_AAC,
|
||||
.priv_data_size = sizeof(libaacDecodeCTX),
|
||||
.init = libaac_decode_init,
|
||||
FF_CODEC_DECODE_CB(libaac_decode_frame),
|
||||
.close = libaac_decode_close,
|
||||
.flush = libaac_decode_flush,
|
||||
.p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF,
|
||||
.caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE,
|
||||
.p.priv_class = &aac_dec_class,
|
||||
.p.wrapper_name = "libaac",
|
||||
};
|
||||
305
libavcodec/libaac_nextenc.c
Executable file
305
libavcodec/libaac_nextenc.c
Executable file
|
|
@ -0,0 +1,305 @@
|
|||
/*
|
||||
* Libaac-next encoder (libxaac based)
|
||||
* Copyright (c) 2025 Wrapper
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Interface to libaac-next encoder.
|
||||
*/
|
||||
|
||||
#include <libaac.h>
|
||||
|
||||
#include "libavutil/channel_layout.h"
|
||||
#include "libavutil/internal.h"
|
||||
#include "libavutil/intreadwrite.h"
|
||||
#include "libavutil/log.h"
|
||||
#include "libavutil/opt.h"
|
||||
#include "libavutil/mem.h"
|
||||
#include "avcodec.h"
|
||||
#include "defs.h"
|
||||
#include "audio_frame_queue.h"
|
||||
#include "codec_internal.h"
|
||||
#include "encode.h"
|
||||
#include "libavutil/samplefmt.h"
|
||||
#include "profiles.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const AVClass *class;
|
||||
AACContext *encoder;
|
||||
int delay_sent;
|
||||
int flush_delay;
|
||||
|
||||
int eld_v2;
|
||||
int esbr;
|
||||
int frame_length;
|
||||
int iq;
|
||||
int tns;
|
||||
|
||||
AudioFrameQueue afq;
|
||||
} libaacEncodeCTX;
|
||||
|
||||
static const AVOption aac_enc_options[] = {
|
||||
{ "eld_v2", "Enable ELDv2 (LD-MPS extension for ELD stereo signals)", offsetof(libaacEncodeCTX, eld_v2), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM },
|
||||
{ "esbr", "Enable the use of Enhanced SBR", offsetof(libaacEncodeCTX, esbr), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM },
|
||||
{ "frame_length", "The desired frame length", offsetof(libaacEncodeCTX, frame_length), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1024, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM },
|
||||
{ "iq", "Inverse quantization", offsetof(libaacEncodeCTX, frame_length), AV_OPT_TYPE_INT, { .i64 = 2 }, 0, 2, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM },
|
||||
{ "tns", "Temporal Noise Shaping", offsetof(libaacEncodeCTX, tns), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM },
|
||||
FF_AAC_PROFILE_OPTS
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static const AVClass aac_enc_class = {
|
||||
.class_name = "libaac",
|
||||
.item_name = av_default_item_name,
|
||||
.option = aac_enc_options,
|
||||
.version = LIBAVUTIL_VERSION_INT,
|
||||
};
|
||||
|
||||
static void aac_enc_error_handler(uint32_t errorCode, const char *section, const char *errorMsg, bool isFatal, void *handle) {
|
||||
AVCodecContext *ctx = (AVCodecContext *)handle;
|
||||
av_log(ctx, AV_LOG_ERROR, "%s: %s (0x%08X)\n", section, errorMsg, errorCode);
|
||||
}
|
||||
|
||||
static av_cold int libaac_encode_init(AVCodecContext *avctx)
|
||||
{
|
||||
libaacEncodeCTX *s = avctx->priv_data;
|
||||
AACSettings cfg = {0};
|
||||
|
||||
/* number of channels */
|
||||
if (avctx->ch_layout.nb_channels < 1 || avctx->ch_layout.nb_channels > 6)
|
||||
{
|
||||
av_log(avctx, AV_LOG_ERROR, "encoding %d channel(s) is not allowed\n", avctx->ch_layout.nb_channels);
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
cfg.sampleRate = avctx->sample_rate;
|
||||
cfg.noChannels = avctx->ch_layout.nb_channels;
|
||||
cfg.bitsPerSamples = avctx->sample_fmt == AV_SAMPLE_FMT_FLT ? 32 : 16;
|
||||
cfg.bitrate = avctx->bit_rate;
|
||||
cfg.adts = !(avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER);
|
||||
cfg.cutoff = avctx->cutoff;
|
||||
switch (avctx->profile) {
|
||||
case AV_PROFILE_AAC_LOW:
|
||||
case AV_PROFILE_UNKNOWN:
|
||||
cfg.profile = AAC_LC;
|
||||
break;
|
||||
|
||||
case AV_PROFILE_AAC_HE:
|
||||
cfg.profile = AAC_HE;
|
||||
break;
|
||||
|
||||
case AV_PROFILE_AAC_HE_V2:
|
||||
cfg.profile = AAC_HEV2;
|
||||
break;
|
||||
|
||||
case AV_PROFILE_AAC_LD:
|
||||
cfg.profile = AAC_LD;
|
||||
break;
|
||||
|
||||
case AV_PROFILE_AAC_ELD:
|
||||
cfg.profile = AAC_ELD;
|
||||
break;
|
||||
|
||||
default:
|
||||
av_log(avctx, AV_LOG_ERROR, "unsupported profile, supported profiles are LC, HE, HEv2, LD and ELD\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
cfg.tns = s->tns;
|
||||
cfg.frameSize = s->frame_length;
|
||||
cfg.eSBR = s->esbr;
|
||||
cfg.iq = s->iq;
|
||||
|
||||
cfg.errorHandleCtx = avctx;
|
||||
cfg.errorHandler = aac_enc_error_handler;
|
||||
|
||||
s->encoder = aac_encode_open(cfg);
|
||||
|
||||
if (!s->encoder)
|
||||
{
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
avctx->frame_size = s->encoder->no_samples / avctx->ch_layout.nb_channels;
|
||||
avctx->initial_padding = s->encoder->inputDelay;
|
||||
s->flush_delay = s->encoder->inputDelay;
|
||||
|
||||
av_log(avctx, AV_LOG_TRACE, "frame size: %d, initial delay: %d\n", avctx->frame_size, avctx->initial_padding);
|
||||
|
||||
ff_af_queue_init(avctx, &s->afq);
|
||||
|
||||
/* Set decoder specific info */
|
||||
avctx->extradata_size = 0;
|
||||
if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)
|
||||
{
|
||||
avctx->extradata = av_mallocz(s->encoder->ascSize + AV_INPUT_BUFFER_PADDING_SIZE);
|
||||
|
||||
if (!avctx->extradata)
|
||||
{
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
memcpy(avctx->extradata, s->encoder->asc, s->encoder->ascSize);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int libaac_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
|
||||
const AVFrame *frame, int *got_packet)
|
||||
{
|
||||
libaacEncodeCTX *s = avctx->priv_data;
|
||||
int ret;
|
||||
int discard_padding;
|
||||
|
||||
if ((ret = ff_alloc_packet(avctx, pkt, s->encoder->max_out_bytes)) < 0)
|
||||
return ret;
|
||||
|
||||
if (!frame)
|
||||
{
|
||||
av_log(avctx, AV_LOG_TRACE, "flush_delay: %d\n", s->flush_delay);
|
||||
|
||||
if (s->flush_delay <= 0)
|
||||
return 0;
|
||||
|
||||
/* Flushing */
|
||||
if ((ret = aac_encode(s->encoder, NULL, 0, pkt->data, (unsigned int *)&pkt->size)) < 0)
|
||||
{
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
s->flush_delay -= avctx->frame_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Encoding */
|
||||
if ((ret = ff_af_queue_add(&s->afq, frame)) < 0)
|
||||
return ret;
|
||||
|
||||
int encodeSize = av_get_bytes_per_sample(avctx->sample_fmt) * avctx->ch_layout.nb_channels * frame->nb_samples;
|
||||
av_log(avctx, AV_LOG_TRACE, "encode size: %d\n", encodeSize);
|
||||
|
||||
if ((ret = aac_encode(s->encoder, frame->data[0], encodeSize, pkt->data, (unsigned int *)&pkt->size)) < 0)
|
||||
{
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
ff_af_queue_remove(&s->afq, avctx->frame_size, &pkt->pts, &pkt->duration);
|
||||
|
||||
/* discard padding copied from fdkaac encoder */
|
||||
discard_padding = avctx->frame_size - pkt->duration;
|
||||
|
||||
// Check if subtraction resulted in an overflow
|
||||
if ((discard_padding < avctx->frame_size) != (pkt->duration > 0))
|
||||
{
|
||||
av_log(avctx, AV_LOG_ERROR, "discard padding overflow\n");
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
if ((!s->delay_sent && avctx->initial_padding > 0) || discard_padding > 0)
|
||||
{
|
||||
uint8_t *side_data =
|
||||
av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10);
|
||||
if (!side_data)
|
||||
return AVERROR(ENOMEM);
|
||||
if (!s->delay_sent)
|
||||
{
|
||||
AV_WL32(side_data, avctx->initial_padding);
|
||||
s->delay_sent = 1;
|
||||
}
|
||||
AV_WL32(side_data + 4, discard_padding);
|
||||
}
|
||||
|
||||
pkt->flags |= AV_PKT_FLAG_KEY;
|
||||
*got_packet = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void libaac_encode_flush(AVCodecContext *avctx)
|
||||
{
|
||||
libaacEncodeCTX *s = avctx->priv_data;
|
||||
uint8_t sink_null[32768];
|
||||
int64_t pts, duration;
|
||||
uint32_t out_bytes;
|
||||
|
||||
av_log(avctx, AV_LOG_TRACE, "encoder flush\n");
|
||||
ff_af_queue_remove(&s->afq, s->afq.frame_count, &pts, &duration);
|
||||
aac_encode(s->encoder, NULL, 0, sink_null, &out_bytes);
|
||||
}
|
||||
|
||||
static av_cold int libaac_encode_close(AVCodecContext *avctx)
|
||||
{
|
||||
libaacEncodeCTX *s = avctx->priv_data;
|
||||
|
||||
if (s->encoder)
|
||||
aac_encode_close(s->encoder);
|
||||
|
||||
ff_af_queue_close(&s->afq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const FFCodecDefault defaults[] = {
|
||||
{"b", "128000"},
|
||||
{NULL}};
|
||||
|
||||
static const AVProfile libaac_profiles[] = {
|
||||
{ AV_PROFILE_AAC_LOW, "LC" },
|
||||
{ AV_PROFILE_AAC_HE, "HE-AAC" },
|
||||
{ AV_PROFILE_AAC_HE_V2, "HE-AACv2" },
|
||||
{ AV_PROFILE_AAC_LD, "LD" },
|
||||
{ AV_PROFILE_AAC_ELD, "ELD" },
|
||||
{AV_PROFILE_UNKNOWN},
|
||||
};
|
||||
|
||||
static const int aac_sample_rates[] = {
|
||||
96000, 88200, 64000, 48000, 44100, 32000,
|
||||
24000, 22050, 16000, 12000, 11025, 8000, 0
|
||||
};
|
||||
|
||||
static const AVChannelLayout aac_ch_layouts[6] = {
|
||||
AV_CHANNEL_LAYOUT_MONO,
|
||||
AV_CHANNEL_LAYOUT_STEREO,
|
||||
AV_CHANNEL_LAYOUT_SURROUND,
|
||||
AV_CHANNEL_LAYOUT_4POINT0,
|
||||
AV_CHANNEL_LAYOUT_5POINT0_BACK,
|
||||
AV_CHANNEL_LAYOUT_5POINT1_BACK,
|
||||
};
|
||||
|
||||
const FFCodec ff_libaac_next_encoder = {
|
||||
.p.name = "libaac",
|
||||
CODEC_LONG_NAME("custom libxaac-based AAC encoder"),
|
||||
.p.type = AVMEDIA_TYPE_AUDIO,
|
||||
.p.id = AV_CODEC_ID_AAC,
|
||||
.p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_ENCODER_FLUSH,
|
||||
.caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE,
|
||||
.priv_data_size = sizeof(libaacEncodeCTX),
|
||||
.init = libaac_encode_init,
|
||||
FF_CODEC_ENCODE_CB(libaac_encode_frame),
|
||||
.flush = libaac_encode_flush,
|
||||
.close = libaac_encode_close,
|
||||
CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16),
|
||||
.p.priv_class = &aac_enc_class,
|
||||
.defaults = defaults,
|
||||
.p.profiles = libaac_profiles,
|
||||
CODEC_SAMPLERATES_ARRAY(aac_sample_rates),
|
||||
.p.wrapper_name = "libaac",
|
||||
CODEC_CH_LAYOUTS_ARRAY(aac_ch_layouts),
|
||||
};
|
||||
|
|
@ -367,6 +367,9 @@ static int decode_frame(AVCodecContext *avctx,
|
|||
if ((w & 1) || (h & 1))
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
avctx->coded_width = FFALIGN(w, 16);
|
||||
avctx->coded_height = FFALIGN(h, 16);
|
||||
|
||||
if (w != avctx->width || h != avctx->height) {
|
||||
av_log(avctx, AV_LOG_WARNING, "picture resolution change: %ix%i -> %ix%i\n",
|
||||
avctx->width, avctx->height, w, h);
|
||||
|
|
@ -374,9 +377,6 @@ static int decode_frame(AVCodecContext *avctx,
|
|||
return ret;
|
||||
}
|
||||
|
||||
avctx->coded_width = FFALIGN(w, 16);
|
||||
avctx->coded_height = FFALIGN(h, 16);
|
||||
|
||||
enum AVPixelFormat pix_fmt = AV_PIX_FMT_BAYER_RGGB16;
|
||||
if (pix_fmt != s->pix_fmt) {
|
||||
s->pix_fmt = pix_fmt;
|
||||
|
|
|
|||
|
|
@ -308,8 +308,6 @@ static int update_dimensions_clear_info(RV60Context *s, int width, int height)
|
|||
if ((ret = av_reallocp_array(&s->blk_info, s->blk_stride * (s->cu_height << 4), sizeof(s->blk_info[0]))) < 0)
|
||||
return ret;
|
||||
|
||||
memset(s->pu_info, 0, s->pu_stride * (s->cu_height << 3) * sizeof(s->pu_info[0]));
|
||||
|
||||
for (int j = 0; j < s->cu_height << 4; j++)
|
||||
for (int i = 0; i < s->cu_width << 4; i++)
|
||||
s->blk_info[j*s->blk_stride + i].mv.mvref = MVREF_NONE;
|
||||
|
|
|
|||
|
|
@ -1757,11 +1757,6 @@ static int process_frame_obj(SANMVideoContext *ctx, GetByteContext *gb)
|
|||
memset(ctx->fbuf, 0, ctx->frm0_size);
|
||||
}
|
||||
|
||||
if (w + FFMAX(left, 0) > ctx->avctx->width || h + FFMAX(top, 0) > ctx->avctx->height) {
|
||||
avpriv_request_sample(ctx->avctx, "overly large frame\n");
|
||||
return AVERROR_PATCHWELCOME;
|
||||
}
|
||||
|
||||
switch (codec) {
|
||||
case 1:
|
||||
case 3:
|
||||
|
|
@ -2074,20 +2069,6 @@ static int codec2subblock(SANMVideoContext *ctx, int cx, int cy, int blk_size)
|
|||
mx = motion_vectors[opcode][0];
|
||||
my = motion_vectors[opcode][1];
|
||||
|
||||
/* The original implementation of this codec precomputes a table
|
||||
* of int16_t all motion vectors for given image width.
|
||||
* For larger widths, starting with 762 pixels, the calculation of
|
||||
* mv table indices 1+ and 255- overflow the int16_t, inverting the
|
||||
* sign of the offset. This is actively exploited in e.g. the
|
||||
* "jonesopn_8.snm" video of "Indiana Jones and the Infernal Machine".
|
||||
* Therefore let the overflow happen and extract x/y components from
|
||||
* the new value.
|
||||
*/
|
||||
if (ctx->width > 761) {
|
||||
index = (int16_t)(my * ctx->width + mx);
|
||||
mx = index % ctx->width;
|
||||
my = index / ctx->width;
|
||||
}
|
||||
if (good_mvec(ctx, cx, cy, mx, my, blk_size)) {
|
||||
copy_block(ctx->frm0 + cx + ctx->pitch * cy,
|
||||
ctx->frm2 + cx + mx + ctx->pitch * (cy + my),
|
||||
|
|
|
|||
|
|
@ -585,7 +585,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *frame,
|
|||
int buf_size = avpkt->size;
|
||||
UtvideoContext *c = avctx->priv_data;
|
||||
int i, j;
|
||||
const uint8_t *plane_start[5] = {NULL};
|
||||
const uint8_t *plane_start[5];
|
||||
int plane_size, max_slice_size = 0, slice_start, slice_end, slice_size;
|
||||
int ret;
|
||||
GetByteContext gb;
|
||||
|
|
|
|||
|
|
@ -1027,7 +1027,6 @@ static const FFCodecDefault vaapi_encode_av1_defaults[] = {
|
|||
{ "g", "120" },
|
||||
{ "qmin", "1" },
|
||||
{ "qmax", "255" },
|
||||
{ "refs", "0" },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1153,7 +1153,6 @@ static const FFCodecDefault vaapi_encode_h264_defaults[] = {
|
|||
{ "b_qoffset", "0" },
|
||||
{ "qmin", "-1" },
|
||||
{ "qmax", "-1" },
|
||||
{ "refs", "0" },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1184,7 +1184,6 @@ static const FFCodecDefault vaapi_encode_h265_defaults[] = {
|
|||
{ "b_qoffset", "0" },
|
||||
{ "qmin", "-1" },
|
||||
{ "qmax", "-1" },
|
||||
{ "refs", "0" },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -235,7 +235,6 @@ static const FFCodecDefault vaapi_encode_vp8_defaults[] = {
|
|||
{ "g", "120" },
|
||||
{ "qmin", "-1" },
|
||||
{ "qmax", "-1" },
|
||||
{ "refs", "0" },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -292,7 +292,6 @@ static const FFCodecDefault vaapi_encode_vp9_defaults[] = {
|
|||
{ "g", "250" },
|
||||
{ "qmin", "-1" },
|
||||
{ "qmax", "-1" },
|
||||
{ "refs", "0" },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1367,7 +1367,6 @@ static const FFCodecDefault vulkan_encode_av1_defaults[] = {
|
|||
{ "g", "300" },
|
||||
{ "qmin", "1" },
|
||||
{ "qmax", "255" },
|
||||
{ "refs", "0" },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1634,7 +1634,6 @@ static const FFCodecDefault vulkan_encode_h264_defaults[] = {
|
|||
{ "b_qoffset", "0" },
|
||||
{ "qmin", "-1" },
|
||||
{ "qmax", "-1" },
|
||||
{ "refs", "0" },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1761,7 +1761,6 @@ static const FFCodecDefault vulkan_encode_h265_defaults[] = {
|
|||
{ "b_qoffset", "0" },
|
||||
{ "qmin", "-1" },
|
||||
{ "qmax", "-1" },
|
||||
{ "refs", "0" },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -170,7 +170,6 @@ X86ASM-OBJS-$(CONFIG_MLP_DECODER) += x86/mlpdsp.o
|
|||
X86ASM-OBJS-$(CONFIG_MPEG4_DECODER) += x86/xvididct.o
|
||||
X86ASM-OBJS-$(CONFIG_PNG_DECODER) += x86/pngdsp.o
|
||||
X86ASM-OBJS-$(CONFIG_PRORES_DECODER) += x86/proresdsp.o
|
||||
X86ASM-OBJS-$(CONFIG_PRORES_RAW_DECODER) += x86/proresdsp.o
|
||||
X86ASM-OBJS-$(CONFIG_RV40_DECODER) += x86/rv40dsp.o
|
||||
X86ASM-OBJS-$(CONFIG_SBC_ENCODER) += x86/sbcdsp.o
|
||||
X86ASM-OBJS-$(CONFIG_SVQ1_ENCODER) += x86/svq1enc.o
|
||||
|
|
|
|||
|
|
@ -215,9 +215,7 @@ static void run_transcription(AVFilterContext *ctx, AVFrame *frame, int samples)
|
|||
|
||||
for (int i = 0; i < n_segments; ++i) {
|
||||
const char *text = whisper_full_get_segment_text(wctx->ctx_wsp, i);
|
||||
if (av_isspace(text[0]))
|
||||
text++;
|
||||
char *text_cleaned = av_strireplace(text, "[BLANK_AUDIO]", "");
|
||||
char *text_cleaned = av_strireplace(text + 1, "[BLANK_AUDIO]", "");
|
||||
|
||||
if (av_strnlen(text_cleaned, 1) == 0) {
|
||||
av_freep(&text_cleaned);
|
||||
|
|
@ -430,8 +428,7 @@ static int query_formats(const AVFilterContext *ctx,
|
|||
#define HOURS 3600000000
|
||||
|
||||
static const AVOption whisper_options[] = {
|
||||
{ "model", "Path to the whisper.cpp model file", OFFSET(model_path), AV_OPT_TYPE_STRING,.flags = FLAGS },
|
||||
{ "language", "Language for transcription ('auto' for auto-detect)", OFFSET(language), AV_OPT_TYPE_STRING, {.str = "auto"}, .flags = FLAGS },
|
||||
{ "model", "Path to the whisper.cpp model file", OFFSET(model_path), AV_OPT_TYPE_STRING,.flags = FLAGS }, { "language", "Language for transcription ('auto' for auto-detect)", OFFSET(language), AV_OPT_TYPE_STRING, {.str = "auto"}, .flags = FLAGS },
|
||||
{ "queue", "Audio queue size", OFFSET(queue), AV_OPT_TYPE_DURATION, {.i64 = 3000000}, 20000, HOURS, .flags = FLAGS },
|
||||
{ "use_gpu", "Use GPU for processing", OFFSET(use_gpu), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, .flags = FLAGS },
|
||||
{ "gpu_device", "GPU device to use", OFFSET(gpu_device), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, .flags = FLAGS },
|
||||
|
|
|
|||
|
|
@ -461,17 +461,17 @@ int avio_put_str16be(AVIOContext *s, const char *str);
|
|||
void avio_write_marker(AVIOContext *s, int64_t time, enum AVIODataMarkerType type);
|
||||
|
||||
/**
|
||||
* Passing this as the "whence" parameter to a seek function causes it to
|
||||
* ORing this as the "whence" parameter to a seek function causes it to
|
||||
* return the filesize without seeking anywhere. Supporting this is optional.
|
||||
* If it is not supported then the seek function will return <0.
|
||||
*/
|
||||
#define AVSEEK_SIZE 0x10000
|
||||
|
||||
/**
|
||||
* OR'ing this flag into the "whence" parameter to a seek function causes it to
|
||||
* Passing this flag as the "whence" parameter to a seek function causes it to
|
||||
* seek by any means (like reopening and linear reading) or other normally unreasonable
|
||||
* means that can be extremely slow.
|
||||
* This is the default and therefore ignored by the seek code since 2010.
|
||||
* This may be ignored by the seek code.
|
||||
*/
|
||||
#define AVSEEK_FORCE 0x20000
|
||||
|
||||
|
|
|
|||
|
|
@ -238,9 +238,10 @@ int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
|
|||
FFIOContext *const ctx = ffiocontext(s);
|
||||
int64_t offset1;
|
||||
int64_t pos;
|
||||
int force = whence & AVSEEK_FORCE;
|
||||
int buffer_size;
|
||||
int short_seek;
|
||||
whence &= ~AVSEEK_FORCE; // force flag does nothing
|
||||
whence &= ~AVSEEK_FORCE;
|
||||
|
||||
if(!s)
|
||||
return AVERROR(EINVAL);
|
||||
|
|
@ -281,7 +282,8 @@ int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
|
|||
} else if ((!(s->seekable & AVIO_SEEKABLE_NORMAL) ||
|
||||
offset1 <= buffer_size + short_seek) &&
|
||||
!s->write_flag && offset1 >= 0 &&
|
||||
(!s->direct || !s->seek)) {
|
||||
(!s->direct || !s->seek) &&
|
||||
(whence != SEEK_END || force)) {
|
||||
while(s->pos < offset && !s->eof_reached)
|
||||
fill_buffer(s);
|
||||
if (s->eof_reached)
|
||||
|
|
@ -298,7 +300,7 @@ int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
|
|||
s->pos = pos;
|
||||
s->eof_reached = 0;
|
||||
fill_buffer(s);
|
||||
return avio_seek(s, offset, SEEK_SET);
|
||||
return avio_seek(s, offset, SEEK_SET | force);
|
||||
} else {
|
||||
int64_t res;
|
||||
if (s->write_flag) {
|
||||
|
|
|
|||
|
|
@ -5456,6 +5456,10 @@ static int heif_add_stream(MOVContext *c, HEIFItem *item)
|
|||
if (!sc->chunk_offsets)
|
||||
goto fail;
|
||||
sc->chunk_count = 1;
|
||||
sc->sample_sizes = av_malloc_array(1, sizeof(*sc->sample_sizes));
|
||||
if (!sc->sample_sizes)
|
||||
goto fail;
|
||||
sc->sample_count = 1;
|
||||
sc->stts_data = av_malloc_array(1, sizeof(*sc->stts_data));
|
||||
if (!sc->stts_data)
|
||||
goto fail;
|
||||
|
|
@ -10467,13 +10471,11 @@ static int mov_parse_heif_items(AVFormatContext *s)
|
|||
st->codecpar->width = item->width;
|
||||
st->codecpar->height = item->height;
|
||||
|
||||
sc->sample_size = sc->stsz_sample_size = item->extent_length;
|
||||
sc->sample_count = 1;
|
||||
|
||||
err = sanity_checks(s, sc, st->index);
|
||||
if (err)
|
||||
err = sanity_checks(s, sc, item->item_id);
|
||||
if (err || !sc->sample_count)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
sc->sample_sizes[0] = item->extent_length;
|
||||
sc->chunk_offsets[0] = item->extent_offset + offset;
|
||||
|
||||
if (item->item_id == mov->primary_item_id)
|
||||
|
|
|
|||
|
|
@ -34,6 +34,17 @@
|
|||
*/
|
||||
#define MAX_CERTIFICATE_SIZE 8192
|
||||
|
||||
enum DTLSState {
|
||||
DTLS_STATE_NONE,
|
||||
|
||||
/* Whether DTLS handshake is finished. */
|
||||
DTLS_STATE_FINISHED,
|
||||
/* Whether DTLS session is closed. */
|
||||
DTLS_STATE_CLOSED,
|
||||
/* Whether DTLS handshake is failed. */
|
||||
DTLS_STATE_FAILED,
|
||||
};
|
||||
|
||||
typedef struct TLSShared {
|
||||
char *ca_file;
|
||||
int verify;
|
||||
|
|
@ -54,6 +65,8 @@ typedef struct TLSShared {
|
|||
int is_dtls;
|
||||
int use_srtp;
|
||||
|
||||
enum DTLSState state;
|
||||
|
||||
/* The certificate and private key content used for DTLS handshake */
|
||||
char* cert_buf;
|
||||
char* key_buf;
|
||||
|
|
@ -99,6 +112,8 @@ int ff_tls_set_external_socket(URLContext *h, URLContext *sock);
|
|||
|
||||
int ff_dtls_export_materials(URLContext *h, char *dtls_srtp_materials, size_t materials_sz);
|
||||
|
||||
int ff_dtls_state(URLContext *h);
|
||||
|
||||
int ff_ssl_read_key_cert(char *key_url, char *cert_url, char *key_buf, size_t key_sz, char *cert_buf, size_t cert_sz, char **fingerprint);
|
||||
|
||||
int ff_ssl_gen_key_cert(char *key_buf, size_t key_sz, char *cert_buf, size_t cert_sz, char **fingerprint);
|
||||
|
|
|
|||
|
|
@ -35,82 +35,127 @@
|
|||
#include <openssl/x509v3.h>
|
||||
|
||||
/**
|
||||
* Convert an EVP_PKEY to a PEM string.
|
||||
* Returns a heap‐allocated null‐terminated string containing
|
||||
* the PEM‐encoded public key. Caller must free.
|
||||
*/
|
||||
static int pkey_to_pem_string(EVP_PKEY *pkey, char *out, size_t out_sz)
|
||||
{
|
||||
BIO *mem = NULL;
|
||||
size_t read_bytes = 0;
|
||||
|
||||
if (!pkey || !out || !out_sz)
|
||||
goto done;
|
||||
static char *pkey_to_pem_string(EVP_PKEY *pkey) {
|
||||
BIO *mem = NULL;
|
||||
BUF_MEM *bptr = NULL;
|
||||
char *pem_str = NULL;
|
||||
|
||||
// Create a memory BIO
|
||||
if (!(mem = BIO_new(BIO_s_mem())))
|
||||
goto done;
|
||||
goto err;
|
||||
|
||||
// Write public key in PEM form
|
||||
if (!PEM_write_bio_PrivateKey(mem, pkey, NULL, NULL, 0, NULL, NULL))
|
||||
goto done;
|
||||
goto err;
|
||||
|
||||
if (!BIO_read_ex(mem, out, out_sz - 1, &read_bytes))
|
||||
goto done;
|
||||
// Extract pointer/length
|
||||
BIO_get_mem_ptr(mem, &bptr);
|
||||
if (!bptr || !bptr->length)
|
||||
goto err;
|
||||
|
||||
done:
|
||||
// Allocate string (+1 for NUL)
|
||||
pem_str = av_malloc(bptr->length + 1);
|
||||
if (!pem_str)
|
||||
goto err;
|
||||
|
||||
// Copy data & NUL‐terminate
|
||||
memcpy(pem_str, bptr->data, bptr->length);
|
||||
pem_str[bptr->length] = '\0';
|
||||
|
||||
cleanup:
|
||||
BIO_free(mem);
|
||||
if (out && out_sz)
|
||||
out[read_bytes] = '\0';
|
||||
return read_bytes;
|
||||
return pem_str;
|
||||
|
||||
err:
|
||||
// error path: free and return NULL
|
||||
free(pem_str);
|
||||
pem_str = NULL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an X509 certificate to a PEM string.
|
||||
* Serialize an X509 certificate to a av_malloc’d PEM string.
|
||||
* Caller must free the returned pointer.
|
||||
*/
|
||||
static int cert_to_pem_string(X509 *cert, char *out, size_t out_sz)
|
||||
static char *cert_to_pem_string(X509 *cert)
|
||||
{
|
||||
BIO *mem = NULL;
|
||||
size_t read_bytes = 0;
|
||||
BIO *mem = BIO_new(BIO_s_mem());
|
||||
BUF_MEM *bptr = NULL;
|
||||
char *out = NULL;
|
||||
|
||||
if (!cert || !out || !out_sz)
|
||||
goto done;
|
||||
|
||||
if (!(mem = BIO_new(BIO_s_mem())))
|
||||
goto done;
|
||||
if (!mem) goto err;
|
||||
|
||||
/* Write the PEM certificate */
|
||||
if (!PEM_write_bio_X509(mem, cert))
|
||||
goto done;
|
||||
goto err;
|
||||
|
||||
if (!BIO_read_ex(mem, out, out_sz - 1, &read_bytes))
|
||||
goto done;
|
||||
BIO_get_mem_ptr(mem, &bptr);
|
||||
if (!bptr || !bptr->length) goto err;
|
||||
|
||||
done:
|
||||
out = av_malloc(bptr->length + 1);
|
||||
if (!out) goto err;
|
||||
|
||||
memcpy(out, bptr->data, bptr->length);
|
||||
out[bptr->length] = '\0';
|
||||
|
||||
cleanup:
|
||||
BIO_free(mem);
|
||||
if (out && out_sz)
|
||||
out[read_bytes] = '\0';
|
||||
return read_bytes;
|
||||
return out;
|
||||
|
||||
err:
|
||||
free(out);
|
||||
out = NULL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate a SHA-256 fingerprint of an X.509 certificate.
|
||||
*
|
||||
* @param ctx AVFormatContext for logging (can be NULL)
|
||||
* @param cert X509 certificate to fingerprint
|
||||
* @return Newly allocated fingerprint string in "AA:BB:CC:…" format,
|
||||
* or NULL on error (logs via av_log if ctx is not NULL).
|
||||
* Caller must free() the returned string.
|
||||
*/
|
||||
static int x509_fingerprint(X509 *cert, char **fingerprint)
|
||||
static char *generate_fingerprint(X509 *cert)
|
||||
{
|
||||
unsigned char md[EVP_MAX_MD_SIZE];
|
||||
int n = 0;
|
||||
AVBPrint buf;
|
||||
AVBPrint fingerprint;
|
||||
char *result = NULL;
|
||||
int i;
|
||||
|
||||
/* To prevent a crash during cleanup, always initialize it. */
|
||||
av_bprint_init(&fingerprint, 0, AV_BPRINT_SIZE_UNLIMITED);
|
||||
|
||||
if (X509_digest(cert, EVP_sha256(), md, &n) != 1) {
|
||||
av_log(NULL, AV_LOG_ERROR, "TLS: Failed to generate fingerprint, %s\n",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
return AVERROR(ENOMEM);
|
||||
av_log(NULL, AV_LOG_ERROR, "TLS: Failed to generate fingerprint, %s\n", ERR_error_string(ERR_get_error(), NULL));
|
||||
goto end;
|
||||
}
|
||||
|
||||
av_bprint_init(&buf, n*3, n*3);
|
||||
for (i = 0; i < n; i++) {
|
||||
av_bprintf(&fingerprint, "%02X", md[i]);
|
||||
if (i + 1 < n)
|
||||
av_bprintf(&fingerprint, ":");
|
||||
}
|
||||
|
||||
for (int i = 0; i < n - 1; i++)
|
||||
av_bprintf(&buf, "%02X:", md[i]);
|
||||
av_bprintf(&buf, "%02X", md[n - 1]);
|
||||
if (!fingerprint.str || !strlen(fingerprint.str)) {
|
||||
av_log(NULL, AV_LOG_ERROR, "TLS: Fingerprint is empty\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
return av_bprint_finalize(&buf, fingerprint);
|
||||
result = av_strdup(fingerprint.str);
|
||||
if (!result) {
|
||||
av_log(NULL, AV_LOG_ERROR, "TLS: Out of memory generating fingerprint\n");
|
||||
}
|
||||
|
||||
end:
|
||||
av_bprint_finalize(&fingerprint, NULL);
|
||||
return result;
|
||||
}
|
||||
|
||||
int ff_ssl_read_key_cert(char *key_url, char *cert_url, char *key_buf, size_t key_sz, char *cert_buf, size_t cert_sz, char **fingerprint)
|
||||
|
|
@ -120,6 +165,7 @@ int ff_ssl_read_key_cert(char *key_url, char *cert_url, char *key_buf, size_t ke
|
|||
AVBPrint key_bp, cert_bp;
|
||||
EVP_PKEY *pkey = NULL;
|
||||
X509 *cert = NULL;
|
||||
char *key_tem = NULL, *cert_tem = NULL;
|
||||
|
||||
/* To prevent a crash during cleanup, always initialize it. */
|
||||
av_bprint_init(&key_bp, 1, MAX_CERTIFICATE_SIZE);
|
||||
|
|
@ -165,18 +211,29 @@ int ff_ssl_read_key_cert(char *key_url, char *cert_url, char *key_buf, size_t ke
|
|||
goto end;
|
||||
}
|
||||
|
||||
pkey_to_pem_string(pkey, key_buf, key_sz);
|
||||
cert_to_pem_string(cert, cert_buf, cert_sz);
|
||||
key_tem = pkey_to_pem_string(pkey);
|
||||
cert_tem = cert_to_pem_string(cert);
|
||||
|
||||
ret = x509_fingerprint(cert, fingerprint);
|
||||
if (ret < 0)
|
||||
av_log(NULL, AV_LOG_ERROR, "TLS: Failed to generate fingerprint from %s\n", cert_url);
|
||||
snprintf(key_buf, key_sz, "%s", key_tem);
|
||||
snprintf(cert_buf, cert_sz, "%s", cert_tem);
|
||||
|
||||
/* Generate fingerprint. */
|
||||
if (fingerprint) {
|
||||
*fingerprint = generate_fingerprint(cert);
|
||||
if (!*fingerprint) {
|
||||
av_log(NULL, AV_LOG_ERROR, "TLS: Failed to generate fingerprint from %s\n", cert_url);
|
||||
ret = AVERROR(EIO);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
BIO_free(key_b);
|
||||
av_bprint_finalize(&key_bp, NULL);
|
||||
BIO_free(cert_b);
|
||||
av_bprint_finalize(&cert_bp, NULL);
|
||||
av_free(key_tem);
|
||||
av_free(cert_tem);
|
||||
EVP_PKEY_free(pkey);
|
||||
X509_free(cert);
|
||||
return ret;
|
||||
|
|
@ -319,9 +376,12 @@ static int openssl_gen_certificate(EVP_PKEY *pkey, X509 **cert, char **fingerpri
|
|||
goto einval_end;
|
||||
}
|
||||
|
||||
ret = x509_fingerprint(*cert, fingerprint);
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
if (fingerprint) {
|
||||
*fingerprint = generate_fingerprint(*cert);
|
||||
if (!*fingerprint) {
|
||||
goto enomem_end;
|
||||
}
|
||||
}
|
||||
|
||||
goto end;
|
||||
enomem_end:
|
||||
|
|
@ -343,6 +403,7 @@ int ff_ssl_gen_key_cert(char *key_buf, size_t key_sz, char *cert_buf, size_t cer
|
|||
int ret = 0;
|
||||
EVP_PKEY *pkey = NULL;
|
||||
X509 *cert = NULL;
|
||||
char *key_tem = NULL, *cert_tem = NULL;
|
||||
|
||||
ret = openssl_gen_private_key(&pkey);
|
||||
if (ret < 0) goto error;
|
||||
|
|
@ -350,9 +411,14 @@ int ff_ssl_gen_key_cert(char *key_buf, size_t key_sz, char *cert_buf, size_t cer
|
|||
ret = openssl_gen_certificate(pkey, &cert, fingerprint);
|
||||
if (ret < 0) goto error;
|
||||
|
||||
pkey_to_pem_string(pkey, key_buf, key_sz);
|
||||
cert_to_pem_string(cert, cert_buf, cert_sz);
|
||||
key_tem = pkey_to_pem_string(pkey);
|
||||
cert_tem = cert_to_pem_string(cert);
|
||||
|
||||
snprintf(key_buf, key_sz, "%s", key_tem);
|
||||
snprintf(cert_buf, cert_sz, "%s", cert_tem);
|
||||
|
||||
av_free(key_tem);
|
||||
av_free(cert_tem);
|
||||
error:
|
||||
X509_free(cert);
|
||||
EVP_PKEY_free(pkey);
|
||||
|
|
@ -361,7 +427,7 @@ error:
|
|||
|
||||
|
||||
/**
|
||||
* Deserialize a PEM-encoded private or public key from a NUL-terminated C string.
|
||||
* Deserialize a PEM‐encoded private or public key from a NUL-terminated C string.
|
||||
*
|
||||
* @param pem_str The PEM text, e.g.
|
||||
* "-----BEGIN PRIVATE KEY-----\n…\n-----END PRIVATE KEY-----\n"
|
||||
|
|
@ -392,7 +458,7 @@ static EVP_PKEY *pkey_from_pem_string(const char *pem_str, int is_priv)
|
|||
}
|
||||
|
||||
/**
|
||||
* Deserialize a PEM-encoded certificate from a NUL-terminated C string.
|
||||
* Deserialize a PEM‐encoded certificate from a NUL-terminated C string.
|
||||
*
|
||||
* @param pem_str The PEM text, e.g.
|
||||
* "-----BEGIN CERTIFICATE-----\n…\n-----END CERTIFICATE-----\n"
|
||||
|
|
@ -476,6 +542,12 @@ int ff_dtls_export_materials(URLContext *h, char *dtls_srtp_materials, size_t ma
|
|||
return 0;
|
||||
}
|
||||
|
||||
int ff_dtls_state(URLContext *h)
|
||||
{
|
||||
TLSContext *c = h->priv_data;
|
||||
return c->tls_shared.state;
|
||||
}
|
||||
|
||||
static int print_ssl_error(URLContext *h, int ret)
|
||||
{
|
||||
TLSContext *c = h->priv_data;
|
||||
|
|
@ -650,6 +722,7 @@ static int dtls_handshake(URLContext *h)
|
|||
goto end;
|
||||
|
||||
ret = 0;
|
||||
c->tls_shared.state = DTLS_STATE_FINISHED;
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -681,6 +681,12 @@ int ff_dtls_export_materials(URLContext *h, char *dtls_srtp_materials, size_t ma
|
|||
#endif
|
||||
}
|
||||
|
||||
int ff_dtls_state(URLContext *h)
|
||||
{
|
||||
TLSContext *c = h->priv_data;
|
||||
return c->tls_shared.state;
|
||||
}
|
||||
|
||||
static void init_sec_buffer(SecBuffer *buffer, unsigned long type,
|
||||
void *data, unsigned long size)
|
||||
{
|
||||
|
|
@ -1105,6 +1111,7 @@ static int tls_handshake(URLContext *h)
|
|||
#endif
|
||||
|
||||
c->connected = 1;
|
||||
s->state = DTLS_STATE_FINISHED;
|
||||
|
||||
fail:
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -198,6 +198,9 @@ typedef struct WHIPContext {
|
|||
|
||||
/* The state of the RTC connection. */
|
||||
enum WHIPState state;
|
||||
/* The callback return value for DTLS. */
|
||||
int dtls_ret;
|
||||
int dtls_closed;
|
||||
|
||||
/* Parameters for the input audio and video codecs. */
|
||||
AVCodecParameters *audio_par;
|
||||
|
|
@ -345,6 +348,41 @@ static av_cold int certificate_key_init(AVFormatContext *s)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* When DTLS state change.
|
||||
*/
|
||||
static int dtls_context_on_state(AVFormatContext *s, const char* type, const char* desc)
|
||||
{
|
||||
int ret = 0;
|
||||
WHIPContext *whip = s->priv_data;
|
||||
int state = ff_dtls_state(whip->dtls_uc);
|
||||
|
||||
if (state == DTLS_STATE_CLOSED) {
|
||||
whip->dtls_closed = 1;
|
||||
av_log(whip, AV_LOG_VERBOSE, "DTLS session closed, type=%s, desc=%s, elapsed=%dms\n",
|
||||
type ? type : "", desc ? desc : "", ELAPSED(whip->whip_starttime, av_gettime()));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (state == DTLS_STATE_FAILED) {
|
||||
whip->state = WHIP_STATE_FAILED;
|
||||
av_log(whip, AV_LOG_ERROR, "DTLS session failed, type=%s, desc=%s\n",
|
||||
type ? type : "", desc ? desc : "");
|
||||
whip->dtls_ret = AVERROR(EIO);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (state == DTLS_STATE_FINISHED && whip->state < WHIP_STATE_DTLS_FINISHED) {
|
||||
whip->state = WHIP_STATE_DTLS_FINISHED;
|
||||
whip->whip_dtls_time = av_gettime();
|
||||
av_log(whip, AV_LOG_VERBOSE, "DTLS handshake is done, elapsed=%dms\n",
|
||||
ELAPSED(whip->whip_starttime, av_gettime()));
|
||||
return ret;
|
||||
}
|
||||
error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static av_cold int dtls_initialize(AVFormatContext *s)
|
||||
{
|
||||
WHIPContext *whip = s->priv_data;
|
||||
|
|
@ -1288,18 +1326,9 @@ next_packet:
|
|||
/* If got any DTLS messages, handle it. */
|
||||
if (is_dtls_packet(whip->buf, ret) && whip->state >= WHIP_STATE_ICE_CONNECTED || whip->state == WHIP_STATE_DTLS_CONNECTING) {
|
||||
whip->state = WHIP_STATE_DTLS_CONNECTING;
|
||||
ret = ffurl_handshake(whip->dtls_uc);
|
||||
if (ret < 0) {
|
||||
whip->state = WHIP_STATE_FAILED;
|
||||
av_log(whip, AV_LOG_VERBOSE, "DTLS session failed\n");
|
||||
if ((ret = ffurl_handshake(whip->dtls_uc)) < 0)
|
||||
goto end;
|
||||
}
|
||||
if (!ret) {
|
||||
whip->state = WHIP_STATE_DTLS_FINISHED;
|
||||
whip->whip_dtls_time = av_gettime();
|
||||
av_log(whip, AV_LOG_VERBOSE, "DTLS handshake is done, elapsed=%dms\n",
|
||||
ELAPSED(whip->whip_starttime, whip->whip_dtls_time));
|
||||
}
|
||||
dtls_context_on_state(s, NULL, NULL);
|
||||
goto next_packet;
|
||||
}
|
||||
}
|
||||
|
|
@ -1742,8 +1771,10 @@ static av_cold int whip_init(AVFormatContext *s)
|
|||
goto end;
|
||||
|
||||
end:
|
||||
if (ret < 0)
|
||||
if (ret < 0 && whip->state < WHIP_STATE_FAILED)
|
||||
whip->state = WHIP_STATE_FAILED;
|
||||
if (ret >= 0 && whip->state >= WHIP_STATE_FAILED && whip->dtls_ret < 0)
|
||||
ret = whip->dtls_ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -1791,8 +1822,12 @@ static int whip_write_packet(AVFormatContext *s, AVPacket *pkt)
|
|||
}
|
||||
|
||||
end:
|
||||
if (ret < 0)
|
||||
if (ret < 0 && whip->state < WHIP_STATE_FAILED)
|
||||
whip->state = WHIP_STATE_FAILED;
|
||||
if (ret >= 0 && whip->state >= WHIP_STATE_FAILED && whip->dtls_ret < 0)
|
||||
ret = whip->dtls_ret;
|
||||
if (ret >= 0 && whip->dtls_closed)
|
||||
ret = AVERROR(EIO);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -229,8 +229,6 @@ static inline int ff_thread_setname(const char *name)
|
|||
#endif
|
||||
#elif HAVE_PTHREAD_SET_NAME_NP
|
||||
pthread_set_name_np(pthread_self(), name);
|
||||
#elif HAVE_W32THREADS
|
||||
ret = win32_thread_setname(name);
|
||||
#else
|
||||
ret = AVERROR(ENOSYS);
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue