diff options
author | Nathaniel Chin | 2021-04-23 22:15:14 +0800 |
---|---|---|
committer | Nathaniel Chin | 2021-04-23 22:15:14 +0800 |
commit | f063eca92c5f257ca81b9a1b827233c5852b131e (patch) | |
tree | 81de381916793fd65fa8bf1c825a24f898ec6c58 | |
parent | 1ce174ba235991855b3dcee1d6f2c84cdc345780 (diff) | |
download | aur-f063eca92c5f257ca81b9a1b827233c5852b131e.tar.gz |
Fix svt-vp9 patch
-rw-r--r-- | .SRCINFO | 12 | ||||
-rw-r--r-- | 040-ffmpeg-add-svt-vp9.patch | 919 | ||||
-rw-r--r-- | PKGBUILD | 14 |
3 files changed, 931 insertions, 14 deletions
@@ -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); @@ -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() { |