summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathaniel Chin2021-04-23 22:15:14 +0800
committerNathaniel Chin2021-04-23 22:15:14 +0800
commitf063eca92c5f257ca81b9a1b827233c5852b131e (patch)
tree81de381916793fd65fa8bf1c825a24f898ec6c58
parent1ce174ba235991855b3dcee1d6f2c84cdc345780 (diff)
downloadaur-f063eca92c5f257ca81b9a1b827233c5852b131e.tar.gz
Fix svt-vp9 patch
-rw-r--r--.SRCINFO12
-rw-r--r--040-ffmpeg-add-svt-vp9.patch919
-rw-r--r--PKGBUILD14
3 files changed, 931 insertions, 14 deletions
diff --git a/.SRCINFO b/.SRCINFO
index f80d0b2146c9..ac0ce4ba6da2 100644
--- a/.SRCINFO
+++ b/.SRCINFO
@@ -1,6 +1,6 @@
pkgbase = ffmpeg-amd-full-git
pkgdesc = Complete solution to record, convert and stream audio and video (all possible features for AMD; git version)
- pkgver = 4.5.r101901.gb593abda6c
+ pkgver = 4.5.r102009.gefdb564504
pkgrel = 1
url = https://www.ffmpeg.org/
arch = i686
@@ -130,15 +130,15 @@ pkgbase = ffmpeg-amd-full-git
conflicts = ffmpeg
source = git+https://git.ffmpeg.org/ffmpeg.git
source = 010-ffmpeg-fix-vmaf-model-path.patch
- source = 020-ffmpeg-add-svt-hevc-gead6fdf.patch::https://raw.githubusercontent.com/OpenVisualCloud/SVT-HEVC/ead6fdf7c9ff84511b42fc1658c1654b84d83e4b/ffmpeg_plugin/0001-lavc-svt_hevc-add-libsvt-hevc-encoder-wrapper.patch
- source = 030-ffmpeg-add-svt-hevc-docs-gead6fdf.patch::https://raw.githubusercontent.com/OpenVisualCloud/SVT-HEVC/ead6fdf7c9ff84511b42fc1658c1654b84d83e4b/ffmpeg_plugin/0002-doc-Add-libsvt_hevc-encoder-docs.patch
- source = 040-ffmpeg-add-svt-vp9-g7951c3c.patch::https://raw.githubusercontent.com/OpenVisualCloud/SVT-VP9/7951c3cf6773c5e0ede00e4ce3e3ad2f7e090cfb/ffmpeg_plugin/master-0001-Add-ability-for-ffmpeg-to-run-svt-vp9.patch
+ source = 020-ffmpeg-add-svt-hevc-g33ca9aa.patch::https://raw.githubusercontent.com/OpenVisualCloud/SVT-HEVC/33ca9aa8a2a2d28022d3fc03704e99ce01828376/ffmpeg_plugin/0001-lavc-svt_hevc-add-libsvt-hevc-encoder-wrapper.patch
+ source = 030-ffmpeg-add-svt-hevc-docs-g33ca9aa.patch::https://raw.githubusercontent.com/OpenVisualCloud/SVT-HEVC/33ca9aa8a2a2d28022d3fc03704e99ce01828376/ffmpeg_plugin/0002-doc-Add-libsvt_hevc-encoder-docs.patch
+ source = 040-ffmpeg-add-svt-vp9.patch
source = LICENSE
sha256sums = SKIP
sha256sums = 52778c70d9fe6e3a10941b99b96ac7749cec325dc1b9ee11ab75332b5ff68e50
- sha256sums = 05ec4d3323dc80ef6c1d4d6d50d339accd51d22b12a735b7a6605f10feb09cec
+ sha256sums = 740dc9838aa47daa9f9b107178e53e384344f4c6f90865bd7e3af189257da544
sha256sums = 1499e419dda72b1604dc5e3959668f3843292ff56bfba78734e31510ba576de0
- sha256sums = 34e78efe063abc10707e47b4a3ba9d22955bfaf26d5670abb963d8f11f6b22b1
+ sha256sums = ab62715392cb1aee475a95bbe4d4205552fe23e5dd50b85ca7be72a8fcd9fbfe
sha256sums = 04a7176400907fd7db0d69116b99de49e582a6e176b3bfb36a03e50a4cb26a36
pkgname = ffmpeg-amd-full-git
diff --git a/040-ffmpeg-add-svt-vp9.patch b/040-ffmpeg-add-svt-vp9.patch
new file mode 100644
index 000000000000..9937f75b5bfa
--- /dev/null
+++ b/040-ffmpeg-add-svt-vp9.patch
@@ -0,0 +1,919 @@
+--- a/configure
++++ b/configure
+@@ -286,6 +286,7 @@ External library support:
+ --enable-libvorbis enable Vorbis en/decoding via libvorbis,
+ native implementation exists [no]
+ --enable-libvpx enable VP8 and VP9 de/encoding via libvpx [no]
++ --enable-libsvtvp9 enable VP9 encoding via svt [no]
+ --enable-libwebp enable WebP encoding via libwebp [no]
+ --enable-libx264 enable H.264 encoding via x264 [no]
+ --enable-libx265 enable HEVC encoding via x265 [no]
+@@ -1803,6 +1804,7 @@ EXTERNAL_LIBRARY_LIST="
+ librtmp
+ libshine
+ libsmbclient
++ libsvtvp9
+ libsnappy
+ libsoxr
+ libspeex
+@@ -3283,6 +3285,7 @@ libvpx_vp8_decoder_deps="libvpx"
+ libvpx_vp8_encoder_deps="libvpx"
+ libvpx_vp9_decoder_deps="libvpx"
+ libvpx_vp9_encoder_deps="libvpx"
++libsvt_vp9_encoder_deps="libsvtvp9"
+ libwebp_encoder_deps="libwebp"
+ libwebp_anim_encoder_deps="libwebp"
+ libx262_encoder_deps="libx262"
+@@ -6468,6 +6471,7 @@ enabled libvpx && {
+ fi
+ }
+
++enabled libsvtvp9 && require_pkg_config libsvtvp9 SvtVp9Enc EbSvtVp9Enc.h eb_vp9_svt_init_handle
+ enabled libwebp && {
+ enabled libwebp_encoder && require_pkg_config libwebp "libwebp >= 0.2.0" webp/encode.h WebPGetEncoderVersion
+ enabled libwebp_anim_encoder && check_pkg_config libwebp_anim_encoder "libwebpmux >= 0.4.0" webp/mux.h WebPAnimEncoderOptionsInit; }
+--- a/libavcodec/Makefile
++++ b/libavcodec/Makefile
+@@ -1065,6 +1065,7 @@ OBJS-$(CONFIG_LIBVPX_VP8_DECODER) += libvpxdec.o
+ OBJS-$(CONFIG_LIBVPX_VP8_ENCODER) += libvpxenc.o
+ OBJS-$(CONFIG_LIBVPX_VP9_DECODER) += libvpxdec.o libvpx.o
+ OBJS-$(CONFIG_LIBVPX_VP9_ENCODER) += libvpxenc.o libvpx.o
++OBJS-$(CONFIG_LIBSVT_VP9_ENCODER) += libsvt_vp9.o
+ OBJS-$(CONFIG_LIBWEBP_ENCODER) += libwebpenc_common.o libwebpenc.o
+ OBJS-$(CONFIG_LIBWEBP_ANIM_ENCODER) += libwebpenc_common.o libwebpenc_animencoder.o
+ OBJS-$(CONFIG_LIBX262_ENCODER) += libx264.o
+--- a/libavcodec/allcodecs.c
++++ b/libavcodec/allcodecs.c
+@@ -758,6 +758,7 @@ extern AVCodec ff_libvpx_vp8_encoder;
+ extern AVCodec ff_libvpx_vp8_decoder;
+ extern AVCodec ff_libvpx_vp9_encoder;
+ extern AVCodec ff_libvpx_vp9_decoder;
++extern AVCodec ff_libsvt_vp9_encoder;
+ /* preferred over libwebp */
+ extern AVCodec ff_libwebp_anim_encoder;
+ extern AVCodec ff_libwebp_encoder;
+--- a/libavcodec/avcodec.h
++++ b/libavcodec/avcodec.h
+@@ -405,6 +405,10 @@ typedef struct RcOverride{
+ * Export encoder Producer Reference Time through packet side data
+ */
+ #define AV_CODEC_EXPORT_DATA_PRFT (1 << 1)
++
++#define AV_PKT_FLAG_SVT_VP9_EXT_ON 0x10000 // Indicating SVT VP9 frame header ext on
++#define AV_PKT_FLAG_SVT_VP9_EXT_OFF 0x20000 // Indicating SVT VP9 frame header ext off
++
+ /**
+ * Decoding only.
+ * Export the AVVideoEncParams structure through frame side data.
+new file mode 100644
+index 0000000000..a557019c9b
+--- /dev/null
++++ b/libavcodec/libsvt_vp9.c
+@@ -0,0 +1,509 @@
++/*
++* Scalable Video Technology for VP9 encoder library plugin
++*
++* Copyright (c) 2018 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 this program; if not, write to the Free Software
++* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++*/
++
++#include <stdint.h>
++#include "EbSvtVp9ErrorCodes.h"
++#include "EbSvtVp9Enc.h"
++
++#include "libavutil/common.h"
++#include "libavutil/frame.h"
++#include "libavutil/opt.h"
++
++#include "internal.h"
++#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(58, 93, 100)
++#include "encode.h"
++#endif
++#include "avcodec.h"
++
++typedef enum eos_status {
++ EOS_NOT_REACHED = 0,
++ EOS_REACHED,
++ EOS_TOTRIGGER
++}EOS_STATUS;
++
++typedef struct SvtContext {
++ AVClass *class;
++
++ EbSvtVp9EncConfiguration enc_params;
++ EbComponentType *svt_handle;
++
++ EbBufferHeaderType *in_buf;
++ int raw_size;
++
++ AVFrame *frame;
++
++ AVBufferPool* pool;
++
++ EOS_STATUS eos_flag;
++
++ // User options.
++ int enc_mode;
++ int rc_mode;
++ int tune;
++ int qp;
++
++ int forced_idr;
++
++ int level;
++
++ int base_layer_switch_mode;
++} SvtContext;
++
++static int error_mapping(EbErrorType svt_ret)
++{
++ int err;
++
++ switch (svt_ret) {
++ case EB_ErrorInsufficientResources:
++ err = AVERROR(ENOMEM);
++ break;
++
++ case EB_ErrorUndefined:
++ case EB_ErrorInvalidComponent:
++ case EB_ErrorBadParameter:
++ err = AVERROR(EINVAL);
++ break;
++
++ case EB_ErrorDestroyThreadFailed:
++ case EB_ErrorSemaphoreUnresponsive:
++ case EB_ErrorDestroySemaphoreFailed:
++ case EB_ErrorCreateMutexFailed:
++ case EB_ErrorMutexUnresponsive:
++ case EB_ErrorDestroyMutexFailed:
++ err = AVERROR_EXTERNAL;
++ break;
++
++ case EB_NoErrorEmptyQueue:
++ err = AVERROR(EAGAIN);
++
++ case EB_ErrorNone:
++ err = 0;
++ break;
++
++ default:
++ err = AVERROR_UNKNOWN;
++ }
++
++ return err;
++}
++
++static void free_buffer(SvtContext *svt_enc)
++{
++ if (svt_enc->in_buf) {
++ EbSvtEncInput *in_data = (EbSvtEncInput *)svt_enc->in_buf->p_buffer;
++ av_freep(&in_data);
++ av_freep(&svt_enc->in_buf);
++ }
++ av_buffer_pool_uninit(&svt_enc->pool);
++}
++
++static int alloc_buffer(EbSvtVp9EncConfiguration *config, SvtContext *svt_enc)
++{
++ const size_t luma_size_8bit =
++ config->source_width * config->source_height;
++ const size_t luma_size_10bit =
++ (config->encoder_bit_depth > 8) ? luma_size_8bit : 0;
++
++ EbSvtEncInput *in_data;
++
++ svt_enc->raw_size = (luma_size_8bit + luma_size_10bit) * 3 / 2;
++
++ // allocate buffer for in and out
++ svt_enc->in_buf = av_mallocz(sizeof(*svt_enc->in_buf));
++ if (!svt_enc->in_buf)
++ goto failed;
++
++
++ svt_enc->in_buf->p_buffer = (unsigned char *)av_mallocz(sizeof(*in_data));
++ if (!svt_enc->in_buf->p_buffer)
++ goto failed;
++
++ svt_enc->in_buf->size = sizeof(*svt_enc->in_buf);
++ svt_enc->in_buf->p_app_private = NULL;
++
++ svt_enc->pool = av_buffer_pool_init(svt_enc->raw_size, NULL);
++ if (!svt_enc->pool)
++ goto failed;
++
++ return 0;
++
++failed:
++ free_buffer(svt_enc);
++ return AVERROR(ENOMEM);
++}
++
++static int config_enc_params(EbSvtVp9EncConfiguration *param,
++ AVCodecContext *avctx)
++{
++ SvtContext *svt_enc = avctx->priv_data;
++ int ret;
++ int ten_bits = 0;
++
++ param->source_width = avctx->width;
++ param->source_height = avctx->height;
++
++ if (avctx->pix_fmt == AV_PIX_FMT_YUV420P10LE) {
++ av_log(avctx, AV_LOG_DEBUG , "Encoder 10 bits depth input\n");
++ // Disable Compressed 10-bit format default
++ ten_bits = 1;
++ }
++
++ // Update param from options
++ param->enc_mode = svt_enc->enc_mode;
++ param->level = svt_enc->level;
++ param->rate_control_mode = svt_enc->rc_mode;
++ param->tune = svt_enc->tune;
++ param->base_layer_switch_mode = svt_enc->base_layer_switch_mode;
++ param->qp = svt_enc->qp;
++
++ param->target_bit_rate = avctx->bit_rate;
++ if (avctx->gop_size > 0)
++ param->intra_period = avctx->gop_size - 1;
++
++ if (avctx->framerate.num > 0 && avctx->framerate.den > 0) {
++ param->frame_rate_numerator = avctx->framerate.num;
++ param->frame_rate_denominator = avctx->framerate.den * avctx->ticks_per_frame;
++ } else {
++ param->frame_rate_numerator = avctx->time_base.den;
++ param->frame_rate_denominator = avctx->time_base.num * avctx->ticks_per_frame;
++ }
++
++ if (param->rate_control_mode) {
++ param->max_qp_allowed = avctx->qmax;
++ param->min_qp_allowed = avctx->qmin;
++ }
++
++ if (ten_bits) {
++ param->encoder_bit_depth = 10;
++ }
++
++ ret = alloc_buffer(param, svt_enc);
++
++ return ret;
++}
++
++static void read_in_data(EbSvtVp9EncConfiguration *config,
++ const AVFrame *frame,
++ EbBufferHeaderType *headerPtr)
++{
++ uint8_t is16bit = config->encoder_bit_depth > 8;
++ uint64_t luma_size =
++ (uint64_t)config->source_width * config->source_height<< is16bit;
++ EbSvtEncInput *in_data = (EbSvtEncInput *)headerPtr->p_buffer;
++
++ // support yuv420p and yuv420p010
++ in_data->luma = frame->data[0];
++ in_data->cb = frame->data[1];
++ in_data->cr = frame->data[2];
++
++ // stride info
++ in_data->y_stride = frame->linesize[0] >> is16bit;
++ in_data->cb_stride = frame->linesize[1] >> is16bit;
++ in_data->cr_stride = frame->linesize[2] >> is16bit;
++
++ headerPtr->n_filled_len += luma_size * 3/2u;
++}
++
++static av_cold int eb_enc_init(AVCodecContext *avctx)
++{
++ SvtContext *svt_enc = avctx->priv_data;
++ EbErrorType svt_ret;
++
++ svt_enc->eos_flag = EOS_NOT_REACHED;
++
++ svt_ret = eb_vp9_svt_init_handle(&svt_enc->svt_handle, svt_enc, &svt_enc->enc_params);
++ if (svt_ret != EB_ErrorNone) {
++ av_log(avctx, AV_LOG_ERROR, "Error init encoder handle\n");
++ goto failed;
++ }
++
++ svt_ret = config_enc_params(&svt_enc->enc_params, avctx);
++ if (svt_ret != EB_ErrorNone) {
++ av_log(avctx, AV_LOG_ERROR, "Error configure encoder parameters\n");
++ goto failed_init_handle;
++ }
++
++ svt_ret = eb_vp9_svt_enc_set_parameter(svt_enc->svt_handle, &svt_enc->enc_params);
++ if (svt_ret != EB_ErrorNone) {
++ av_log(avctx, AV_LOG_ERROR, "Error setting encoder parameters\n");
++ goto failed_init_handle;
++ }
++
++ svt_ret = eb_vp9_init_encoder(svt_enc->svt_handle);
++ if (svt_ret != EB_ErrorNone) {
++ av_log(avctx, AV_LOG_ERROR, "Error init encoder\n");
++ goto failed_init_handle;
++ }
++
++ svt_enc->frame = av_frame_alloc();
++ if (!svt_enc->frame)
++ return AVERROR(ENOMEM);
++
++ // if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
++ // EbBufferHeaderType* headerPtr;
++ // headerPtr->size = sizeof(headerPtr);
++ // headerPtr->n_filled_len = 0; /* in/out */
++ // headerPtr->p_buffer = av_malloc(10 * 1024 * 1024);
++ // headerPtr->n_alloc_len = (10 * 1024 * 1024);
++ //
++ // if (!headerPtr->p_buffer) {
++ // av_log(avctx, AV_LOG_ERROR,
++ // "Cannot allocate buffer size %d.\n", headerPtr->n_alloc_len);
++ // svt_ret = EB_ErrorInsufficientResources;
++ // goto failed_init_enc;
++ // }
++ //
++ // svt_ret = eb_svt_enc_stream_header(svt_enc->svt_handle, &headerPtr);
++ // if (svt_ret != EB_ErrorNone) {
++ // av_log(avctx, AV_LOG_ERROR, "Error when build stream header.\n");
++ // av_freep(&headerPtr->p_buffer);
++ // goto failed_init_enc;
++ // }
++ //
++ // avctx->extradata_size = headerPtr->n_filled_len;
++ // avctx->extradata = av_mallocz(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
++ // if (!avctx->extradata) {
++ // av_log(avctx, AV_LOG_ERROR,
++ // "Cannot allocate VP9 header of size %d.\n", avctx->extradata_size);
++ // av_freep(&headerPtr->p_buffer);
++ // svt_ret = EB_ErrorInsufficientResources;
++ // goto failed_init_enc;
++ // }
++ // memcpy(avctx->extradata, headerPtr->p_buffer, avctx->extradata_size);
++ //
++ // av_freep(&headerPtr->p_buffer);
++ // }
++ return 0;
++
++//failed_init_enc:
++// eb_deinit_encoder(svt_enc->svt_handle);
++failed_init_handle:
++ eb_vp9_deinit_handle(svt_enc->svt_handle);
++failed:
++ free_buffer(svt_enc);
++ return error_mapping(svt_ret);
++}
++
++static int eb_send_frame(AVCodecContext *avctx, const AVFrame *frame)
++{
++ SvtContext *svt_enc = avctx->priv_data;
++ EbBufferHeaderType *headerPtr = svt_enc->in_buf;
++
++ if (!frame) {
++ if (svt_enc->eos_flag == EOS_REACHED)
++ return 0;
++
++ EbBufferHeaderType headerPtrLast;
++ headerPtrLast.n_alloc_len = 0;
++ headerPtrLast.n_filled_len = 0;
++ headerPtrLast.n_tick_count = 0;
++ headerPtrLast.p_app_private = NULL;
++ headerPtrLast.p_buffer = NULL;
++ headerPtrLast.flags = EB_BUFFERFLAG_EOS;
++
++ eb_vp9_svt_enc_send_picture(svt_enc->svt_handle, &headerPtrLast);
++ svt_enc->eos_flag = EOS_REACHED;
++ av_log(avctx, AV_LOG_DEBUG, "Finish sending frames!!!\n");
++ return 0;
++ }
++
++ read_in_data(&svt_enc->enc_params, frame, headerPtr);
++
++ headerPtr->flags = 0;
++ headerPtr->p_app_private = NULL;
++ headerPtr->pts = frame->pts;
++ switch (frame->pict_type) {
++ case AV_PICTURE_TYPE_I:
++ headerPtr->pic_type = svt_enc->forced_idr > 0 ? EB_IDR_PICTURE : EB_I_PICTURE;
++ break;
++ case AV_PICTURE_TYPE_P:
++ headerPtr->pic_type = EB_P_PICTURE;
++ break;
++ case AV_PICTURE_TYPE_B:
++ headerPtr->pic_type = EB_B_PICTURE;
++ break;
++ default:
++ headerPtr->pic_type = EB_INVALID_PICTURE;
++ break;
++ }
++ eb_vp9_svt_enc_send_picture(svt_enc->svt_handle, headerPtr);
++
++ return 0;
++}
++
++static int eb_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
++{
++ SvtContext *svt_enc = avctx->priv_data;
++ EbBufferHeaderType *headerPtr;
++ EbErrorType svt_ret;
++ AVBufferRef *ref;
++
++ if (EOS_TOTRIGGER == svt_enc->eos_flag) {
++ pkt = NULL;
++ return AVERROR_EOF;
++ }
++
++#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(58, 93, 100)
++ AVFrame *frame = svt_enc->frame;
++ int ret = ff_encode_get_frame(avctx, frame);
++ if (ret < 0 && ret != AVERROR_EOF)
++ return ret;
++ if (ret == AVERROR_EOF)
++ frame = NULL;
++
++ eb_send_frame(avctx, frame);
++ av_frame_unref(svt_enc->frame);
++#endif
++
++ svt_ret = eb_vp9_svt_get_packet(svt_enc->svt_handle, &headerPtr, svt_enc->eos_flag);
++ if (svt_ret == EB_NoErrorEmptyQueue)
++ return AVERROR(EAGAIN);
++
++ ref = av_buffer_pool_get(svt_enc->pool);
++ if (!ref) {
++ av_log(avctx, AV_LOG_ERROR, "Failed to allocate output packet.\n");
++ eb_vp9_svt_release_out_buffer(&headerPtr);
++ return AVERROR(ENOMEM);
++ }
++ pkt->buf = ref;
++ pkt->data = ref->data;
++
++ memcpy(pkt->data, headerPtr->p_buffer, headerPtr->n_filled_len);
++ pkt->size = headerPtr->n_filled_len;
++ pkt->pts = headerPtr->pts;
++ pkt->dts = headerPtr->dts;
++ if (headerPtr->pic_type == EB_IDR_PICTURE)
++ pkt->flags |= AV_PKT_FLAG_KEY;
++ if (headerPtr->pic_type == EB_NON_REF_PICTURE)
++ pkt->flags |= AV_PKT_FLAG_DISPOSABLE;
++
++ if (headerPtr->flags & EB_BUFFERFLAG_SHOW_EXT)
++ pkt->flags |= AV_PKT_FLAG_SVT_VP9_EXT_ON;
++ else
++ pkt->flags |= AV_PKT_FLAG_SVT_VP9_EXT_OFF;
++
++ if (EB_BUFFERFLAG_EOS & headerPtr->flags)
++ svt_enc->eos_flag = EOS_TOTRIGGER;
++
++ eb_vp9_svt_release_out_buffer(&headerPtr);
++ return 0;
++}
++
++static av_cold int eb_enc_close(AVCodecContext *avctx)
++{
++ SvtContext *svt_enc = avctx->priv_data;
++
++ eb_vp9_deinit_encoder(svt_enc->svt_handle);
++ eb_vp9_deinit_handle(svt_enc->svt_handle);
++
++ av_frame_free(&svt_enc->frame);
++
++ free_buffer(svt_enc);
++
++ return 0;
++}
++
++#define OFFSET(x) offsetof(SvtContext, x)
++#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
++static const AVOption options[] = {
++ { "preset", "Encoding preset [1, 1]",
++ OFFSET(enc_mode), AV_OPT_TYPE_INT, { .i64 = 9 }, 0, 9, VE },
++
++ { "level", "Set level (level_idc)", OFFSET(level),
++ AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 0xff, VE, "level" },
++
++#define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \
++ { .i64 = value }, 0, 0, VE, "level"
++ { LEVEL("1", 10) },
++ { LEVEL("2", 20) },
++ { LEVEL("2.1", 21) },
++ { LEVEL("3", 30) },
++ { LEVEL("3.1", 31) },
++ { LEVEL("4", 40) },
++ { LEVEL("4.1", 41) },
++ { LEVEL("5", 50) },
++ { LEVEL("5.1", 51) },
++ { LEVEL("5.2", 52) },
++ { LEVEL("6", 60) },
++ { LEVEL("6.1", 61) },
++ { LEVEL("6.2", 62) },
++#undef LEVEL
++
++ { "tune", "Tune mode", OFFSET(tune),
++ AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, VE , "tune"},
++ { "vq", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, VE, "tune" },
++ { "ssim", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, VE, "tune" },
++ { "vmaf", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, INT_MIN, INT_MAX, VE, "tune" },
++
++ { "rc", "Bit rate control mode", OFFSET(rc_mode),
++ AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, VE , "rc"},
++ { "cqp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, VE, "rc" },
++ { "vbr", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, VE, "rc" },
++ { "cbr", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, INT_MIN, INT_MAX, VE, "rc" },
++
++ { "qp", "QP value for intra frames", OFFSET(qp),
++ AV_OPT_TYPE_INT, { .i64 = 32 }, 0, 51, VE },
++
++ { "bl_mode", "Random Access Prediction Structure type setting", OFFSET(base_layer_switch_mode),
++ AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE },
++
++ { "forced-idr", "If forcing keyframes, force them as IDR frames.", OFFSET(forced_idr),
++ AV_OPT_TYPE_BOOL, { .i64 = 0 }, -1, 1, VE },
++
++ {NULL},
++};
++
++static const AVClass class = {
++ .class_name = "libsvt_vp9",
++ .item_name = av_default_item_name,
++ .option = options,
++ .version = LIBAVUTIL_VERSION_INT,
++};
++
++static const AVCodecDefault eb_enc_defaults[] = {
++ { "b", "7M" },
++ { "flags", "-cgop" },
++ { "qmin", "10" },
++ { "qmax", "48" },
++ { NULL },
++};
++
++AVCodec ff_libsvt_vp9_encoder = {
++ .name = "libsvt_vp9",
++ .long_name = NULL_IF_CONFIG_SMALL("SVT-VP9(Scalable Video Technology for VP9) encoder"),
++ .priv_data_size = sizeof(SvtContext),
++ .type = AVMEDIA_TYPE_VIDEO,
++ .id = AV_CODEC_ID_VP9,
++ .init = eb_enc_init,
++#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 93, 100)
++ .send_frame = eb_send_frame,
++#endif
++ .receive_packet = eb_receive_packet,
++ .close = eb_enc_close,
++ .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS,
++ .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P,
++ AV_PIX_FMT_NONE },
++ .priv_class = &class,
++ .defaults = eb_enc_defaults,
++ .caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
++ .wrapper_name = "libsvt_vp9",
++};
+--- a/libavformat/dashenc.c
++++ b/libavformat/dashenc.c
+@@ -2271,6 +2271,48 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt)
+ return ret;
+ }
+
++static int dash_write_packet_vp9(AVFormatContext *s, AVPacket *pkt)
++{
++ int ret;
++ if (pkt->flags & AV_PKT_FLAG_SVT_VP9_EXT_ON) {
++ uint8_t *saved_data = pkt->data;
++ int saved_size = pkt->size;
++ int64_t saved_pts = pkt->pts;
++
++ // Main frame
++ pkt->data = saved_data;
++ pkt->size = saved_size - 4;
++ pkt->pts = saved_pts;
++ ret = dash_write_packet(s, pkt);
++
++ // Latter 4 one-byte repeated frames
++ pkt->data = saved_data + saved_size - 4;
++ pkt->size = 1;
++ pkt->pts = saved_pts - 2;
++ ret = dash_write_packet(s, pkt);
++
++ pkt->data = saved_data + saved_size - 3;
++ pkt->size = 1;
++ pkt->pts = saved_pts - 1;
++ ret = dash_write_packet(s, pkt);
++
++ pkt->data = saved_data + saved_size - 2;
++ pkt->size = 1;
++ pkt->pts = saved_pts;
++ ret = dash_write_packet(s, pkt);
++
++ pkt->data = saved_data + saved_size - 1;
++ pkt->size = 1;
++ pkt->pts = saved_pts + 1;
++ ret = dash_write_packet(s, pkt);
++ }
++ else{
++ ret = dash_write_packet(s, pkt);
++ }
++
++ return ret;
++}
++
+ static int dash_write_trailer(AVFormatContext *s)
+ {
+ DASHContext *c = s->priv_data;
+@@ -2318,6 +2360,11 @@ static int dash_check_bitstream(struct AVFormatContext *s, const AVPacket *avpkt
+ DASHContext *c = s->priv_data;
+ OutputStream *os = &c->streams[avpkt->stream_index];
+ AVFormatContext *oc = os->ctx;
++
++ if ((avpkt->flags & AV_PKT_FLAG_SVT_VP9_EXT_ON) ||
++ (avpkt->flags & AV_PKT_FLAG_SVT_VP9_EXT_OFF))
++ return 0;
++
+ if (oc->oformat->check_bitstream) {
+ int ret;
+ AVPacket pkt = *avpkt;
+@@ -2405,7 +2452,7 @@ AVOutputFormat ff_dash_muxer = {
+ .flags = AVFMT_GLOBALHEADER | AVFMT_NOFILE | AVFMT_TS_NEGATIVE,
+ .init = dash_init,
+ .write_header = dash_write_header,
+- .write_packet = dash_write_packet,
++ .write_packet = dash_write_packet_vp9,
+ .write_trailer = dash_write_trailer,
+ .deinit = dash_free,
+ .check_bitstream = dash_check_bitstream,
+--- a/libavformat/ivfenc.c
++++ b/libavformat/ivfenc.c
+@@ -81,9 +81,33 @@ static int ivf_write_packet(AVFormatContext *s, AVPacket *pkt)
+ AVIOContext *pb = s->pb;
+ IVFEncContext *ctx = s->priv_data;
+
+- avio_wl32(pb, pkt->size);
+- avio_wl64(pb, pkt->pts);
+- avio_write(pb, pkt->data, pkt->size);
++ if (pkt->flags & AV_PKT_FLAG_SVT_VP9_EXT_ON) {
++ avio_wl32(pb, pkt->size - 4);
++ avio_wl64(pb, pkt->pts);
++ avio_write(pb, pkt->data, pkt->size - 4);
++
++ avio_wl32(pb, 1);
++ avio_wl64(pb, pkt->pts - 2);
++ avio_write(pb, pkt->data + pkt->size - 4, 1);
++
++ avio_wl32(pb, 1);
++ avio_wl64(pb, pkt->pts - 1);
++ avio_write(pb, pkt->data + pkt->size - 3, 1);
++
++ avio_wl32(pb, 1);
++ avio_wl64(pb, pkt->pts);
++ avio_write(pb, pkt->data + pkt->size - 2, 1);
++
++ avio_wl32(pb, 1);
++ avio_wl64(pb, pkt->pts + 1);
++ avio_write(pb, pkt->data + pkt->size - 1, 1);
++ }
++ else {
++ avio_wl32(pb, pkt->size);
++ avio_wl64(pb, pkt->pts);
++ avio_write(pb, pkt->data, pkt->size);
++ }
++
+ if (ctx->frame_cnt)
+ ctx->sum_delta_pts += pkt->pts - ctx->last_pts;
+ ctx->last_pkt_duration = pkt->duration;
+--- a/libavformat/matroskaenc.c
++++ b/libavformat/matroskaenc.c
+@@ -142,6 +142,9 @@ typedef struct MatroskaMuxContext {
+ unsigned nb_attachments;
+ int have_video;
+
++ int simple_block_timecode;
++ int accumulated_cluster_timecode;
++
+ int wrote_chapters;
+ int wrote_tags;
+
+@@ -2108,7 +2111,13 @@ static int mkv_write_block(AVFormatContext *s, AVIOContext *pb,
+ put_ebml_id(pb, blockid);
+ put_ebml_length(pb, size + track->track_num_size + 3, 0);
+ put_ebml_num(pb, track_number, track->track_num_size);
+- avio_wb16(pb, ts - mkv->cluster_pts);
++
++ if ((pkt->flags & AV_PKT_FLAG_SVT_VP9_EXT_ON) ||
++ (pkt->flags & AV_PKT_FLAG_SVT_VP9_EXT_OFF))
++ avio_wb16(pb, mkv->simple_block_timecode);
++ else
++ avio_wb16(pb, ts - mkv->cluster_pts);
++
+ avio_w8(pb, (blockid == MATROSKA_ID_SIMPLEBLOCK && keyframe) ? (1 << 7) : 0);
+ avio_write(pb, data + offset, size);
+ if (data != pkt->data)
+@@ -2301,7 +2310,7 @@ static int mkv_check_new_extra_data(AVFormatContext *s, const AVPacket *pkt)
+ return 0;
+ }
+
+-static int mkv_write_packet_internal(AVFormatContext *s, const AVPacket *pkt)
++static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
+ {
+ MatroskaMuxContext *mkv = s->priv_data;
+ AVIOContext *pb;
+@@ -2312,6 +2321,8 @@ static int mkv_write_packet_internal(AVFormatContext *s, const AVPacket *pkt)
+ int ret;
+ int64_t ts = track->write_dts ? pkt->dts : pkt->pts;
+ int64_t relative_packet_pos;
++ double fps = 0;
++ int pts_interval = 0;
+
+ if (ts == AV_NOPTS_VALUE) {
+ av_log(s, AV_LOG_ERROR, "Can't write packet with unknown timestamp\n");
+@@ -2329,6 +2340,11 @@ static int mkv_write_packet_internal(AVFormatContext *s, const AVPacket *pkt)
+ }
+ }
+
++ if ((pkt->flags & AV_PKT_FLAG_SVT_VP9_EXT_ON) || (pkt->flags & AV_PKT_FLAG_SVT_VP9_EXT_OFF)) {
++ fps = av_q2d(s->streams[pkt->stream_index]->avg_frame_rate);
++ pts_interval = 1000 / fps;
++ }
++
+ if (mkv->cluster_pos == -1) {
+ ret = start_ebml_master_crc32(&mkv->cluster_bc, mkv);
+ if (ret < 0)
+@@ -2347,7 +2363,67 @@ static int mkv_write_packet_internal(AVFormatContext *s, const AVPacket *pkt)
+
+ if (par->codec_type != AVMEDIA_TYPE_SUBTITLE ||
+ (par->codec_id != AV_CODEC_ID_WEBVTT && duration <= 0)) {
+- ret = mkv_write_block(s, pb, MATROSKA_ID_SIMPLEBLOCK, pkt, keyframe);
++ if (pkt->flags & AV_PKT_FLAG_SVT_VP9_EXT_ON) {
++ uint8_t *saved_data = pkt->data;
++ int saved_size = pkt->size;
++ int64_t saved_pts = pkt->pts;
++ // Main frame
++ pkt->data = saved_data;
++ pkt->size = saved_size - 4;
++ pkt->pts = saved_pts;
++ mkv_write_block(s, pb, MATROSKA_ID_SIMPLEBLOCK, pkt, keyframe);
++
++ // Latter 4 one-byte repeated frames
++ pkt->data = saved_data + saved_size - 4;
++ pkt->size = 1;
++ pkt->pts = saved_pts - 2;
++ mkv_write_block(s, pb, MATROSKA_ID_SIMPLEBLOCK, pkt, keyframe);
++ mkv->simple_block_timecode += pts_interval;
++
++ pkt->data = saved_data + saved_size - 3;
++ pkt->size = 1;
++ pkt->pts = saved_pts - 1;
++ mkv_write_block(s, pb, MATROSKA_ID_SIMPLEBLOCK, pkt, keyframe);
++ mkv->simple_block_timecode += pts_interval;
++
++ pkt->data = saved_data + saved_size - 2;
++ pkt->size = 1;
++ pkt->pts = saved_pts;
++ mkv_write_block(s, pb, MATROSKA_ID_SIMPLEBLOCK, pkt, keyframe);
++ mkv->simple_block_timecode += pts_interval;
++
++ pkt->data = saved_data + saved_size - 1;
++ pkt->size = 1;
++ pkt->pts = saved_pts + 1;
++ mkv_write_block(s, pb, MATROSKA_ID_SIMPLEBLOCK, pkt, keyframe);
++ mkv->simple_block_timecode += pts_interval;
++ } else {
++ ret = mkv_write_block(s, pb, MATROSKA_ID_SIMPLEBLOCK, pkt, keyframe);
++ if (ret < 0) return ret;
++ if (pkt->flags & AV_PKT_FLAG_SVT_VP9_EXT_OFF) {
++ GetBitContext gb;
++ int invisible, profile;
++
++ if ((ret = init_get_bits8(&gb, pkt->data, pkt->size)) < 0)
++ return ret;
++
++ get_bits(&gb, 2); // frame marker
++ profile = get_bits1(&gb);
++ profile |= get_bits1(&gb) << 1;
++ if (profile == 3) profile += get_bits1(&gb);
++
++ if (get_bits1(&gb)) {
++ invisible = 0;
++ } else {
++ get_bits1(&gb); // keyframe
++ invisible = !get_bits1(&gb);
++ }
++
++ if (!invisible)
++ mkv->simple_block_timecode += pts_interval;
++ }
++ }
++
+ if (ret < 0)
+ return ret;
+ if (keyframe && IS_SEEKABLE(s->pb, mkv) &&
+@@ -2415,8 +2491,14 @@ static int mkv_write_packet(AVFormatContext *s, const AVPacket *pkt)
+ if (mkv->cluster_pos != -1) {
+ if (mkv->tracks[pkt->stream_index].write_dts)
+ cluster_time = pkt->dts - mkv->cluster_pts;
+- else
+- cluster_time = pkt->pts - mkv->cluster_pts;
++ else {
++ if ((pkt->flags & AV_PKT_FLAG_SVT_VP9_EXT_ON) ||
++ (pkt->flags & AV_PKT_FLAG_SVT_VP9_EXT_OFF))
++ cluster_time = mkv->accumulated_cluster_timecode - mkv->cluster_pts;
++ else
++ cluster_time = pkt->pts - mkv->cluster_pts;
++ }
++
+ cluster_time += mkv->tracks[pkt->stream_index].ts_offset;
+
+ cluster_size = avio_tell(mkv->cluster_bc);
+@@ -2440,7 +2522,13 @@ static int mkv_write_packet(AVFormatContext *s, const AVPacket *pkt)
+ start_new_cluster = 0;
+
+ if (start_new_cluster) {
+- ret = mkv_end_cluster(s);
++ if ((pkt->flags & AV_PKT_FLAG_SVT_VP9_EXT_ON) ||
++ (pkt->flags & AV_PKT_FLAG_SVT_VP9_EXT_OFF)) {
++ // Reset Timecode for new cluster.
++ mkv->accumulated_cluster_timecode += mkv->simple_block_timecode;
++ mkv->simple_block_timecode = 0;
++ }
++ ret = mkv_end_cluster(s);
+ if (ret < 0)
+ return ret;
+ }
+@@ -2780,6 +2868,10 @@ static int mkv_check_bitstream(struct AVFormatContext *s, const AVPacket *pkt)
+ int ret = 1;
+ AVStream *st = s->streams[pkt->stream_index];
+
++ if ((pkt->flags & AV_PKT_FLAG_SVT_VP9_EXT_ON) ||
++ (pkt->flags & AV_PKT_FLAG_SVT_VP9_EXT_OFF))
++ return 0;
++
+ if (st->codecpar->codec_id == AV_CODEC_ID_AAC) {
+ if (pkt->size > 2 && (AV_RB16(pkt->data) & 0xfff0) == 0xfff0)
+ ret = ff_stream_add_bitstream_filter(st, "aac_adtstoasc", NULL);
+--- a/libavformat/movenc.c
++++ b/libavformat/movenc.c
+@@ -5978,7 +5978,43 @@ static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt)
+ }
+ }
+
+- return ff_mov_write_packet(s, pkt);
++ if (pkt->flags & AV_PKT_FLAG_SVT_VP9_EXT_ON) {
++ uint8_t *saved_data = pkt->data;
++ int saved_size = pkt->size;
++ int64_t saved_pts = pkt->pts;
++
++ // Main frame
++ pkt->data = saved_data;
++ pkt->size = saved_size - 4;
++ pkt->pts = saved_pts;
++ ret = ff_mov_write_packet(s, pkt);
++
++ // Latter 4 one-byte repeated frames
++ pkt->data = saved_data + saved_size - 4;
++ pkt->size = 1;
++ pkt->pts = saved_pts - 2;
++ ret = ff_mov_write_packet(s, pkt);
++
++ pkt->data = saved_data + saved_size - 3;
++ pkt->size = 1;
++ pkt->pts = saved_pts - 1;
++ ret = ff_mov_write_packet(s, pkt);
++
++ pkt->data = saved_data + saved_size - 2;
++ pkt->size = 1;
++ pkt->pts = saved_pts;
++ ret = ff_mov_write_packet(s, pkt);
++
++ pkt->data = saved_data + saved_size - 1;
++ pkt->size = 1;
++ pkt->pts = saved_pts + 1;
++ ret = ff_mov_write_packet(s, pkt);
++ }
++ else{
++ ret = ff_mov_write_packet(s, pkt);
++ }
++
++ return ret;
+ }
+
+ static int mov_write_subtitle_end_packet(AVFormatContext *s,
+@@ -7165,6 +7201,10 @@ static int mov_check_bitstream(struct AVFormatContext *s, const AVPacket *pkt)
+ int ret = 1;
+ AVStream *st = s->streams[pkt->stream_index];
+
++ if ((pkt->flags & AV_PKT_FLAG_SVT_VP9_EXT_ON) ||
++ (pkt->flags & AV_PKT_FLAG_SVT_VP9_EXT_OFF))
++ return 0;
++
+ if (st->codecpar->codec_id == AV_CODEC_ID_AAC) {
+ if (pkt->size > 2 && (AV_RB16(pkt->data) & 0xfff0) == 0xfff0)
+ ret = ff_stream_add_bitstream_filter(st, "aac_adtstoasc", NULL);
diff --git a/PKGBUILD b/PKGBUILD
index 2cab23368117..171e1c45be55 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -3,12 +3,9 @@
# Contributor: Marko Korhonen <reekymarko at reekynet.com>
# Contributor: Bruno Filipe < gmail-com: bmilreu >
-_svt_hevc_ver='ead6fdf7c9ff84511b42fc1658c1654b84d83e4b'
-_svt_vp9_ver='7951c3cf6773c5e0ede00e4ce3e3ad2f7e090cfb'
-
pkgname=ffmpeg-amd-full-git
_srcname=ffmpeg
-pkgver=4.5.r101901.gb593abda6c
+pkgver=4.5.r102009.gefdb564504
pkgrel=1
pkgdesc='Complete solution to record, convert and stream audio and video (all possible features for AMD; git version)'
arch=('i686' 'x86_64')
@@ -44,17 +41,18 @@ provides=('libavcodec.so' 'libavdevice.so' 'libavfilter.so' 'libavformat.so'
'libavutil.so' 'libpostproc.so' 'libavresample.so' 'libswscale.so'
'libswresample.so' 'ffmpeg' 'ffmpeg-full' 'ffmpeg-git')
conflicts=('ffmpeg')
+_svt_hevc_ver='33ca9aa8a2a2d28022d3fc03704e99ce01828376'
source=('git+https://git.ffmpeg.org/ffmpeg.git'
'010-ffmpeg-fix-vmaf-model-path.patch'
"020-ffmpeg-add-svt-hevc-g${_svt_hevc_ver:0:7}.patch"::"https://raw.githubusercontent.com/OpenVisualCloud/SVT-HEVC/${_svt_hevc_ver}/ffmpeg_plugin/0001-lavc-svt_hevc-add-libsvt-hevc-encoder-wrapper.patch"
"030-ffmpeg-add-svt-hevc-docs-g${_svt_hevc_ver:0:7}.patch"::"https://raw.githubusercontent.com/OpenVisualCloud/SVT-HEVC/${_svt_hevc_ver}/ffmpeg_plugin/0002-doc-Add-libsvt_hevc-encoder-docs.patch"
- "040-ffmpeg-add-svt-vp9-g${_svt_vp9_ver:0:7}.patch"::"https://raw.githubusercontent.com/OpenVisualCloud/SVT-VP9/${_svt_vp9_ver}/ffmpeg_plugin/master-0001-Add-ability-for-ffmpeg-to-run-svt-vp9.patch"
+ '040-ffmpeg-add-svt-vp9.patch'
'LICENSE')
sha256sums=('SKIP'
'52778c70d9fe6e3a10941b99b96ac7749cec325dc1b9ee11ab75332b5ff68e50'
- '05ec4d3323dc80ef6c1d4d6d50d339accd51d22b12a735b7a6605f10feb09cec'
+ '740dc9838aa47daa9f9b107178e53e384344f4c6f90865bd7e3af189257da544'
'1499e419dda72b1604dc5e3959668f3843292ff56bfba78734e31510ba576de0'
- '34e78efe063abc10707e47b4a3ba9d22955bfaf26d5670abb963d8f11f6b22b1'
+ 'ab62715392cb1aee475a95bbe4d4205552fe23e5dd50b85ca7be72a8fcd9fbfe'
'04a7176400907fd7db0d69116b99de49e582a6e176b3bfb36a03e50a4cb26a36')
prepare() {
@@ -64,7 +62,7 @@ prepare() {
patch -d ffmpeg -Np1 -i "${srcdir}/010-ffmpeg-fix-vmaf-model-path.patch"
patch -d ffmpeg -Np1 -i "${srcdir}/020-ffmpeg-add-svt-hevc-g${_svt_hevc_ver:0:7}.patch"
patch -d ffmpeg -Np1 -i "${srcdir}/030-ffmpeg-add-svt-hevc-docs-g${_svt_hevc_ver:0:7}.patch"
- patch -d ffmpeg -Np1 -i "${srcdir}/040-ffmpeg-add-svt-vp9-g${_svt_vp9_ver:0:7}.patch"
+ patch -d ffmpeg -Np1 -i "${srcdir}/040-ffmpeg-add-svt-vp9.patch"
}
pkgver() {