From 79a2bb9e6b5d13013c1670ddf40cf8a4b7996620 Mon Sep 17 00:00:00 2001 From: Caio Vidal Date: Sat, 26 Feb 2022 15:22:24 -0300 Subject: [PATCH 1/9] add qsv encoder --- sunshine/video.cpp | 59 ++++++++++++++++++++++++++++++++++++++++++---- sunshine/video.h | 23 ++++++++++++++++++ 2 files changed, 78 insertions(+), 4 deletions(-) diff --git a/sunshine/video.cpp b/sunshine/video.cpp index 1a3d51e94dd..52f2cff725c 100644 --- a/sunshine/video.cpp +++ b/sunshine/video.cpp @@ -72,6 +72,7 @@ platf::pix_fmt_e map_pix_fmt(AVPixelFormat fmt); util::Either dxgi_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ctx); util::Either vaapi_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ctx); util::Either cuda_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ctx); +util::Either qsv_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ctx); int hwframe_ctx(ctx_t &ctx, buffer_t &hwdevice, AVPixelFormat format); @@ -474,6 +475,32 @@ static encoder_t amdvce { DEFAULT, dxgi_make_hwdevice_ctx }; + + +static encoder_t quicksync { + "quicksync"sv, + { FF_PROFILE_H264_HIGH, FF_PROFILE_HEVC_MAIN }, + AV_HWDEVICE_TYPE_QSV, + AV_PIX_FMT_QSV, + AV_PIX_FMT_NV12, AV_PIX_FMT_P010, + { + { + { "forced-idr"s, 1 }, + { "preset"s, &config::video.sw.preset }, + }, + std::make_optional({ "qp"s, &config::video.qp }), + "hevc_qsv"s, + }, + { + { + { "preset"s, 7 }, + }, + std::make_optional({ "qp"s, &config::video.qp }), + "h264_qsv"s, + }, + H264_ONLY, + qsv_make_hwdevice_ctx +}; #endif static encoder_t software { @@ -542,6 +569,7 @@ static std::vector encoders { nvenc, #ifdef _WIN32 amdvce, + quicksync, #endif #ifdef __linux__ vaapi, @@ -735,7 +763,9 @@ int encode(int64_t frame_nr, session_t &session, frame_t::pointer frame, safe::m } while(ret >= 0) { - auto packet = std::make_unique(nullptr); + auto packet = std::make_unique(nullptr); + auto av_packet = packet.get(); + av_packet->alloc(); ret = avcodec_receive_packet(ctx.get(), packet.get()); if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { @@ -1280,7 +1310,7 @@ void captureThreadSync() { ctx.shutdown_event->raise(true); ctx.join_event->raise(true); } - }); + }); while(encode_run_sync(synced_session_ctxs, ctx) == encode_e::reinit) {} } @@ -1296,7 +1326,7 @@ void capture_async( auto lg = util::fail_guard([&]() { images->stop(); shutdown_event->raise(true); - }); + }); auto ref = capture_thread_async.ref(); if(!ref) { @@ -1656,7 +1686,7 @@ int hwframe_ctx(ctx_t &ctx, buffer_t &hwdevice, AVPixelFormat format) { frame_ctx->sw_format = format; frame_ctx->height = ctx->height; frame_ctx->width = ctx->width; - frame_ctx->initial_pool_size = 0; + frame_ctx->initial_pool_size = 20; if(auto err = av_hwframe_ctx_init(frame_ref.get()); err < 0) { return err; @@ -1738,6 +1768,25 @@ util::Either dxgi_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_c return ctx_buf; } + +util::Either qsv_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ctx) { + + AVBufferRef *hw_device_ctx = NULL; + + auto err = av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_QSV, NULL, NULL, 0); + + if(err) { + char err_str[AV_ERROR_MAX_STRING_SIZE] { 0 }; + BOOST_LOG(error) << "Failed to create FFMpeg hardware device context: "sv << av_make_error_string(err_str, AV_ERROR_MAX_STRING_SIZE, err); + + return err; + } + + buffer_t ctx_buf { hw_device_ctx }; + + return ctx_buf; +} + #endif int start_capture_async(capture_thread_async_ctx_t &capture_thread_ctx) { @@ -1774,6 +1823,8 @@ platf::mem_type_e map_dev_type(AVHWDeviceType type) { return platf::mem_type_e::dxgi; case AV_HWDEVICE_TYPE_VAAPI: return platf::mem_type_e::vaapi; + case AV_HWDEVICE_TYPE_QSV: + return platf::mem_type_e::system; case AV_HWDEVICE_TYPE_CUDA: return platf::mem_type_e::cuda; case AV_HWDEVICE_TYPE_NONE: diff --git a/sunshine/video.h b/sunshine/video.h index fab4ff76837..1002b31ee91 100644 --- a/sunshine/video.h +++ b/sunshine/video.h @@ -29,6 +29,29 @@ struct packet_raw_t : public AVPacket { side_data_elems = 0; } + void alloc() { + AVPacket *enc_pkt; + + if(!(enc_pkt = av_packet_alloc())) { + return; + } + + pts = enc_pkt->pts; + dts = enc_pkt->dts; + pos = enc_pkt->pos; + duration = enc_pkt->duration; + flags = enc_pkt->flags; + stream_index = enc_pkt->stream_index; + buf = enc_pkt->buf; + side_data = enc_pkt->side_data; + side_data_elems = enc_pkt->side_data_elems; + data = enc_pkt->data; + opaque = enc_pkt->opaque; + opaque_ref = enc_pkt->opaque_ref; + size = enc_pkt->size; + time_base = enc_pkt->time_base; + } + template explicit packet_raw_t(P *user_data) : channel_data { user_data } { init_packet(); From b43ae668fb5f9017759df005d80ecf5d3b2ef5f5 Mon Sep 17 00:00:00 2001 From: Caio Vidal Date: Sun, 27 Feb 2022 19:15:34 -0300 Subject: [PATCH 2/9] cmakelists prebuilt change --- CMakeLists.txt | 3 +- third-party/cbs/cbs.c | 2100 ++++++++++++++++++++--------------------- 2 files changed, 1052 insertions(+), 1051 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2bdc2f08177..3752c1ccf98 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,7 +32,7 @@ if(WIN32) enable_language(RC) set(CMAKE_RC_COMPILER windres) file( - DOWNLOAD "https://github.com/TheElixZammuto/sunshine-prebuilt/releases/download/1.0.0/pre-compiled.zip" "${CMAKE_CURRENT_BINARY_DIR}/pre-compiled.zip" + DOWNLOAD "https://github.com/caioavidal/sunshine-prebuilt/releases/download/1.0.0/pre-compiled.zip" "${CMAKE_CURRENT_BINARY_DIR}/pre-compiled.zip" TIMEOUT 60 EXPECTED_HASH SHA256=5d59986bd7f619eaaf82b2dd56b5127b747c9cbe8db61e3b898ff6b485298ed6) @@ -91,6 +91,7 @@ if(WIN32) ${SUNSHINE_PREPARED_BINARIES}/lib/libx264.a ${SUNSHINE_PREPARED_BINARIES}/lib/libx265.a ${SUNSHINE_PREPARED_BINARIES}/lib/libhdr10plus.a + ${SUNSHINE_PREPARED_BINARIES}/lib/libmfx.a z lzma bcrypt libiconv.a) list(PREPEND PLATFORM_LIBRARIES diff --git a/third-party/cbs/cbs.c b/third-party/cbs/cbs.c index 456cac20b03..19cb8a2e69c 100644 --- a/third-party/cbs/cbs.c +++ b/third-party/cbs/cbs.c @@ -1,1050 +1,1050 @@ -/* - * 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 - */ - -#include - -#include -#include -#include -#include - -#include - -#include "cbs/cbs.h" -#include "cbs_internal.h" - -#include "get_bits.h" - - -static const CodedBitstreamType *const cbs_type_table[] = { -#if CONFIG_CBS_AV1 - &ff_cbs_type_av1, -#endif -#if CONFIG_CBS_H264 - &ff_cbs_type_h264, -#endif -#if CONFIG_CBS_H265 - &ff_cbs_type_h265, -#endif -#if CONFIG_CBS_JPEG - &ff_cbs_type_jpeg, -#endif -#if CONFIG_CBS_MPEG2 - &ff_cbs_type_mpeg2, -#endif -#if CONFIG_CBS_VP9 - &ff_cbs_type_vp9, -#endif -}; - -const enum AVCodecID ff_cbs_all_codec_ids[] = { -#if CONFIG_CBS_AV1 - AV_CODEC_ID_AV1, -#endif -#if CONFIG_CBS_H264 - AV_CODEC_ID_H264, -#endif -#if CONFIG_CBS_H265 - AV_CODEC_ID_H265, -#endif -#if CONFIG_CBS_JPEG - AV_CODEC_ID_MJPEG, -#endif -#if CONFIG_CBS_MPEG2 - AV_CODEC_ID_MPEG2VIDEO, -#endif -#if CONFIG_CBS_VP9 - AV_CODEC_ID_VP9, -#endif - AV_CODEC_ID_NONE -}; - -int ff_cbs_init(CodedBitstreamContext **ctx_ptr, - enum AVCodecID codec_id, void *log_ctx) { - CodedBitstreamContext *ctx; - const CodedBitstreamType *type; - int i; - - type = NULL; - for(i = 0; i < FF_ARRAY_ELEMS(cbs_type_table); i++) { - if(cbs_type_table[i]->codec_id == codec_id) { - type = cbs_type_table[i]; - break; - } - } - if(!type) - return AVERROR(EINVAL); - - ctx = av_mallocz(sizeof(*ctx)); - if(!ctx) - return AVERROR(ENOMEM); - - ctx->log_ctx = log_ctx; - ctx->codec = type; /* Must be before any error */ - - if(type->priv_data_size) { - ctx->priv_data = av_mallocz(ctx->codec->priv_data_size); - if(!ctx->priv_data) { - av_freep(&ctx); - return AVERROR(ENOMEM); - } - if(type->priv_class) { - *(const AVClass **)ctx->priv_data = type->priv_class; - av_opt_set_defaults(ctx->priv_data); - } - } - - ctx->decompose_unit_types = NULL; - - ctx->trace_enable = 0; - ctx->trace_level = AV_LOG_TRACE; - - *ctx_ptr = ctx; - return 0; -} - -void ff_cbs_flush(CodedBitstreamContext *ctx) { - if(ctx->codec->flush) - ctx->codec->flush(ctx); -} - -void ff_cbs_close(CodedBitstreamContext **ctx_ptr) { - CodedBitstreamContext *ctx = *ctx_ptr; - - if(!ctx) - return; - - if(ctx->codec->close) - ctx->codec->close(ctx); - - av_freep(&ctx->write_buffer); - - if(ctx->codec->priv_class && ctx->priv_data) - av_opt_free(ctx->priv_data); - - av_freep(&ctx->priv_data); - av_freep(ctx_ptr); -} - -static void cbs_unit_uninit(CodedBitstreamUnit *unit) { - av_buffer_unref(&unit->content_ref); - unit->content = NULL; - - av_buffer_unref(&unit->data_ref); - unit->data = NULL; - unit->data_size = 0; - unit->data_bit_padding = 0; -} - -void ff_cbs_fragment_reset(CodedBitstreamFragment *frag) { - int i; - - for(i = 0; i < frag->nb_units; i++) - cbs_unit_uninit(&frag->units[i]); - frag->nb_units = 0; - - av_buffer_unref(&frag->data_ref); - frag->data = NULL; - frag->data_size = 0; - frag->data_bit_padding = 0; -} - -void ff_cbs_fragment_free(CodedBitstreamFragment *frag) { - ff_cbs_fragment_reset(frag); - - av_freep(&frag->units); - frag->nb_units_allocated = 0; -} - -static int cbs_read_fragment_content(CodedBitstreamContext *ctx, - CodedBitstreamFragment *frag) { - int err, i, j; - - for(i = 0; i < frag->nb_units; i++) { - CodedBitstreamUnit *unit = &frag->units[i]; - - if(ctx->decompose_unit_types) { - for(j = 0; j < ctx->nb_decompose_unit_types; j++) { - if(ctx->decompose_unit_types[j] == unit->type) - break; - } - if(j >= ctx->nb_decompose_unit_types) - continue; - } - - av_buffer_unref(&unit->content_ref); - unit->content = NULL; - - av_assert0(unit->data && unit->data_ref); - - err = ctx->codec->read_unit(ctx, unit); - if(err == AVERROR(ENOSYS)) { - av_log(ctx->log_ctx, AV_LOG_VERBOSE, - "Decomposition unimplemented for unit %d " - "(type %" PRIu32 ").\n", - i, unit->type); - } - else if(err == AVERROR(EAGAIN)) { - av_log(ctx->log_ctx, AV_LOG_VERBOSE, - "Skipping decomposition of unit %d " - "(type %" PRIu32 ").\n", - i, unit->type); - av_buffer_unref(&unit->content_ref); - unit->content = NULL; - } - else if(err < 0) { - av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to read unit %d " - "(type %" PRIu32 ").\n", - i, unit->type); - return err; - } - } - - return 0; -} - -static int cbs_fill_fragment_data(CodedBitstreamFragment *frag, - const uint8_t *data, size_t size) { - av_assert0(!frag->data && !frag->data_ref); - - frag->data_ref = - av_buffer_alloc(size + AV_INPUT_BUFFER_PADDING_SIZE); - if(!frag->data_ref) - return AVERROR(ENOMEM); - - frag->data = frag->data_ref->data; - frag->data_size = size; - - memcpy(frag->data, data, size); - memset(frag->data + size, 0, - AV_INPUT_BUFFER_PADDING_SIZE); - - return 0; -} - -static int cbs_read_data(CodedBitstreamContext *ctx, - CodedBitstreamFragment *frag, - AVBufferRef *buf, - const uint8_t *data, size_t size, - int header) { - int err; - - if(buf) { - frag->data_ref = av_buffer_ref(buf); - if(!frag->data_ref) - return AVERROR(ENOMEM); - - frag->data = (uint8_t *)data; - frag->data_size = size; - } - else { - err = cbs_fill_fragment_data(frag, data, size); - if(err < 0) - return err; - } - - err = ctx->codec->split_fragment(ctx, frag, header); - if(err < 0) - return err; - - return cbs_read_fragment_content(ctx, frag); -} - -int ff_cbs_read_extradata(CodedBitstreamContext *ctx, - CodedBitstreamFragment *frag, - const AVCodecParameters *par) { - return cbs_read_data(ctx, frag, NULL, - par->extradata, - par->extradata_size, 1); -} - -int ff_cbs_read_extradata_from_codec(CodedBitstreamContext *ctx, - CodedBitstreamFragment *frag, - const AVCodecContext *avctx) { - return cbs_read_data(ctx, frag, NULL, - avctx->extradata, - avctx->extradata_size, 1); -} - -int ff_cbs_read_packet(CodedBitstreamContext *ctx, - CodedBitstreamFragment *frag, - const AVPacket *pkt) { - return cbs_read_data(ctx, frag, pkt->buf, - pkt->data, pkt->size, 0); -} - -int ff_cbs_read(CodedBitstreamContext *ctx, - CodedBitstreamFragment *frag, - const uint8_t *data, size_t size) { - return cbs_read_data(ctx, frag, NULL, - data, size, 0); -} - -static int cbs_write_unit_data(CodedBitstreamContext *ctx, - CodedBitstreamUnit *unit) { - PutBitContext pbc; - int ret; - - if(!ctx->write_buffer) { - // Initial write buffer size is 1MB. - ctx->write_buffer_size = 1024 * 1024; - - reallocate_and_try_again: - ret = av_reallocp(&ctx->write_buffer, ctx->write_buffer_size); - if(ret < 0) { - av_log(ctx->log_ctx, AV_LOG_ERROR, "Unable to allocate a " - "sufficiently large write buffer (last attempt " - "%zu bytes).\n", - ctx->write_buffer_size); - return ret; - } - } - - init_put_bits(&pbc, ctx->write_buffer, ctx->write_buffer_size); - - ret = ctx->codec->write_unit(ctx, unit, &pbc); - if(ret < 0) { - if(ret == AVERROR(ENOSPC)) { - // Overflow. - if(ctx->write_buffer_size == INT_MAX / 8) - return AVERROR(ENOMEM); - ctx->write_buffer_size = FFMIN(2 * ctx->write_buffer_size, INT_MAX / 8); - goto reallocate_and_try_again; - } - // Write failed for some other reason. - return ret; - } - - // Overflow but we didn't notice. - av_assert0(put_bits_count(&pbc) <= 8 * ctx->write_buffer_size); - - if(put_bits_count(&pbc) % 8) - unit->data_bit_padding = 8 - put_bits_count(&pbc) % 8; - else - unit->data_bit_padding = 0; - - flush_put_bits(&pbc); - - ret = ff_cbs_alloc_unit_data(unit, put_bytes_output(&pbc)); - if(ret < 0) - return ret; - - memcpy(unit->data, ctx->write_buffer, unit->data_size); - - return 0; -} - -int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx, - CodedBitstreamFragment *frag) { - int err, i; - - for(i = 0; i < frag->nb_units; i++) { - CodedBitstreamUnit *unit = &frag->units[i]; - - if(!unit->content) - continue; - - av_buffer_unref(&unit->data_ref); - unit->data = NULL; - - err = cbs_write_unit_data(ctx, unit); - if(err < 0) { - av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to write unit %d " - "(type %" PRIu32 ").\n", - i, unit->type); - return err; - } - av_assert0(unit->data && unit->data_ref); - } - - av_buffer_unref(&frag->data_ref); - frag->data = NULL; - - err = ctx->codec->assemble_fragment(ctx, frag); - if(err < 0) { - av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to assemble fragment.\n"); - return err; - } - av_assert0(frag->data && frag->data_ref); - - return 0; -} - -int ff_cbs_write_extradata(CodedBitstreamContext *ctx, - AVCodecParameters *par, - CodedBitstreamFragment *frag) { - int err; - - err = ff_cbs_write_fragment_data(ctx, frag); - if(err < 0) - return err; - - av_freep(&par->extradata); - - par->extradata = av_malloc(frag->data_size + - AV_INPUT_BUFFER_PADDING_SIZE); - if(!par->extradata) - return AVERROR(ENOMEM); - - memcpy(par->extradata, frag->data, frag->data_size); - memset(par->extradata + frag->data_size, 0, - AV_INPUT_BUFFER_PADDING_SIZE); - par->extradata_size = frag->data_size; - - return 0; -} - -int ff_cbs_write_packet(CodedBitstreamContext *ctx, - AVPacket *pkt, - CodedBitstreamFragment *frag) { - AVBufferRef *buf; - int err; - - err = ff_cbs_write_fragment_data(ctx, frag); - if(err < 0) - return err; - - buf = av_buffer_ref(frag->data_ref); - if(!buf) - return AVERROR(ENOMEM); - - av_buffer_unref(&pkt->buf); - - pkt->buf = buf; - pkt->data = frag->data; - pkt->size = frag->data_size; - - return 0; -} - - -void ff_cbs_trace_header(CodedBitstreamContext *ctx, - const char *name) { - if(!ctx->trace_enable) - return; - - av_log(ctx->log_ctx, ctx->trace_level, "%s\n", name); -} - -void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, int position, - const char *str, const int *subscripts, - const char *bits, int64_t value) { - char name[256]; - size_t name_len, bits_len; - int pad, subs, i, j, k, n; - - if(!ctx->trace_enable) - return; - - av_assert0(value >= INT_MIN && value <= UINT32_MAX); - - subs = subscripts ? subscripts[0] : 0; - n = 0; - for(i = j = 0; str[i];) { - if(str[i] == '[') { - if(n < subs) { - ++n; - k = snprintf(name + j, sizeof(name) - j, "[%d", subscripts[n]); - av_assert0(k > 0 && j + k < sizeof(name)); - j += k; - for(++i; str[i] && str[i] != ']'; i++) - ; - av_assert0(str[i] == ']'); - } - else { - while(str[i] && str[i] != ']') - name[j++] = str[i++]; - av_assert0(str[i] == ']'); - } - } - else { - av_assert0(j + 1 < sizeof(name)); - name[j++] = str[i++]; - } - } - av_assert0(j + 1 < sizeof(name)); - name[j] = 0; - av_assert0(n == subs); - - name_len = strlen(name); - bits_len = strlen(bits); - - if(name_len + bits_len > 60) - pad = bits_len + 2; - else - pad = 61 - name_len; - - av_log(ctx->log_ctx, ctx->trace_level, "%-10d %s%*s = %" PRId64 "\n", - position, name, pad, bits, value); -} - -int ff_cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc, - int width, const char *name, - const int *subscripts, uint32_t *write_to, - uint32_t range_min, uint32_t range_max) { - uint32_t value; - int position; - - av_assert0(width > 0 && width <= 32); - - if(get_bits_left(gbc) < width) { - av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid value at " - "%s: bitstream ended.\n", - name); - return AVERROR_INVALIDDATA; - } - - if(ctx->trace_enable) - position = get_bits_count(gbc); - - value = get_bits_long(gbc, width); - - if(ctx->trace_enable) { - char bits[33]; - int i; - for(i = 0; i < width; i++) - bits[i] = value >> (width - i - 1) & 1 ? '1' : '0'; - bits[i] = 0; - - ff_cbs_trace_syntax_element(ctx, position, name, subscripts, - bits, value); - } - - if(value < range_min || value > range_max) { - av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " - "%" PRIu32 ", but must be in [%" PRIu32 ",%" PRIu32 "].\n", - name, value, range_min, range_max); - return AVERROR_INVALIDDATA; - } - - *write_to = value; - return 0; -} - -int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc, - int width, const char *name, - const int *subscripts, uint32_t value, - uint32_t range_min, uint32_t range_max) { - av_assert0(width > 0 && width <= 32); - - if(value < range_min || value > range_max) { - av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " - "%" PRIu32 ", but must be in [%" PRIu32 ",%" PRIu32 "].\n", - name, value, range_min, range_max); - return AVERROR_INVALIDDATA; - } - - if(put_bits_left(pbc) < width) - return AVERROR(ENOSPC); - - if(ctx->trace_enable) { - char bits[33]; - int i; - for(i = 0; i < width; i++) - bits[i] = value >> (width - i - 1) & 1 ? '1' : '0'; - bits[i] = 0; - - ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), - name, subscripts, bits, value); - } - - if(width < 32) - put_bits(pbc, width, value); - else - put_bits32(pbc, value); - - return 0; -} - -int ff_cbs_read_signed(CodedBitstreamContext *ctx, GetBitContext *gbc, - int width, const char *name, - const int *subscripts, int32_t *write_to, - int32_t range_min, int32_t range_max) { - int32_t value; - int position; - - av_assert0(width > 0 && width <= 32); - - if(get_bits_left(gbc) < width) { - av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid value at " - "%s: bitstream ended.\n", - name); - return AVERROR_INVALIDDATA; - } - - if(ctx->trace_enable) - position = get_bits_count(gbc); - - value = get_sbits_long(gbc, width); - - if(ctx->trace_enable) { - char bits[33]; - int i; - for(i = 0; i < width; i++) - bits[i] = value & (1U << (width - i - 1)) ? '1' : '0'; - bits[i] = 0; - - ff_cbs_trace_syntax_element(ctx, position, name, subscripts, - bits, value); - } - - if(value < range_min || value > range_max) { - av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " - "%" PRId32 ", but must be in [%" PRId32 ",%" PRId32 "].\n", - name, value, range_min, range_max); - return AVERROR_INVALIDDATA; - } - - *write_to = value; - return 0; -} - -int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc, - int width, const char *name, - const int *subscripts, int32_t value, - int32_t range_min, int32_t range_max) { - av_assert0(width > 0 && width <= 32); - - if(value < range_min || value > range_max) { - av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " - "%" PRId32 ", but must be in [%" PRId32 ",%" PRId32 "].\n", - name, value, range_min, range_max); - return AVERROR_INVALIDDATA; - } - - if(put_bits_left(pbc) < width) - return AVERROR(ENOSPC); - - if(ctx->trace_enable) { - char bits[33]; - int i; - for(i = 0; i < width; i++) - bits[i] = value & (1U << (width - i - 1)) ? '1' : '0'; - bits[i] = 0; - - ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), - name, subscripts, bits, value); - } - - if(width < 32) - put_sbits(pbc, width, value); - else - put_bits32(pbc, value); - - return 0; -} - - -int ff_cbs_alloc_unit_content(CodedBitstreamUnit *unit, - size_t size, - void (*free)(void *opaque, uint8_t *data)) { - av_assert0(!unit->content && !unit->content_ref); - - unit->content = av_mallocz(size); - if(!unit->content) - return AVERROR(ENOMEM); - - unit->content_ref = av_buffer_create(unit->content, size, - free, NULL, 0); - if(!unit->content_ref) { - av_freep(&unit->content); - return AVERROR(ENOMEM); - } - - return 0; -} - -int ff_cbs_alloc_unit_data(CodedBitstreamUnit *unit, - size_t size) { - av_assert0(!unit->data && !unit->data_ref); - - unit->data_ref = av_buffer_alloc(size + AV_INPUT_BUFFER_PADDING_SIZE); - if(!unit->data_ref) - return AVERROR(ENOMEM); - - unit->data = unit->data_ref->data; - unit->data_size = size; - - memset(unit->data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); - - return 0; -} - -static int cbs_insert_unit(CodedBitstreamFragment *frag, - int position) { - CodedBitstreamUnit *units; - - if(frag->nb_units < frag->nb_units_allocated) { - units = frag->units; - - if(position < frag->nb_units) - memmove(units + position + 1, units + position, - (frag->nb_units - position) * sizeof(*units)); - } - else { - units = av_malloc_array(frag->nb_units * 2 + 1, sizeof(*units)); - if(!units) - return AVERROR(ENOMEM); - - frag->nb_units_allocated = 2 * frag->nb_units_allocated + 1; - - if(position > 0) - memcpy(units, frag->units, position * sizeof(*units)); - - if(position < frag->nb_units) - memcpy(units + position + 1, frag->units + position, - (frag->nb_units - position) * sizeof(*units)); - } - - memset(units + position, 0, sizeof(*units)); - - if(units != frag->units) { - av_free(frag->units); - frag->units = units; - } - - ++frag->nb_units; - - return 0; -} - -int ff_cbs_insert_unit_content(CodedBitstreamFragment *frag, - int position, - CodedBitstreamUnitType type, - void *content, - AVBufferRef *content_buf) { - CodedBitstreamUnit *unit; - AVBufferRef *content_ref; - int err; - - if(position == -1) - position = frag->nb_units; - av_assert0(position >= 0 && position <= frag->nb_units); - - if(content_buf) { - content_ref = av_buffer_ref(content_buf); - if(!content_ref) - return AVERROR(ENOMEM); - } - else { - content_ref = NULL; - } - - err = cbs_insert_unit(frag, position); - if(err < 0) { - av_buffer_unref(&content_ref); - return err; - } - - unit = &frag->units[position]; - unit->type = type; - unit->content = content; - unit->content_ref = content_ref; - - return 0; -} - -int ff_cbs_insert_unit_data(CodedBitstreamFragment *frag, - int position, - CodedBitstreamUnitType type, - uint8_t *data, size_t data_size, - AVBufferRef *data_buf) { - CodedBitstreamUnit *unit; - AVBufferRef *data_ref; - int err; - - if(position == -1) - position = frag->nb_units; - av_assert0(position >= 0 && position <= frag->nb_units); - - if(data_buf) - data_ref = av_buffer_ref(data_buf); - else - data_ref = av_buffer_create(data, data_size, NULL, NULL, 0); - if(!data_ref) { - if(!data_buf) - av_free(data); - return AVERROR(ENOMEM); - } - - err = cbs_insert_unit(frag, position); - if(err < 0) { - av_buffer_unref(&data_ref); - return err; - } - - unit = &frag->units[position]; - unit->type = type; - unit->data = data; - unit->data_size = data_size; - unit->data_ref = data_ref; - - return 0; -} - -void ff_cbs_delete_unit(CodedBitstreamFragment *frag, - int position) { - av_assert0(0 <= position && position < frag->nb_units && "Unit to be deleted not in fragment."); - - cbs_unit_uninit(&frag->units[position]); - - --frag->nb_units; - - if(frag->nb_units > 0) - memmove(frag->units + position, - frag->units + position + 1, - (frag->nb_units - position) * sizeof(*frag->units)); -} - -static void cbs_default_free_unit_content(void *opaque, uint8_t *data) { - const CodedBitstreamUnitTypeDescriptor *desc = opaque; - if(desc->content_type == CBS_CONTENT_TYPE_INTERNAL_REFS) { - int i; - for(i = 0; i < desc->nb_ref_offsets; i++) { - void **ptr = (void **)(data + desc->ref_offsets[i]); - av_buffer_unref((AVBufferRef **)(ptr + 1)); - } - } - av_free(data); -} - -static const CodedBitstreamUnitTypeDescriptor - * - cbs_find_unit_type_desc(CodedBitstreamContext *ctx, - CodedBitstreamUnit *unit) { - const CodedBitstreamUnitTypeDescriptor *desc; - int i, j; - - if(!ctx->codec->unit_types) - return NULL; - - for(i = 0;; i++) { - desc = &ctx->codec->unit_types[i]; - if(desc->nb_unit_types == 0) - break; - if(desc->nb_unit_types == CBS_UNIT_TYPE_RANGE) { - if(unit->type >= desc->unit_type_range_start && - unit->type <= desc->unit_type_range_end) - return desc; - } - else { - for(j = 0; j < desc->nb_unit_types; j++) { - if(desc->unit_types[j] == unit->type) - return desc; - } - } - } - return NULL; -} - -int ff_cbs_alloc_unit_content2(CodedBitstreamContext *ctx, - CodedBitstreamUnit *unit) { - const CodedBitstreamUnitTypeDescriptor *desc; - - av_assert0(!unit->content && !unit->content_ref); - - desc = cbs_find_unit_type_desc(ctx, unit); - if(!desc) - return AVERROR(ENOSYS); - - unit->content = av_mallocz(desc->content_size); - if(!unit->content) - return AVERROR(ENOMEM); - - unit->content_ref = - av_buffer_create(unit->content, desc->content_size, - desc->content_free ? desc->content_free : cbs_default_free_unit_content, - (void *)desc, 0); - if(!unit->content_ref) { - av_freep(&unit->content); - return AVERROR(ENOMEM); - } - - return 0; -} - -static int cbs_clone_unit_content(AVBufferRef **clone_ref, - CodedBitstreamUnit *unit, - const CodedBitstreamUnitTypeDescriptor *desc) { - uint8_t *src, *copy; - uint8_t **src_ptr, **copy_ptr; - AVBufferRef **src_buf, **copy_buf; - int err, i; - - av_assert0(unit->content); - src = unit->content; - - copy = av_memdup(src, desc->content_size); - if(!copy) - return AVERROR(ENOMEM); - - for(i = 0; i < desc->nb_ref_offsets; i++) { - src_ptr = (uint8_t **)(src + desc->ref_offsets[i]); - src_buf = (AVBufferRef **)(src_ptr + 1); - copy_ptr = (uint8_t **)(copy + desc->ref_offsets[i]); - copy_buf = (AVBufferRef **)(copy_ptr + 1); - - if(!*src_ptr) { - av_assert0(!*src_buf); - continue; - } - if(!*src_buf) { - // We can't handle a non-refcounted pointer here - we don't - // have enough information to handle whatever structure lies - // at the other end of it. - err = AVERROR(EINVAL); - goto fail; - } - - // src_ptr is required to point somewhere inside src_buf. If it - // doesn't, there is a bug somewhere. - av_assert0(*src_ptr >= (*src_buf)->data && - *src_ptr < (*src_buf)->data + (*src_buf)->size); - - *copy_buf = av_buffer_ref(*src_buf); - if(!*copy_buf) { - err = AVERROR(ENOMEM); - goto fail; - } - *copy_ptr = (*copy_buf)->data + (*src_ptr - (*src_buf)->data); - } - - *clone_ref = av_buffer_create(copy, desc->content_size, - desc->content_free ? desc->content_free : - cbs_default_free_unit_content, - (void *)desc, 0); - if(!*clone_ref) { - err = AVERROR(ENOMEM); - goto fail; - } - - return 0; - -fail: - for(--i; i >= 0; i--) - av_buffer_unref((AVBufferRef **)(copy + desc->ref_offsets[i])); - av_freep(©); - *clone_ref = NULL; - return err; -} - -int ff_cbs_make_unit_refcounted(CodedBitstreamContext *ctx, - CodedBitstreamUnit *unit) { - const CodedBitstreamUnitTypeDescriptor *desc; - AVBufferRef *ref; - int err; - - av_assert0(unit->content); - if(unit->content_ref) { - // Already refcounted, nothing to do. - return 0; - } - - desc = cbs_find_unit_type_desc(ctx, unit); - if(!desc) - return AVERROR(ENOSYS); - - switch(desc->content_type) { - case CBS_CONTENT_TYPE_POD: - ref = av_buffer_alloc(desc->content_size); - if(!ref) - return AVERROR(ENOMEM); - memcpy(ref->data, unit->content, desc->content_size); - err = 0; - break; - - case CBS_CONTENT_TYPE_INTERNAL_REFS: - err = cbs_clone_unit_content(&ref, unit, desc); - break; - - case CBS_CONTENT_TYPE_COMPLEX: - if(!desc->content_clone) - return AVERROR_PATCHWELCOME; - err = desc->content_clone(&ref, unit); - break; - - default: - av_assert0(0 && "Invalid content type."); - } - - if(err < 0) - return err; - - unit->content_ref = ref; - unit->content = ref->data; - return 0; -} - -int ff_cbs_make_unit_writable(CodedBitstreamContext *ctx, - CodedBitstreamUnit *unit) { - const CodedBitstreamUnitTypeDescriptor *desc; - AVBufferRef *ref; - int err; - - // This can only be applied to refcounted units. - err = ff_cbs_make_unit_refcounted(ctx, unit); - if(err < 0) - return err; - av_assert0(unit->content && unit->content_ref); - - if(av_buffer_is_writable(unit->content_ref)) - return 0; - - desc = cbs_find_unit_type_desc(ctx, unit); - if(!desc) - return AVERROR(ENOSYS); - - switch(desc->content_type) { - case CBS_CONTENT_TYPE_POD: - err = av_buffer_make_writable(&unit->content_ref); - break; - - case CBS_CONTENT_TYPE_INTERNAL_REFS: - err = cbs_clone_unit_content(&ref, unit, desc); - break; - - case CBS_CONTENT_TYPE_COMPLEX: - if(!desc->content_clone) - return AVERROR_PATCHWELCOME; - err = desc->content_clone(&ref, unit); - break; - - default: - av_assert0(0 && "Invalid content type."); - } - if(err < 0) - return err; - - if(desc->content_type != CBS_CONTENT_TYPE_POD) { - av_buffer_unref(&unit->content_ref); - unit->content_ref = ref; - } - unit->content = unit->content_ref->data; - return 0; -} - -const uint8_t ff_log2_tab[256] = { - 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 -}; \ No newline at end of file +// /* +// * 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 +// */ + +// #include + +// #include +// #include +// #include +// #include + +// #include + +// #include "cbs/cbs.h" +// #include "cbs_internal.h" + +// #include "get_bits.h" + + +// static const CodedBitstreamType *const cbs_type_table[] = { +// #if CONFIG_CBS_AV1 +// &ff_cbs_type_av1, +// #endif +// #if CONFIG_CBS_H264 +// &ff_cbs_type_h264, +// #endif +// #if CONFIG_CBS_H265 +// &ff_cbs_type_h265, +// #endif +// #if CONFIG_CBS_JPEG +// &ff_cbs_type_jpeg, +// #endif +// #if CONFIG_CBS_MPEG2 +// &ff_cbs_type_mpeg2, +// #endif +// #if CONFIG_CBS_VP9 +// &ff_cbs_type_vp9, +// #endif +// }; + +// const enum AVCodecID ff_cbs_all_codec_ids[] = { +// #if CONFIG_CBS_AV1 +// AV_CODEC_ID_AV1, +// #endif +// #if CONFIG_CBS_H264 +// AV_CODEC_ID_H264, +// #endif +// #if CONFIG_CBS_H265 +// AV_CODEC_ID_H265, +// #endif +// #if CONFIG_CBS_JPEG +// AV_CODEC_ID_MJPEG, +// #endif +// #if CONFIG_CBS_MPEG2 +// AV_CODEC_ID_MPEG2VIDEO, +// #endif +// #if CONFIG_CBS_VP9 +// AV_CODEC_ID_VP9, +// #endif +// AV_CODEC_ID_NONE +// }; + +// int ff_cbs_init(CodedBitstreamContext **ctx_ptr, +// enum AVCodecID codec_id, void *log_ctx) { +// CodedBitstreamContext *ctx; +// const CodedBitstreamType *type; +// int i; + +// type = NULL; +// for(i = 0; i < FF_ARRAY_ELEMS(cbs_type_table); i++) { +// if(cbs_type_table[i]->codec_id == codec_id) { +// type = cbs_type_table[i]; +// break; +// } +// } +// if(!type) +// return AVERROR(EINVAL); + +// ctx = av_mallocz(sizeof(*ctx)); +// if(!ctx) +// return AVERROR(ENOMEM); + +// ctx->log_ctx = log_ctx; +// ctx->codec = type; /* Must be before any error */ + +// if(type->priv_data_size) { +// ctx->priv_data = av_mallocz(ctx->codec->priv_data_size); +// if(!ctx->priv_data) { +// av_freep(&ctx); +// return AVERROR(ENOMEM); +// } +// if(type->priv_class) { +// *(const AVClass **)ctx->priv_data = type->priv_class; +// av_opt_set_defaults(ctx->priv_data); +// } +// } + +// ctx->decompose_unit_types = NULL; + +// ctx->trace_enable = 0; +// ctx->trace_level = AV_LOG_TRACE; + +// *ctx_ptr = ctx; +// return 0; +// } + +// void ff_cbs_flush(CodedBitstreamContext *ctx) { +// if(ctx->codec->flush) +// ctx->codec->flush(ctx); +// } + +// void ff_cbs_close(CodedBitstreamContext **ctx_ptr) { +// CodedBitstreamContext *ctx = *ctx_ptr; + +// if(!ctx) +// return; + +// if(ctx->codec->close) +// ctx->codec->close(ctx); + +// av_freep(&ctx->write_buffer); + +// if(ctx->codec->priv_class && ctx->priv_data) +// av_opt_free(ctx->priv_data); + +// av_freep(&ctx->priv_data); +// av_freep(ctx_ptr); +// } + +// static void cbs_unit_uninit(CodedBitstreamUnit *unit) { +// av_buffer_unref(&unit->content_ref); +// unit->content = NULL; + +// av_buffer_unref(&unit->data_ref); +// unit->data = NULL; +// unit->data_size = 0; +// unit->data_bit_padding = 0; +// } + +// void ff_cbs_fragment_reset(CodedBitstreamFragment *frag) { +// int i; + +// for(i = 0; i < frag->nb_units; i++) +// cbs_unit_uninit(&frag->units[i]); +// frag->nb_units = 0; + +// av_buffer_unref(&frag->data_ref); +// frag->data = NULL; +// frag->data_size = 0; +// frag->data_bit_padding = 0; +// } + +// void ff_cbs_fragment_free(CodedBitstreamFragment *frag) { +// ff_cbs_fragment_reset(frag); + +// av_freep(&frag->units); +// frag->nb_units_allocated = 0; +// } + +// static int cbs_read_fragment_content(CodedBitstreamContext *ctx, +// CodedBitstreamFragment *frag) { +// int err, i, j; + +// for(i = 0; i < frag->nb_units; i++) { +// CodedBitstreamUnit *unit = &frag->units[i]; + +// if(ctx->decompose_unit_types) { +// for(j = 0; j < ctx->nb_decompose_unit_types; j++) { +// if(ctx->decompose_unit_types[j] == unit->type) +// break; +// } +// if(j >= ctx->nb_decompose_unit_types) +// continue; +// } + +// av_buffer_unref(&unit->content_ref); +// unit->content = NULL; + +// av_assert0(unit->data && unit->data_ref); + +// err = ctx->codec->read_unit(ctx, unit); +// if(err == AVERROR(ENOSYS)) { +// av_log(ctx->log_ctx, AV_LOG_VERBOSE, +// "Decomposition unimplemented for unit %d " +// "(type %" PRIu32 ").\n", +// i, unit->type); +// } +// else if(err == AVERROR(EAGAIN)) { +// av_log(ctx->log_ctx, AV_LOG_VERBOSE, +// "Skipping decomposition of unit %d " +// "(type %" PRIu32 ").\n", +// i, unit->type); +// av_buffer_unref(&unit->content_ref); +// unit->content = NULL; +// } +// else if(err < 0) { +// av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to read unit %d " +// "(type %" PRIu32 ").\n", +// i, unit->type); +// return err; +// } +// } + +// return 0; +// } + +// static int cbs_fill_fragment_data(CodedBitstreamFragment *frag, +// const uint8_t *data, size_t size) { +// av_assert0(!frag->data && !frag->data_ref); + +// frag->data_ref = +// av_buffer_alloc(size + AV_INPUT_BUFFER_PADDING_SIZE); +// if(!frag->data_ref) +// return AVERROR(ENOMEM); + +// frag->data = frag->data_ref->data; +// frag->data_size = size; + +// memcpy(frag->data, data, size); +// memset(frag->data + size, 0, +// AV_INPUT_BUFFER_PADDING_SIZE); + +// return 0; +// } + +// static int cbs_read_data(CodedBitstreamContext *ctx, +// CodedBitstreamFragment *frag, +// AVBufferRef *buf, +// const uint8_t *data, size_t size, +// int header) { +// int err; + +// if(buf) { +// frag->data_ref = av_buffer_ref(buf); +// if(!frag->data_ref) +// return AVERROR(ENOMEM); + +// frag->data = (uint8_t *)data; +// frag->data_size = size; +// } +// else { +// err = cbs_fill_fragment_data(frag, data, size); +// if(err < 0) +// return err; +// } + +// err = ctx->codec->split_fragment(ctx, frag, header); +// if(err < 0) +// return err; + +// return cbs_read_fragment_content(ctx, frag); +// } + +// int ff_cbs_read_extradata(CodedBitstreamContext *ctx, +// CodedBitstreamFragment *frag, +// const AVCodecParameters *par) { +// return cbs_read_data(ctx, frag, NULL, +// par->extradata, +// par->extradata_size, 1); +// } + +// int ff_cbs_read_extradata_from_codec(CodedBitstreamContext *ctx, +// CodedBitstreamFragment *frag, +// const AVCodecContext *avctx) { +// return cbs_read_data(ctx, frag, NULL, +// avctx->extradata, +// avctx->extradata_size, 1); +// } + +// int ff_cbs_read_packet(CodedBitstreamContext *ctx, +// CodedBitstreamFragment *frag, +// const AVPacket *pkt) { +// return cbs_read_data(ctx, frag, pkt->buf, +// pkt->data, pkt->size, 0); +// } + +// int ff_cbs_read(CodedBitstreamContext *ctx, +// CodedBitstreamFragment *frag, +// const uint8_t *data, size_t size) { +// return cbs_read_data(ctx, frag, NULL, +// data, size, 0); +// } + +// static int cbs_write_unit_data(CodedBitstreamContext *ctx, +// CodedBitstreamUnit *unit) { +// PutBitContext pbc; +// int ret; + +// if(!ctx->write_buffer) { +// // Initial write buffer size is 1MB. +// ctx->write_buffer_size = 1024 * 1024; + +// reallocate_and_try_again: +// ret = av_reallocp(&ctx->write_buffer, ctx->write_buffer_size); +// if(ret < 0) { +// av_log(ctx->log_ctx, AV_LOG_ERROR, "Unable to allocate a " +// "sufficiently large write buffer (last attempt " +// "%zu bytes).\n", +// ctx->write_buffer_size); +// return ret; +// } +// } + +// init_put_bits(&pbc, ctx->write_buffer, ctx->write_buffer_size); + +// ret = ctx->codec->write_unit(ctx, unit, &pbc); +// if(ret < 0) { +// if(ret == AVERROR(ENOSPC)) { +// // Overflow. +// if(ctx->write_buffer_size == INT_MAX / 8) +// return AVERROR(ENOMEM); +// ctx->write_buffer_size = FFMIN(2 * ctx->write_buffer_size, INT_MAX / 8); +// goto reallocate_and_try_again; +// } +// // Write failed for some other reason. +// return ret; +// } + +// // Overflow but we didn't notice. +// av_assert0(put_bits_count(&pbc) <= 8 * ctx->write_buffer_size); + +// if(put_bits_count(&pbc) % 8) +// unit->data_bit_padding = 8 - put_bits_count(&pbc) % 8; +// else +// unit->data_bit_padding = 0; + +// flush_put_bits(&pbc); + +// ret = ff_cbs_alloc_unit_data(unit, put_bytes_output(&pbc)); +// if(ret < 0) +// return ret; + +// memcpy(unit->data, ctx->write_buffer, unit->data_size); + +// return 0; +// } + +// int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx, +// CodedBitstreamFragment *frag) { +// int err, i; + +// for(i = 0; i < frag->nb_units; i++) { +// CodedBitstreamUnit *unit = &frag->units[i]; + +// if(!unit->content) +// continue; + +// av_buffer_unref(&unit->data_ref); +// unit->data = NULL; + +// err = cbs_write_unit_data(ctx, unit); +// if(err < 0) { +// av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to write unit %d " +// "(type %" PRIu32 ").\n", +// i, unit->type); +// return err; +// } +// av_assert0(unit->data && unit->data_ref); +// } + +// av_buffer_unref(&frag->data_ref); +// frag->data = NULL; + +// err = ctx->codec->assemble_fragment(ctx, frag); +// if(err < 0) { +// av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to assemble fragment.\n"); +// return err; +// } +// av_assert0(frag->data && frag->data_ref); + +// return 0; +// } + +// int ff_cbs_write_extradata(CodedBitstreamContext *ctx, +// AVCodecParameters *par, +// CodedBitstreamFragment *frag) { +// int err; + +// err = ff_cbs_write_fragment_data(ctx, frag); +// if(err < 0) +// return err; + +// av_freep(&par->extradata); + +// par->extradata = av_malloc(frag->data_size + +// AV_INPUT_BUFFER_PADDING_SIZE); +// if(!par->extradata) +// return AVERROR(ENOMEM); + +// memcpy(par->extradata, frag->data, frag->data_size); +// memset(par->extradata + frag->data_size, 0, +// AV_INPUT_BUFFER_PADDING_SIZE); +// par->extradata_size = frag->data_size; + +// return 0; +// } + +// int ff_cbs_write_packet(CodedBitstreamContext *ctx, +// AVPacket *pkt, +// CodedBitstreamFragment *frag) { +// AVBufferRef *buf; +// int err; + +// err = ff_cbs_write_fragment_data(ctx, frag); +// if(err < 0) +// return err; + +// buf = av_buffer_ref(frag->data_ref); +// if(!buf) +// return AVERROR(ENOMEM); + +// av_buffer_unref(&pkt->buf); + +// pkt->buf = buf; +// pkt->data = frag->data; +// pkt->size = frag->data_size; + +// return 0; +// } + + +// void ff_cbs_trace_header(CodedBitstreamContext *ctx, +// const char *name) { +// if(!ctx->trace_enable) +// return; + +// av_log(ctx->log_ctx, ctx->trace_level, "%s\n", name); +// } + +// void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, int position, +// const char *str, const int *subscripts, +// const char *bits, int64_t value) { +// char name[256]; +// size_t name_len, bits_len; +// int pad, subs, i, j, k, n; + +// if(!ctx->trace_enable) +// return; + +// av_assert0(value >= INT_MIN && value <= UINT32_MAX); + +// subs = subscripts ? subscripts[0] : 0; +// n = 0; +// for(i = j = 0; str[i];) { +// if(str[i] == '[') { +// if(n < subs) { +// ++n; +// k = snprintf(name + j, sizeof(name) - j, "[%d", subscripts[n]); +// av_assert0(k > 0 && j + k < sizeof(name)); +// j += k; +// for(++i; str[i] && str[i] != ']'; i++) +// ; +// av_assert0(str[i] == ']'); +// } +// else { +// while(str[i] && str[i] != ']') +// name[j++] = str[i++]; +// av_assert0(str[i] == ']'); +// } +// } +// else { +// av_assert0(j + 1 < sizeof(name)); +// name[j++] = str[i++]; +// } +// } +// av_assert0(j + 1 < sizeof(name)); +// name[j] = 0; +// av_assert0(n == subs); + +// name_len = strlen(name); +// bits_len = strlen(bits); + +// if(name_len + bits_len > 60) +// pad = bits_len + 2; +// else +// pad = 61 - name_len; + +// av_log(ctx->log_ctx, ctx->trace_level, "%-10d %s%*s = %" PRId64 "\n", +// position, name, pad, bits, value); +// } + +// int ff_cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc, +// int width, const char *name, +// const int *subscripts, uint32_t *write_to, +// uint32_t range_min, uint32_t range_max) { +// uint32_t value; +// int position; + +// av_assert0(width > 0 && width <= 32); + +// if(get_bits_left(gbc) < width) { +// av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid value at " +// "%s: bitstream ended.\n", +// name); +// return AVERROR_INVALIDDATA; +// } + +// if(ctx->trace_enable) +// position = get_bits_count(gbc); + +// value = get_bits_long(gbc, width); + +// if(ctx->trace_enable) { +// char bits[33]; +// int i; +// for(i = 0; i < width; i++) +// bits[i] = value >> (width - i - 1) & 1 ? '1' : '0'; +// bits[i] = 0; + +// ff_cbs_trace_syntax_element(ctx, position, name, subscripts, +// bits, value); +// } + +// if(value < range_min || value > range_max) { +// av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " +// "%" PRIu32 ", but must be in [%" PRIu32 ",%" PRIu32 "].\n", +// name, value, range_min, range_max); +// return AVERROR_INVALIDDATA; +// } + +// *write_to = value; +// return 0; +// } + +// int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc, +// int width, const char *name, +// const int *subscripts, uint32_t value, +// uint32_t range_min, uint32_t range_max) { +// av_assert0(width > 0 && width <= 32); + +// if(value < range_min || value > range_max) { +// av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " +// "%" PRIu32 ", but must be in [%" PRIu32 ",%" PRIu32 "].\n", +// name, value, range_min, range_max); +// return AVERROR_INVALIDDATA; +// } + +// if(put_bits_left(pbc) < width) +// return AVERROR(ENOSPC); + +// if(ctx->trace_enable) { +// char bits[33]; +// int i; +// for(i = 0; i < width; i++) +// bits[i] = value >> (width - i - 1) & 1 ? '1' : '0'; +// bits[i] = 0; + +// ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), +// name, subscripts, bits, value); +// } + +// if(width < 32) +// put_bits(pbc, width, value); +// else +// put_bits32(pbc, value); + +// return 0; +// } + +// int ff_cbs_read_signed(CodedBitstreamContext *ctx, GetBitContext *gbc, +// int width, const char *name, +// const int *subscripts, int32_t *write_to, +// int32_t range_min, int32_t range_max) { +// int32_t value; +// int position; + +// av_assert0(width > 0 && width <= 32); + +// if(get_bits_left(gbc) < width) { +// av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid value at " +// "%s: bitstream ended.\n", +// name); +// return AVERROR_INVALIDDATA; +// } + +// if(ctx->trace_enable) +// position = get_bits_count(gbc); + +// value = get_sbits_long(gbc, width); + +// if(ctx->trace_enable) { +// char bits[33]; +// int i; +// for(i = 0; i < width; i++) +// bits[i] = value & (1U << (width - i - 1)) ? '1' : '0'; +// bits[i] = 0; + +// ff_cbs_trace_syntax_element(ctx, position, name, subscripts, +// bits, value); +// } + +// if(value < range_min || value > range_max) { +// av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " +// "%" PRId32 ", but must be in [%" PRId32 ",%" PRId32 "].\n", +// name, value, range_min, range_max); +// return AVERROR_INVALIDDATA; +// } + +// *write_to = value; +// return 0; +// } + +// int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc, +// int width, const char *name, +// const int *subscripts, int32_t value, +// int32_t range_min, int32_t range_max) { +// av_assert0(width > 0 && width <= 32); + +// if(value < range_min || value > range_max) { +// av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " +// "%" PRId32 ", but must be in [%" PRId32 ",%" PRId32 "].\n", +// name, value, range_min, range_max); +// return AVERROR_INVALIDDATA; +// } + +// if(put_bits_left(pbc) < width) +// return AVERROR(ENOSPC); + +// if(ctx->trace_enable) { +// char bits[33]; +// int i; +// for(i = 0; i < width; i++) +// bits[i] = value & (1U << (width - i - 1)) ? '1' : '0'; +// bits[i] = 0; + +// ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), +// name, subscripts, bits, value); +// } + +// if(width < 32) +// put_sbits(pbc, width, value); +// else +// put_bits32(pbc, value); + +// return 0; +// } + + +// int ff_cbs_alloc_unit_content(CodedBitstreamUnit *unit, +// size_t size, +// void (*free)(void *opaque, uint8_t *data)) { +// av_assert0(!unit->content && !unit->content_ref); + +// unit->content = av_mallocz(size); +// if(!unit->content) +// return AVERROR(ENOMEM); + +// unit->content_ref = av_buffer_create(unit->content, size, +// free, NULL, 0); +// if(!unit->content_ref) { +// av_freep(&unit->content); +// return AVERROR(ENOMEM); +// } + +// return 0; +// } + +// int ff_cbs_alloc_unit_data(CodedBitstreamUnit *unit, +// size_t size) { +// av_assert0(!unit->data && !unit->data_ref); + +// unit->data_ref = av_buffer_alloc(size + AV_INPUT_BUFFER_PADDING_SIZE); +// if(!unit->data_ref) +// return AVERROR(ENOMEM); + +// unit->data = unit->data_ref->data; +// unit->data_size = size; + +// memset(unit->data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + +// return 0; +// } + +// static int cbs_insert_unit(CodedBitstreamFragment *frag, +// int position) { +// CodedBitstreamUnit *units; + +// if(frag->nb_units < frag->nb_units_allocated) { +// units = frag->units; + +// if(position < frag->nb_units) +// memmove(units + position + 1, units + position, +// (frag->nb_units - position) * sizeof(*units)); +// } +// else { +// units = av_malloc_array(frag->nb_units * 2 + 1, sizeof(*units)); +// if(!units) +// return AVERROR(ENOMEM); + +// frag->nb_units_allocated = 2 * frag->nb_units_allocated + 1; + +// if(position > 0) +// memcpy(units, frag->units, position * sizeof(*units)); + +// if(position < frag->nb_units) +// memcpy(units + position + 1, frag->units + position, +// (frag->nb_units - position) * sizeof(*units)); +// } + +// memset(units + position, 0, sizeof(*units)); + +// if(units != frag->units) { +// av_free(frag->units); +// frag->units = units; +// } + +// ++frag->nb_units; + +// return 0; +// } + +// int ff_cbs_insert_unit_content(CodedBitstreamFragment *frag, +// int position, +// CodedBitstreamUnitType type, +// void *content, +// AVBufferRef *content_buf) { +// CodedBitstreamUnit *unit; +// AVBufferRef *content_ref; +// int err; + +// if(position == -1) +// position = frag->nb_units; +// av_assert0(position >= 0 && position <= frag->nb_units); + +// if(content_buf) { +// content_ref = av_buffer_ref(content_buf); +// if(!content_ref) +// return AVERROR(ENOMEM); +// } +// else { +// content_ref = NULL; +// } + +// err = cbs_insert_unit(frag, position); +// if(err < 0) { +// av_buffer_unref(&content_ref); +// return err; +// } + +// unit = &frag->units[position]; +// unit->type = type; +// unit->content = content; +// unit->content_ref = content_ref; + +// return 0; +// } + +// int ff_cbs_insert_unit_data(CodedBitstreamFragment *frag, +// int position, +// CodedBitstreamUnitType type, +// uint8_t *data, size_t data_size, +// AVBufferRef *data_buf) { +// CodedBitstreamUnit *unit; +// AVBufferRef *data_ref; +// int err; + +// if(position == -1) +// position = frag->nb_units; +// av_assert0(position >= 0 && position <= frag->nb_units); + +// if(data_buf) +// data_ref = av_buffer_ref(data_buf); +// else +// data_ref = av_buffer_create(data, data_size, NULL, NULL, 0); +// if(!data_ref) { +// if(!data_buf) +// av_free(data); +// return AVERROR(ENOMEM); +// } + +// err = cbs_insert_unit(frag, position); +// if(err < 0) { +// av_buffer_unref(&data_ref); +// return err; +// } + +// unit = &frag->units[position]; +// unit->type = type; +// unit->data = data; +// unit->data_size = data_size; +// unit->data_ref = data_ref; + +// return 0; +// } + +// void ff_cbs_delete_unit(CodedBitstreamFragment *frag, +// int position) { +// av_assert0(0 <= position && position < frag->nb_units && "Unit to be deleted not in fragment."); + +// cbs_unit_uninit(&frag->units[position]); + +// --frag->nb_units; + +// if(frag->nb_units > 0) +// memmove(frag->units + position, +// frag->units + position + 1, +// (frag->nb_units - position) * sizeof(*frag->units)); +// } + +// static void cbs_default_free_unit_content(void *opaque, uint8_t *data) { +// const CodedBitstreamUnitTypeDescriptor *desc = opaque; +// if(desc->content_type == CBS_CONTENT_TYPE_INTERNAL_REFS) { +// int i; +// for(i = 0; i < desc->nb_ref_offsets; i++) { +// void **ptr = (void **)(data + desc->ref_offsets[i]); +// av_buffer_unref((AVBufferRef **)(ptr + 1)); +// } +// } +// av_free(data); +// } + +// static const CodedBitstreamUnitTypeDescriptor +// * +// cbs_find_unit_type_desc(CodedBitstreamContext *ctx, +// CodedBitstreamUnit *unit) { +// const CodedBitstreamUnitTypeDescriptor *desc; +// int i, j; + +// if(!ctx->codec->unit_types) +// return NULL; + +// for(i = 0;; i++) { +// desc = &ctx->codec->unit_types[i]; +// if(desc->nb_unit_types == 0) +// break; +// if(desc->nb_unit_types == CBS_UNIT_TYPE_RANGE) { +// if(unit->type >= desc->unit_type_range_start && +// unit->type <= desc->unit_type_range_end) +// return desc; +// } +// else { +// for(j = 0; j < desc->nb_unit_types; j++) { +// if(desc->unit_types[j] == unit->type) +// return desc; +// } +// } +// } +// return NULL; +// } + +// int ff_cbs_alloc_unit_content2(CodedBitstreamContext *ctx, +// CodedBitstreamUnit *unit) { +// const CodedBitstreamUnitTypeDescriptor *desc; + +// av_assert0(!unit->content && !unit->content_ref); + +// desc = cbs_find_unit_type_desc(ctx, unit); +// if(!desc) +// return AVERROR(ENOSYS); + +// unit->content = av_mallocz(desc->content_size); +// if(!unit->content) +// return AVERROR(ENOMEM); + +// unit->content_ref = +// av_buffer_create(unit->content, desc->content_size, +// desc->content_free ? desc->content_free : cbs_default_free_unit_content, +// (void *)desc, 0); +// if(!unit->content_ref) { +// av_freep(&unit->content); +// return AVERROR(ENOMEM); +// } + +// return 0; +// } + +// static int cbs_clone_unit_content(AVBufferRef **clone_ref, +// CodedBitstreamUnit *unit, +// const CodedBitstreamUnitTypeDescriptor *desc) { +// uint8_t *src, *copy; +// uint8_t **src_ptr, **copy_ptr; +// AVBufferRef **src_buf, **copy_buf; +// int err, i; + +// av_assert0(unit->content); +// src = unit->content; + +// copy = av_memdup(src, desc->content_size); +// if(!copy) +// return AVERROR(ENOMEM); + +// for(i = 0; i < desc->nb_ref_offsets; i++) { +// src_ptr = (uint8_t **)(src + desc->ref_offsets[i]); +// src_buf = (AVBufferRef **)(src_ptr + 1); +// copy_ptr = (uint8_t **)(copy + desc->ref_offsets[i]); +// copy_buf = (AVBufferRef **)(copy_ptr + 1); + +// if(!*src_ptr) { +// av_assert0(!*src_buf); +// continue; +// } +// if(!*src_buf) { +// // We can't handle a non-refcounted pointer here - we don't +// // have enough information to handle whatever structure lies +// // at the other end of it. +// err = AVERROR(EINVAL); +// goto fail; +// } + +// // src_ptr is required to point somewhere inside src_buf. If it +// // doesn't, there is a bug somewhere. +// av_assert0(*src_ptr >= (*src_buf)->data && +// *src_ptr < (*src_buf)->data + (*src_buf)->size); + +// *copy_buf = av_buffer_ref(*src_buf); +// if(!*copy_buf) { +// err = AVERROR(ENOMEM); +// goto fail; +// } +// *copy_ptr = (*copy_buf)->data + (*src_ptr - (*src_buf)->data); +// } + +// *clone_ref = av_buffer_create(copy, desc->content_size, +// desc->content_free ? desc->content_free : +// cbs_default_free_unit_content, +// (void *)desc, 0); +// if(!*clone_ref) { +// err = AVERROR(ENOMEM); +// goto fail; +// } + +// return 0; + +// fail: +// for(--i; i >= 0; i--) +// av_buffer_unref((AVBufferRef **)(copy + desc->ref_offsets[i])); +// av_freep(©); +// *clone_ref = NULL; +// return err; +// } + +// int ff_cbs_make_unit_refcounted(CodedBitstreamContext *ctx, +// CodedBitstreamUnit *unit) { +// const CodedBitstreamUnitTypeDescriptor *desc; +// AVBufferRef *ref; +// int err; + +// av_assert0(unit->content); +// if(unit->content_ref) { +// // Already refcounted, nothing to do. +// return 0; +// } + +// desc = cbs_find_unit_type_desc(ctx, unit); +// if(!desc) +// return AVERROR(ENOSYS); + +// switch(desc->content_type) { +// case CBS_CONTENT_TYPE_POD: +// ref = av_buffer_alloc(desc->content_size); +// if(!ref) +// return AVERROR(ENOMEM); +// memcpy(ref->data, unit->content, desc->content_size); +// err = 0; +// break; + +// case CBS_CONTENT_TYPE_INTERNAL_REFS: +// err = cbs_clone_unit_content(&ref, unit, desc); +// break; + +// case CBS_CONTENT_TYPE_COMPLEX: +// if(!desc->content_clone) +// return AVERROR_PATCHWELCOME; +// err = desc->content_clone(&ref, unit); +// break; + +// default: +// av_assert0(0 && "Invalid content type."); +// } + +// if(err < 0) +// return err; + +// unit->content_ref = ref; +// unit->content = ref->data; +// return 0; +// } + +// int ff_cbs_make_unit_writable(CodedBitstreamContext *ctx, +// CodedBitstreamUnit *unit) { +// const CodedBitstreamUnitTypeDescriptor *desc; +// AVBufferRef *ref; +// int err; + +// // This can only be applied to refcounted units. +// err = ff_cbs_make_unit_refcounted(ctx, unit); +// if(err < 0) +// return err; +// av_assert0(unit->content && unit->content_ref); + +// if(av_buffer_is_writable(unit->content_ref)) +// return 0; + +// desc = cbs_find_unit_type_desc(ctx, unit); +// if(!desc) +// return AVERROR(ENOSYS); + +// switch(desc->content_type) { +// case CBS_CONTENT_TYPE_POD: +// err = av_buffer_make_writable(&unit->content_ref); +// break; + +// case CBS_CONTENT_TYPE_INTERNAL_REFS: +// err = cbs_clone_unit_content(&ref, unit, desc); +// break; + +// case CBS_CONTENT_TYPE_COMPLEX: +// if(!desc->content_clone) +// return AVERROR_PATCHWELCOME; +// err = desc->content_clone(&ref, unit); +// break; + +// default: +// av_assert0(0 && "Invalid content type."); +// } +// if(err < 0) +// return err; + +// if(desc->content_type != CBS_CONTENT_TYPE_POD) { +// av_buffer_unref(&unit->content_ref); +// unit->content_ref = ref; +// } +// unit->content = unit->content_ref->data; +// return 0; +// } + +// const uint8_t ff_log2_tab[256] = { +// 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, +// 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, +// 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, +// 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, +// 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +// 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +// 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +// 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +// }; \ No newline at end of file From f31de5ea3448eb12dec55b85448fd13dc7193570 Mon Sep 17 00:00:00 2001 From: Caio Vidal Date: Mon, 28 Feb 2022 09:40:59 -0300 Subject: [PATCH 3/9] Add qsv to config.cpp file and ui --- sunshine/video.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sunshine/video.cpp b/sunshine/video.cpp index bcb0473776a..6fdf0e18edd 100644 --- a/sunshine/video.cpp +++ b/sunshine/video.cpp @@ -486,14 +486,16 @@ static encoder_t quicksync { { { { "forced-idr"s, 1 }, - { "preset"s, &config::video.sw.preset }, + { "preset"s, &config::video.qsv.preset }, }, std::make_optional({ "qp"s, &config::video.qp }), "hevc_qsv"s, }, { { - { "preset"s, 7 }, + { "preset"s, &config::video.qsv.preset }, + { "cavlc"s, &config::video.qsv.cavlc }, + }, std::make_optional({ "qp"s, &config::video.qp }), "h264_qsv"s, @@ -800,8 +802,6 @@ int encode(int64_t frame_nr, session_t &session, frame_t::pointer frame, safe::m while(ret >= 0) { auto packet = std::make_unique(nullptr); - auto av_packet = packet.get(); - av_packet->alloc(); ret = avcodec_receive_packet(ctx.get(), packet.get()); if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { From 02c5e3e131ca076b6486f5b5240681a8dd4de64a Mon Sep 17 00:00:00 2001 From: Caio Vidal Date: Mon, 28 Feb 2022 09:41:23 -0300 Subject: [PATCH 4/9] Add qsv to UI --- CMakeLists.txt | 8 +- assets/sunshine.conf | 348 ++----------- assets/web/config.html | 55 ++- sunshine/config.cpp | 28 +- sunshine/config.h | 5 + sunshine/video.h | 27 +- third-party/cbs/cbs.c | 1050 ---------------------------------------- 7 files changed, 108 insertions(+), 1413 deletions(-) delete mode 100644 third-party/cbs/cbs.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ff134d2585..60542439260 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,7 +52,7 @@ if(WIN32) file( DOWNLOAD "https://github.com/caioavidal/sunshine-prebuilt/releases/download/1.0.0/pre-compiled.zip" "${CMAKE_CURRENT_BINARY_DIR}/pre-compiled.zip" TIMEOUT 60 - EXPECTED_HASH SHA256=5d59986bd7f619eaaf82b2dd56b5127b747c9cbe8db61e3b898ff6b485298ed6) + EXPECTED_HASH SHA256=bf0cab8832272f7e077ee87a678bfd9edfeddb6cd613c0aab25a0d893ff08eda) file(ARCHIVE_EXTRACT INPUT "${CMAKE_CURRENT_BINARY_DIR}/pre-compiled.zip" @@ -380,8 +380,6 @@ include_directories( ${PLATFORM_INCLUDE_DIRS} ) -add_subdirectory(third-party/cbs) - string(TOUPPER "x${CMAKE_BUILD_TYPE}" BUILD_TYPE) if("${BUILD_TYPE}" STREQUAL "XDEBUG") list(APPEND SUNSHINE_COMPILE_OPTIONS -O0 -ggdb3) @@ -405,12 +403,8 @@ if(NOT SUNSHINE_DEFAULT_DIR) set(SUNSHINE_DEFAULT_DIR "${SUNSHINE_ASSETS_DIR}") endif() -list(APPEND CBS_EXTERNAL_LIBRARIES - cbs) - list(APPEND SUNSHINE_EXTERNAL_LIBRARIES libminiupnpc-static - ${CBS_EXTERNAL_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} enet opus diff --git a/assets/sunshine.conf b/assets/sunshine.conf index a1e020f03c9..0543134435d 100644 --- a/assets/sunshine.conf +++ b/assets/sunshine.conf @@ -1,318 +1,30 @@ -# If no external IP address is given, Sunshine will attempt to automatically detect external ip-address -# external_ip = 123.456.789.12 - -# Set the familly of ports used by Sunshine -# port = 47989 - -# The private key must be 2048 bits -# pkey = /dir/pkey.pem - -# The certificate must be signed with a 2048 bit key -# cert = /dir/cert.pem - -# The name displayed by Moonlight -# If not specified, the PC's hostname is used -# sunshine_name = Sunshine - -# The minimum log level printed to standard out -# -# none -> no logs are printed to standard out -# -# verbose = [0] -# debug = [1] -# info = [2] -# warning = [3] -# error = [4] -# fatal = [5] -# none = [6] -# -# min_log_level = info - -# The origin of the remote endpoint address that is not denied for HTTP method /pin -# Could be any of the following values: -# pc|lan|wan -# pc: Only localhost may access /pin -# lan: Only those in LAN may access /pin -# wan: Anyone may access /pin -# -# origin_pin_allowed = pc - -# The origin of the remote endpoint address that is not denied for HTTPS Web UI -# Could be any of the following values: -# pc|lan|wan -# pc: Only localhost may access the Web Manager -# lan: Only those in LAN may access the Web Manager -# wan: Anyone may access the Web Manager -# -# origin_web_ui_allowed = lan - -# If UPnP is enabled, Sunshine will attempt to open ports for streaming over the internet -# To enable it, uncomment the following line: -# upnp = on - -# The file where current state of Sunshine is stored -# file_state = sunshine_state.json - -# The file where user credentials for the UI are stored -# By default, credentials are stored in `file_state` -# credentials_file = sunshine_state.json - -# The display modes advertised by Sunshine -# -# Some versions of Moonlight, such as Moonlight-nx (Switch), -# rely on this list to ensure that the requested resolutions and fps -# are supported. -# -# fps = [10, 30, 60, 90, 120] -# resolutions = [ -# 352x240, -# 480x360, -# 858x480, -# 1280x720, -# 1920x1080, -# 2560x1080, -# 3440x1440, -# 1920x1200, -# 3860x2160, -# 3840x1600, -# ] - -# Sometimes it may be usefull to map keybindings. -# Wayland won't allow clients to capture the Win Key for example -# -# See https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes -# -# Note: -# keybindings needs to have a multiple of two elements -# keybindings = [ -# 0x10, 0xA0, -# 0x11, 0xA2, -# 0x12, 0xA4, -# 0x4A, 0x4B -# ] - -# It may be possible that you cannot send the Windows Key from Moonlight directly. -# In those cases it may be useful to make Sunshine think the Right Alt key is the Windows key -# key_rightalt_to_key_win = enabled - -# How long to wait in milliseconds for data from moonlight before shutting down the stream -# ping_timeout = 10000 - -# The file where configuration for the different applications that Sunshine can run during a stream -# file_apps = apps.json - -# Percentage of error correcting packets per data packet in each video frame -# Higher values can correct for more network packet loss, but at the cost of increasing bandwidth usage -# The default value of 20 is what GeForce Experience uses -# -# The value must be greater than 0 and lower than or equal to 255 -# fec_percentage = 20 - -# When multicasting, it could be usefull to have different configurations for each connected Client. -# For example: -# Clients connected through WAN and LAN have different bitrate contstraints. -# Decoders may require different settings for color -# -# Unlike simply broadcasting to multiple Client, this will generate distinct video streams. -# Note, CPU usage increases for each distinct video stream generated -# channels = 1 - -# The back/select button on the controller -# On the Shield, the home and powerbutton are not passed to Moonlight -# If, after the timeout, the back button is still pressed down, Home/Guide button press is emulated. -# If back_button_timeout < 0, then the Home/Guide button will not be emulated -# back_button_timeout = 2000 - -# !! Windows only !! -# Gamepads supported by Sunshine -# Possible values: -# x360 -- xbox 360 controller -# ds4 -- dualshock controller (PS4) -# gamepad = x360 - -# Control how fast keys will repeat themselves -# The initial delay in milliseconds before repeating keys -# key_repeat_delay = 500 -# -# How often keys repeat every second -# This configurable option supports decimals -# key_repeat_frequency = 24.9 - -# The name of the audio sink used for Audio Loopback -# If you do not specify this variable, pulseaudio will select the default monitor device. -# -# You can find the name of the audio sink using the following command: -# !! Linux only !! -# pacmd list-sinks | grep "name:" if running vanilla pulseaudio -# pPipewire: Use `pactl info | grep Source`. In some causes you'd need to use the `sink` device. Try `pactl info | grep Sink`, if _Source_ doesn't work -# audio_sink = alsa_output.pci-0000_09_00.3.analog-stereo -# -# !! Windows only !! -# tools\audio-info.exe -# audio_sink = {0.0.0.00000000}.{FD47D9CC-4218-4135-9CE2-0C195C87405B} -# -# The virtual sink, is the audio device that's virtual (Like Steam Streaming Speakers), it allows Sunshine -# to stream audio, while muting the speakers. -# virtual_sink = {0.0.0.00000000}.{8edba70c-1125-467c-b89c-15da389bc1d4} - -# -# !! MacOS only !! -# audio_sink = BlackHole 2ch - -# !! Windows only !! -# You can select the video card you want to stream: -# The appropriate values can be found using the following command: -# tools\dxgi-info.exe -# adapter_name = Radeon RX 580 Series -# output_name = \\.\DISPLAY1 - -# !! Linux only !! -# Set the display number to stream. -# You can find them by the following command: -# xrandr --listmonitors -# Example output: "0: +HDMI-1 1920/518x1200/324+0+0 HDMI-1" -# ^ <-- You need this. -# output_name = 0 - -############################################### -# FFmpeg software encoding parameters -# Honestly, I have no idea what the optimal values would be. -# Play around with this :) - -# Quantitization Parameter -# Some devices don't support Constant Bit Rate. For those devices, QP is used instead -# Higher value means more compression, but less quality -# qp = 28 - -# Minimum number of threads used by ffmpeg to encode the video. -# Increasing the value slightly reduces encoding efficiency, but the tradeoff is usually -# worth it to gain the use of more CPU cores for encoding. The ideal value is the lowest -# value that can reliably encode at your desired streaming settings on your hardware. -# min_threads = 1 - -# Allows the client to request HEVC Main or HEVC Main10 video streams. -# HEVC is more CPU-intensive to encode, so enabling this may reduce performance when using software encoding. -# If set to 0 (default), Sunshine will specify support for HEVC based on encoder -# If set to 1, Sunshine will not advertise support for HEVC -# If set to 2, Sunshine will advertise support for HEVC Main profile -# If set to 3, Sunshine will advertise support for HEVC Main and Main10 (HDR) profiles -# hevc_mode = 2 - -# Force a specific encoder, otherwise Sunshine will use the first encoder that is available -# supported encoders: -# nvenc -# amdvce # NOTE: alpha stage. The cursor is not yet displayed -# software -# -# encoder = nvenc -##################################### Software ##################################### -# See x264 --fullhelp for the different presets -# sw_preset = superfast -# sw_tune = zerolatency -# - -##################################### NVENC ##################################### -###### presets ########### -# default -# hp -- high performance -# hq -- high quality -# slow -- hq 2 passes -# medium -- hq 1 pass -# fast -- hp 1 pass -# bd -# ll -- low latency -# llhq -# llhp -# lossless -# losslesshp -########################## -# nv_preset = llhq -# -####### rate control ##### -# auto -- let ffmpeg decide rate control -# constqp -- constant QP mode -# vbr -- variable bitrate -# cbr -- constant bitrate -# cbr_hq -- cbr high quality -# cbr_ld_hq -- cbr low delay high quality -# vbr_hq -- vbr high quality -########################## -# nv_rc = auto - -###### h264 entropy ###### -# auto -- let ffmpeg nvenc decide the entropy encoding -# cabac -# cavlc -########################## -# nv_coder = auto - -##################################### AMD ##################################### -###### presets ########### -# default -# speed -# balanced -########################## -# amd_quality = balanced -# -####### rate control ##### -# auto -- let ffmpeg decide rate control -# constqp -- constant QP mode -# vbr_latency -- Latency Constrained Variable Bitrate -# vbr_peak -- Peak Contrained Variable Bitrate -# cbr -- constant bitrate -########################## -# amd_rc = auto - -###### h264 entropy ###### -# auto -- let ffmpeg nvenc decide the entropy encoding -# cabac -# cavlc -########################## -# amd_coder = auto - -#################################### VAAPI ################################### -####### adapter ########## -# Unlike with `amdvce` and `nvenc`, it doesn't matter if video encoding is done -# on a different GPU. -# Run the following commands: -# 1. ls /dev/dri/renderD* -# to find all devices capable of VAAPI -# 2. vainfo --display drm --device /dev/dri/renderD129 | grep -E "((VAProfileH264High|VAProfileHEVCMain|VAProfileHEVCMain10).*VAEntrypointEncSlice)|Driver version" -# Lists the name and capabilities of the device. -# To be supported by Sunshine, it needs to have at the very minimum: -# VAProfileH264High : VAEntrypointEncSlice -# adapter_name = /dev/dri/renderD128 - -################################# VideoToolbox ############################### -####### software encoding ########## -# Video Toolbox can be allowed/required to use software encoding instead of -# hardware accelerated encoding. -# auto -- let sunshine decide on encoding -# disabled -- disable software encoding -# allowed -- allow software encoding -# forced -- force software encoding -########################## -# vt_software = auto -# -####### realtime encoding ########## -# Disabling realtime encoding might result in a delayed frame encoding or frame drop -########################## -# vt_realtime = enabled -# -###### h264/hevc entropy ###### -# auto -- let ffmpeg decide the entropy encoding -# cabac -# cavlc -########################## -# vt_coder = auto - - -############################################## -# Some configurable parameters, are merely toggles for specific features -# The first occurrence turns it on, the second occurence turns it off, the third occurence turns it on again, etc, etc -# Here, you change the default state of any flag -# -# To set the initial state of flags -0 and -1 to on, set the following flags: -# flags = 012 -# -# See: sunshine --help for all options under the header: flags +key_rightalt_to_key_win = disabled +gamepad = x360 +upnp = disabled +min_log_level = 2 +origin_pin_allowed = pc +origin_web_ui_allowed = lan +hevc_mode = 0 +qsv_preset = 7 +qsv_cavlc = 1 +nv_preset = default +nv_rc = auto +nv_coder = auto +amd_quality = default +amd_rc = auto +vt_coder = auto +vt_software = auto +vt_realtime = enabled +fps = [10,30,60,90,120] +resolutions = [ + 352x240, + 480x360, + 858x480, + 1280x720, + 1920x1080, + 2560x1080, + 3440x1440, + 1920x1200, + 3860x2160, + 3840x1600 +] diff --git a/assets/web/config.html b/assets/web/config.html index 203e807fea5..0e65988aa2f 100644 --- a/assets/web/config.html +++ b/assets/web/config.html @@ -1,15 +1,10 @@
-

Configuration

-
- -
+ +
+
+ +
+ + +
+
+
+ +
+ + +
+
+
@@ -787,6 +812,10 @@

Configuration

id: "sw", name: "Software Encoder", }, + { + id: "qsv", + name: "QuickSync Encoder", + }, { id: "nv", name: "NVENC Encoder", @@ -839,6 +868,8 @@

Configuration

this.config.origin_web_manager_allowed || "lan"; this.config.hevc_mode = this.config.hevc_mode || 0; this.config.encoder = this.config.encoder || ""; + this.config.qsv_preset = this.config.qsv_preset || "4"; + this.config.qsv_cavlc = this.config.qsv_cavlc || "0"; this.config.nv_preset = this.config.nv_preset || "default"; this.config.nv_rc = this.config.nv_rc || "auto"; this.config.nv_coder = this.config.nv_coder || "auto"; @@ -902,4 +933,4 @@

Configuration

font-size: 12px; font-weight: bold; } - + \ No newline at end of file diff --git a/sunshine/config.cpp b/sunshine/config.cpp index 6aaeb3058e2..188ff0e35d8 100644 --- a/sunshine/config.cpp +++ b/sunshine/config.cpp @@ -162,6 +162,26 @@ int coder_from_view(const std::string_view &coder) { } } // namespace amd +namespace qsv { +enum preset_e : int { + _default = 4, + veryslow = 1, + slower = 2, + slow = 3, + medium = 4, + fast = 5, + faster = 6, + veryfast = 7 +}; + +enum cavlc_e : int { + _auto = false, + enabled = true, + disabled = false +}; + +} // namespace qsv + namespace vt { enum coder_e : int { @@ -213,9 +233,10 @@ video_t video { nv::llhq, std::nullopt, -1 }, // nv - { - amd::balanced, + qsv::medium, + qsv::disabled }, //qsv + { amd::balanced, std::nullopt, std::nullopt, -1 }, // amd @@ -711,6 +732,9 @@ void apply_config(std::unordered_map &&vars) { int_f(vars, "nv_rc", video.nv.rc, nv::rc_from_view); int_f(vars, "nv_coder", video.nv.coder, nv::coder_from_view); + int_f(vars, "qsv_preset", video.qsv.preset); + int_f(vars, "qsv_cavlc", video.qsv.cavlc); + int_f(vars, "amd_quality", video.amd.quality, amd::quality_from_view); std::string rc; diff --git a/sunshine/config.h b/sunshine/config.h index 183139612dc..d8e43166a2f 100644 --- a/sunshine/config.h +++ b/sunshine/config.h @@ -26,6 +26,11 @@ struct video_t { std::optional rc; int coder; } nv; + + struct { + std::optional preset; + std::optional cavlc; + } qsv; struct { std::optional quality; diff --git a/sunshine/video.h b/sunshine/video.h index 1002b31ee91..ae07ae54ad2 100644 --- a/sunshine/video.h +++ b/sunshine/video.h @@ -27,31 +27,10 @@ struct packet_raw_t : public AVPacket { buf = nullptr; side_data = nullptr; side_data_elems = 0; + opaque = nullptr; + opaque_ref = nullptr; } - - void alloc() { - AVPacket *enc_pkt; - - if(!(enc_pkt = av_packet_alloc())) { - return; - } - - pts = enc_pkt->pts; - dts = enc_pkt->dts; - pos = enc_pkt->pos; - duration = enc_pkt->duration; - flags = enc_pkt->flags; - stream_index = enc_pkt->stream_index; - buf = enc_pkt->buf; - side_data = enc_pkt->side_data; - side_data_elems = enc_pkt->side_data_elems; - data = enc_pkt->data; - opaque = enc_pkt->opaque; - opaque_ref = enc_pkt->opaque_ref; - size = enc_pkt->size; - time_base = enc_pkt->time_base; - } - + template explicit packet_raw_t(P *user_data) : channel_data { user_data } { init_packet(); diff --git a/third-party/cbs/cbs.c b/third-party/cbs/cbs.c deleted file mode 100644 index 19cb8a2e69c..00000000000 --- a/third-party/cbs/cbs.c +++ /dev/null @@ -1,1050 +0,0 @@ -// /* -// * 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 -// */ - -// #include - -// #include -// #include -// #include -// #include - -// #include - -// #include "cbs/cbs.h" -// #include "cbs_internal.h" - -// #include "get_bits.h" - - -// static const CodedBitstreamType *const cbs_type_table[] = { -// #if CONFIG_CBS_AV1 -// &ff_cbs_type_av1, -// #endif -// #if CONFIG_CBS_H264 -// &ff_cbs_type_h264, -// #endif -// #if CONFIG_CBS_H265 -// &ff_cbs_type_h265, -// #endif -// #if CONFIG_CBS_JPEG -// &ff_cbs_type_jpeg, -// #endif -// #if CONFIG_CBS_MPEG2 -// &ff_cbs_type_mpeg2, -// #endif -// #if CONFIG_CBS_VP9 -// &ff_cbs_type_vp9, -// #endif -// }; - -// const enum AVCodecID ff_cbs_all_codec_ids[] = { -// #if CONFIG_CBS_AV1 -// AV_CODEC_ID_AV1, -// #endif -// #if CONFIG_CBS_H264 -// AV_CODEC_ID_H264, -// #endif -// #if CONFIG_CBS_H265 -// AV_CODEC_ID_H265, -// #endif -// #if CONFIG_CBS_JPEG -// AV_CODEC_ID_MJPEG, -// #endif -// #if CONFIG_CBS_MPEG2 -// AV_CODEC_ID_MPEG2VIDEO, -// #endif -// #if CONFIG_CBS_VP9 -// AV_CODEC_ID_VP9, -// #endif -// AV_CODEC_ID_NONE -// }; - -// int ff_cbs_init(CodedBitstreamContext **ctx_ptr, -// enum AVCodecID codec_id, void *log_ctx) { -// CodedBitstreamContext *ctx; -// const CodedBitstreamType *type; -// int i; - -// type = NULL; -// for(i = 0; i < FF_ARRAY_ELEMS(cbs_type_table); i++) { -// if(cbs_type_table[i]->codec_id == codec_id) { -// type = cbs_type_table[i]; -// break; -// } -// } -// if(!type) -// return AVERROR(EINVAL); - -// ctx = av_mallocz(sizeof(*ctx)); -// if(!ctx) -// return AVERROR(ENOMEM); - -// ctx->log_ctx = log_ctx; -// ctx->codec = type; /* Must be before any error */ - -// if(type->priv_data_size) { -// ctx->priv_data = av_mallocz(ctx->codec->priv_data_size); -// if(!ctx->priv_data) { -// av_freep(&ctx); -// return AVERROR(ENOMEM); -// } -// if(type->priv_class) { -// *(const AVClass **)ctx->priv_data = type->priv_class; -// av_opt_set_defaults(ctx->priv_data); -// } -// } - -// ctx->decompose_unit_types = NULL; - -// ctx->trace_enable = 0; -// ctx->trace_level = AV_LOG_TRACE; - -// *ctx_ptr = ctx; -// return 0; -// } - -// void ff_cbs_flush(CodedBitstreamContext *ctx) { -// if(ctx->codec->flush) -// ctx->codec->flush(ctx); -// } - -// void ff_cbs_close(CodedBitstreamContext **ctx_ptr) { -// CodedBitstreamContext *ctx = *ctx_ptr; - -// if(!ctx) -// return; - -// if(ctx->codec->close) -// ctx->codec->close(ctx); - -// av_freep(&ctx->write_buffer); - -// if(ctx->codec->priv_class && ctx->priv_data) -// av_opt_free(ctx->priv_data); - -// av_freep(&ctx->priv_data); -// av_freep(ctx_ptr); -// } - -// static void cbs_unit_uninit(CodedBitstreamUnit *unit) { -// av_buffer_unref(&unit->content_ref); -// unit->content = NULL; - -// av_buffer_unref(&unit->data_ref); -// unit->data = NULL; -// unit->data_size = 0; -// unit->data_bit_padding = 0; -// } - -// void ff_cbs_fragment_reset(CodedBitstreamFragment *frag) { -// int i; - -// for(i = 0; i < frag->nb_units; i++) -// cbs_unit_uninit(&frag->units[i]); -// frag->nb_units = 0; - -// av_buffer_unref(&frag->data_ref); -// frag->data = NULL; -// frag->data_size = 0; -// frag->data_bit_padding = 0; -// } - -// void ff_cbs_fragment_free(CodedBitstreamFragment *frag) { -// ff_cbs_fragment_reset(frag); - -// av_freep(&frag->units); -// frag->nb_units_allocated = 0; -// } - -// static int cbs_read_fragment_content(CodedBitstreamContext *ctx, -// CodedBitstreamFragment *frag) { -// int err, i, j; - -// for(i = 0; i < frag->nb_units; i++) { -// CodedBitstreamUnit *unit = &frag->units[i]; - -// if(ctx->decompose_unit_types) { -// for(j = 0; j < ctx->nb_decompose_unit_types; j++) { -// if(ctx->decompose_unit_types[j] == unit->type) -// break; -// } -// if(j >= ctx->nb_decompose_unit_types) -// continue; -// } - -// av_buffer_unref(&unit->content_ref); -// unit->content = NULL; - -// av_assert0(unit->data && unit->data_ref); - -// err = ctx->codec->read_unit(ctx, unit); -// if(err == AVERROR(ENOSYS)) { -// av_log(ctx->log_ctx, AV_LOG_VERBOSE, -// "Decomposition unimplemented for unit %d " -// "(type %" PRIu32 ").\n", -// i, unit->type); -// } -// else if(err == AVERROR(EAGAIN)) { -// av_log(ctx->log_ctx, AV_LOG_VERBOSE, -// "Skipping decomposition of unit %d " -// "(type %" PRIu32 ").\n", -// i, unit->type); -// av_buffer_unref(&unit->content_ref); -// unit->content = NULL; -// } -// else if(err < 0) { -// av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to read unit %d " -// "(type %" PRIu32 ").\n", -// i, unit->type); -// return err; -// } -// } - -// return 0; -// } - -// static int cbs_fill_fragment_data(CodedBitstreamFragment *frag, -// const uint8_t *data, size_t size) { -// av_assert0(!frag->data && !frag->data_ref); - -// frag->data_ref = -// av_buffer_alloc(size + AV_INPUT_BUFFER_PADDING_SIZE); -// if(!frag->data_ref) -// return AVERROR(ENOMEM); - -// frag->data = frag->data_ref->data; -// frag->data_size = size; - -// memcpy(frag->data, data, size); -// memset(frag->data + size, 0, -// AV_INPUT_BUFFER_PADDING_SIZE); - -// return 0; -// } - -// static int cbs_read_data(CodedBitstreamContext *ctx, -// CodedBitstreamFragment *frag, -// AVBufferRef *buf, -// const uint8_t *data, size_t size, -// int header) { -// int err; - -// if(buf) { -// frag->data_ref = av_buffer_ref(buf); -// if(!frag->data_ref) -// return AVERROR(ENOMEM); - -// frag->data = (uint8_t *)data; -// frag->data_size = size; -// } -// else { -// err = cbs_fill_fragment_data(frag, data, size); -// if(err < 0) -// return err; -// } - -// err = ctx->codec->split_fragment(ctx, frag, header); -// if(err < 0) -// return err; - -// return cbs_read_fragment_content(ctx, frag); -// } - -// int ff_cbs_read_extradata(CodedBitstreamContext *ctx, -// CodedBitstreamFragment *frag, -// const AVCodecParameters *par) { -// return cbs_read_data(ctx, frag, NULL, -// par->extradata, -// par->extradata_size, 1); -// } - -// int ff_cbs_read_extradata_from_codec(CodedBitstreamContext *ctx, -// CodedBitstreamFragment *frag, -// const AVCodecContext *avctx) { -// return cbs_read_data(ctx, frag, NULL, -// avctx->extradata, -// avctx->extradata_size, 1); -// } - -// int ff_cbs_read_packet(CodedBitstreamContext *ctx, -// CodedBitstreamFragment *frag, -// const AVPacket *pkt) { -// return cbs_read_data(ctx, frag, pkt->buf, -// pkt->data, pkt->size, 0); -// } - -// int ff_cbs_read(CodedBitstreamContext *ctx, -// CodedBitstreamFragment *frag, -// const uint8_t *data, size_t size) { -// return cbs_read_data(ctx, frag, NULL, -// data, size, 0); -// } - -// static int cbs_write_unit_data(CodedBitstreamContext *ctx, -// CodedBitstreamUnit *unit) { -// PutBitContext pbc; -// int ret; - -// if(!ctx->write_buffer) { -// // Initial write buffer size is 1MB. -// ctx->write_buffer_size = 1024 * 1024; - -// reallocate_and_try_again: -// ret = av_reallocp(&ctx->write_buffer, ctx->write_buffer_size); -// if(ret < 0) { -// av_log(ctx->log_ctx, AV_LOG_ERROR, "Unable to allocate a " -// "sufficiently large write buffer (last attempt " -// "%zu bytes).\n", -// ctx->write_buffer_size); -// return ret; -// } -// } - -// init_put_bits(&pbc, ctx->write_buffer, ctx->write_buffer_size); - -// ret = ctx->codec->write_unit(ctx, unit, &pbc); -// if(ret < 0) { -// if(ret == AVERROR(ENOSPC)) { -// // Overflow. -// if(ctx->write_buffer_size == INT_MAX / 8) -// return AVERROR(ENOMEM); -// ctx->write_buffer_size = FFMIN(2 * ctx->write_buffer_size, INT_MAX / 8); -// goto reallocate_and_try_again; -// } -// // Write failed for some other reason. -// return ret; -// } - -// // Overflow but we didn't notice. -// av_assert0(put_bits_count(&pbc) <= 8 * ctx->write_buffer_size); - -// if(put_bits_count(&pbc) % 8) -// unit->data_bit_padding = 8 - put_bits_count(&pbc) % 8; -// else -// unit->data_bit_padding = 0; - -// flush_put_bits(&pbc); - -// ret = ff_cbs_alloc_unit_data(unit, put_bytes_output(&pbc)); -// if(ret < 0) -// return ret; - -// memcpy(unit->data, ctx->write_buffer, unit->data_size); - -// return 0; -// } - -// int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx, -// CodedBitstreamFragment *frag) { -// int err, i; - -// for(i = 0; i < frag->nb_units; i++) { -// CodedBitstreamUnit *unit = &frag->units[i]; - -// if(!unit->content) -// continue; - -// av_buffer_unref(&unit->data_ref); -// unit->data = NULL; - -// err = cbs_write_unit_data(ctx, unit); -// if(err < 0) { -// av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to write unit %d " -// "(type %" PRIu32 ").\n", -// i, unit->type); -// return err; -// } -// av_assert0(unit->data && unit->data_ref); -// } - -// av_buffer_unref(&frag->data_ref); -// frag->data = NULL; - -// err = ctx->codec->assemble_fragment(ctx, frag); -// if(err < 0) { -// av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to assemble fragment.\n"); -// return err; -// } -// av_assert0(frag->data && frag->data_ref); - -// return 0; -// } - -// int ff_cbs_write_extradata(CodedBitstreamContext *ctx, -// AVCodecParameters *par, -// CodedBitstreamFragment *frag) { -// int err; - -// err = ff_cbs_write_fragment_data(ctx, frag); -// if(err < 0) -// return err; - -// av_freep(&par->extradata); - -// par->extradata = av_malloc(frag->data_size + -// AV_INPUT_BUFFER_PADDING_SIZE); -// if(!par->extradata) -// return AVERROR(ENOMEM); - -// memcpy(par->extradata, frag->data, frag->data_size); -// memset(par->extradata + frag->data_size, 0, -// AV_INPUT_BUFFER_PADDING_SIZE); -// par->extradata_size = frag->data_size; - -// return 0; -// } - -// int ff_cbs_write_packet(CodedBitstreamContext *ctx, -// AVPacket *pkt, -// CodedBitstreamFragment *frag) { -// AVBufferRef *buf; -// int err; - -// err = ff_cbs_write_fragment_data(ctx, frag); -// if(err < 0) -// return err; - -// buf = av_buffer_ref(frag->data_ref); -// if(!buf) -// return AVERROR(ENOMEM); - -// av_buffer_unref(&pkt->buf); - -// pkt->buf = buf; -// pkt->data = frag->data; -// pkt->size = frag->data_size; - -// return 0; -// } - - -// void ff_cbs_trace_header(CodedBitstreamContext *ctx, -// const char *name) { -// if(!ctx->trace_enable) -// return; - -// av_log(ctx->log_ctx, ctx->trace_level, "%s\n", name); -// } - -// void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, int position, -// const char *str, const int *subscripts, -// const char *bits, int64_t value) { -// char name[256]; -// size_t name_len, bits_len; -// int pad, subs, i, j, k, n; - -// if(!ctx->trace_enable) -// return; - -// av_assert0(value >= INT_MIN && value <= UINT32_MAX); - -// subs = subscripts ? subscripts[0] : 0; -// n = 0; -// for(i = j = 0; str[i];) { -// if(str[i] == '[') { -// if(n < subs) { -// ++n; -// k = snprintf(name + j, sizeof(name) - j, "[%d", subscripts[n]); -// av_assert0(k > 0 && j + k < sizeof(name)); -// j += k; -// for(++i; str[i] && str[i] != ']'; i++) -// ; -// av_assert0(str[i] == ']'); -// } -// else { -// while(str[i] && str[i] != ']') -// name[j++] = str[i++]; -// av_assert0(str[i] == ']'); -// } -// } -// else { -// av_assert0(j + 1 < sizeof(name)); -// name[j++] = str[i++]; -// } -// } -// av_assert0(j + 1 < sizeof(name)); -// name[j] = 0; -// av_assert0(n == subs); - -// name_len = strlen(name); -// bits_len = strlen(bits); - -// if(name_len + bits_len > 60) -// pad = bits_len + 2; -// else -// pad = 61 - name_len; - -// av_log(ctx->log_ctx, ctx->trace_level, "%-10d %s%*s = %" PRId64 "\n", -// position, name, pad, bits, value); -// } - -// int ff_cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc, -// int width, const char *name, -// const int *subscripts, uint32_t *write_to, -// uint32_t range_min, uint32_t range_max) { -// uint32_t value; -// int position; - -// av_assert0(width > 0 && width <= 32); - -// if(get_bits_left(gbc) < width) { -// av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid value at " -// "%s: bitstream ended.\n", -// name); -// return AVERROR_INVALIDDATA; -// } - -// if(ctx->trace_enable) -// position = get_bits_count(gbc); - -// value = get_bits_long(gbc, width); - -// if(ctx->trace_enable) { -// char bits[33]; -// int i; -// for(i = 0; i < width; i++) -// bits[i] = value >> (width - i - 1) & 1 ? '1' : '0'; -// bits[i] = 0; - -// ff_cbs_trace_syntax_element(ctx, position, name, subscripts, -// bits, value); -// } - -// if(value < range_min || value > range_max) { -// av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " -// "%" PRIu32 ", but must be in [%" PRIu32 ",%" PRIu32 "].\n", -// name, value, range_min, range_max); -// return AVERROR_INVALIDDATA; -// } - -// *write_to = value; -// return 0; -// } - -// int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc, -// int width, const char *name, -// const int *subscripts, uint32_t value, -// uint32_t range_min, uint32_t range_max) { -// av_assert0(width > 0 && width <= 32); - -// if(value < range_min || value > range_max) { -// av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " -// "%" PRIu32 ", but must be in [%" PRIu32 ",%" PRIu32 "].\n", -// name, value, range_min, range_max); -// return AVERROR_INVALIDDATA; -// } - -// if(put_bits_left(pbc) < width) -// return AVERROR(ENOSPC); - -// if(ctx->trace_enable) { -// char bits[33]; -// int i; -// for(i = 0; i < width; i++) -// bits[i] = value >> (width - i - 1) & 1 ? '1' : '0'; -// bits[i] = 0; - -// ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), -// name, subscripts, bits, value); -// } - -// if(width < 32) -// put_bits(pbc, width, value); -// else -// put_bits32(pbc, value); - -// return 0; -// } - -// int ff_cbs_read_signed(CodedBitstreamContext *ctx, GetBitContext *gbc, -// int width, const char *name, -// const int *subscripts, int32_t *write_to, -// int32_t range_min, int32_t range_max) { -// int32_t value; -// int position; - -// av_assert0(width > 0 && width <= 32); - -// if(get_bits_left(gbc) < width) { -// av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid value at " -// "%s: bitstream ended.\n", -// name); -// return AVERROR_INVALIDDATA; -// } - -// if(ctx->trace_enable) -// position = get_bits_count(gbc); - -// value = get_sbits_long(gbc, width); - -// if(ctx->trace_enable) { -// char bits[33]; -// int i; -// for(i = 0; i < width; i++) -// bits[i] = value & (1U << (width - i - 1)) ? '1' : '0'; -// bits[i] = 0; - -// ff_cbs_trace_syntax_element(ctx, position, name, subscripts, -// bits, value); -// } - -// if(value < range_min || value > range_max) { -// av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " -// "%" PRId32 ", but must be in [%" PRId32 ",%" PRId32 "].\n", -// name, value, range_min, range_max); -// return AVERROR_INVALIDDATA; -// } - -// *write_to = value; -// return 0; -// } - -// int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc, -// int width, const char *name, -// const int *subscripts, int32_t value, -// int32_t range_min, int32_t range_max) { -// av_assert0(width > 0 && width <= 32); - -// if(value < range_min || value > range_max) { -// av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " -// "%" PRId32 ", but must be in [%" PRId32 ",%" PRId32 "].\n", -// name, value, range_min, range_max); -// return AVERROR_INVALIDDATA; -// } - -// if(put_bits_left(pbc) < width) -// return AVERROR(ENOSPC); - -// if(ctx->trace_enable) { -// char bits[33]; -// int i; -// for(i = 0; i < width; i++) -// bits[i] = value & (1U << (width - i - 1)) ? '1' : '0'; -// bits[i] = 0; - -// ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), -// name, subscripts, bits, value); -// } - -// if(width < 32) -// put_sbits(pbc, width, value); -// else -// put_bits32(pbc, value); - -// return 0; -// } - - -// int ff_cbs_alloc_unit_content(CodedBitstreamUnit *unit, -// size_t size, -// void (*free)(void *opaque, uint8_t *data)) { -// av_assert0(!unit->content && !unit->content_ref); - -// unit->content = av_mallocz(size); -// if(!unit->content) -// return AVERROR(ENOMEM); - -// unit->content_ref = av_buffer_create(unit->content, size, -// free, NULL, 0); -// if(!unit->content_ref) { -// av_freep(&unit->content); -// return AVERROR(ENOMEM); -// } - -// return 0; -// } - -// int ff_cbs_alloc_unit_data(CodedBitstreamUnit *unit, -// size_t size) { -// av_assert0(!unit->data && !unit->data_ref); - -// unit->data_ref = av_buffer_alloc(size + AV_INPUT_BUFFER_PADDING_SIZE); -// if(!unit->data_ref) -// return AVERROR(ENOMEM); - -// unit->data = unit->data_ref->data; -// unit->data_size = size; - -// memset(unit->data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); - -// return 0; -// } - -// static int cbs_insert_unit(CodedBitstreamFragment *frag, -// int position) { -// CodedBitstreamUnit *units; - -// if(frag->nb_units < frag->nb_units_allocated) { -// units = frag->units; - -// if(position < frag->nb_units) -// memmove(units + position + 1, units + position, -// (frag->nb_units - position) * sizeof(*units)); -// } -// else { -// units = av_malloc_array(frag->nb_units * 2 + 1, sizeof(*units)); -// if(!units) -// return AVERROR(ENOMEM); - -// frag->nb_units_allocated = 2 * frag->nb_units_allocated + 1; - -// if(position > 0) -// memcpy(units, frag->units, position * sizeof(*units)); - -// if(position < frag->nb_units) -// memcpy(units + position + 1, frag->units + position, -// (frag->nb_units - position) * sizeof(*units)); -// } - -// memset(units + position, 0, sizeof(*units)); - -// if(units != frag->units) { -// av_free(frag->units); -// frag->units = units; -// } - -// ++frag->nb_units; - -// return 0; -// } - -// int ff_cbs_insert_unit_content(CodedBitstreamFragment *frag, -// int position, -// CodedBitstreamUnitType type, -// void *content, -// AVBufferRef *content_buf) { -// CodedBitstreamUnit *unit; -// AVBufferRef *content_ref; -// int err; - -// if(position == -1) -// position = frag->nb_units; -// av_assert0(position >= 0 && position <= frag->nb_units); - -// if(content_buf) { -// content_ref = av_buffer_ref(content_buf); -// if(!content_ref) -// return AVERROR(ENOMEM); -// } -// else { -// content_ref = NULL; -// } - -// err = cbs_insert_unit(frag, position); -// if(err < 0) { -// av_buffer_unref(&content_ref); -// return err; -// } - -// unit = &frag->units[position]; -// unit->type = type; -// unit->content = content; -// unit->content_ref = content_ref; - -// return 0; -// } - -// int ff_cbs_insert_unit_data(CodedBitstreamFragment *frag, -// int position, -// CodedBitstreamUnitType type, -// uint8_t *data, size_t data_size, -// AVBufferRef *data_buf) { -// CodedBitstreamUnit *unit; -// AVBufferRef *data_ref; -// int err; - -// if(position == -1) -// position = frag->nb_units; -// av_assert0(position >= 0 && position <= frag->nb_units); - -// if(data_buf) -// data_ref = av_buffer_ref(data_buf); -// else -// data_ref = av_buffer_create(data, data_size, NULL, NULL, 0); -// if(!data_ref) { -// if(!data_buf) -// av_free(data); -// return AVERROR(ENOMEM); -// } - -// err = cbs_insert_unit(frag, position); -// if(err < 0) { -// av_buffer_unref(&data_ref); -// return err; -// } - -// unit = &frag->units[position]; -// unit->type = type; -// unit->data = data; -// unit->data_size = data_size; -// unit->data_ref = data_ref; - -// return 0; -// } - -// void ff_cbs_delete_unit(CodedBitstreamFragment *frag, -// int position) { -// av_assert0(0 <= position && position < frag->nb_units && "Unit to be deleted not in fragment."); - -// cbs_unit_uninit(&frag->units[position]); - -// --frag->nb_units; - -// if(frag->nb_units > 0) -// memmove(frag->units + position, -// frag->units + position + 1, -// (frag->nb_units - position) * sizeof(*frag->units)); -// } - -// static void cbs_default_free_unit_content(void *opaque, uint8_t *data) { -// const CodedBitstreamUnitTypeDescriptor *desc = opaque; -// if(desc->content_type == CBS_CONTENT_TYPE_INTERNAL_REFS) { -// int i; -// for(i = 0; i < desc->nb_ref_offsets; i++) { -// void **ptr = (void **)(data + desc->ref_offsets[i]); -// av_buffer_unref((AVBufferRef **)(ptr + 1)); -// } -// } -// av_free(data); -// } - -// static const CodedBitstreamUnitTypeDescriptor -// * -// cbs_find_unit_type_desc(CodedBitstreamContext *ctx, -// CodedBitstreamUnit *unit) { -// const CodedBitstreamUnitTypeDescriptor *desc; -// int i, j; - -// if(!ctx->codec->unit_types) -// return NULL; - -// for(i = 0;; i++) { -// desc = &ctx->codec->unit_types[i]; -// if(desc->nb_unit_types == 0) -// break; -// if(desc->nb_unit_types == CBS_UNIT_TYPE_RANGE) { -// if(unit->type >= desc->unit_type_range_start && -// unit->type <= desc->unit_type_range_end) -// return desc; -// } -// else { -// for(j = 0; j < desc->nb_unit_types; j++) { -// if(desc->unit_types[j] == unit->type) -// return desc; -// } -// } -// } -// return NULL; -// } - -// int ff_cbs_alloc_unit_content2(CodedBitstreamContext *ctx, -// CodedBitstreamUnit *unit) { -// const CodedBitstreamUnitTypeDescriptor *desc; - -// av_assert0(!unit->content && !unit->content_ref); - -// desc = cbs_find_unit_type_desc(ctx, unit); -// if(!desc) -// return AVERROR(ENOSYS); - -// unit->content = av_mallocz(desc->content_size); -// if(!unit->content) -// return AVERROR(ENOMEM); - -// unit->content_ref = -// av_buffer_create(unit->content, desc->content_size, -// desc->content_free ? desc->content_free : cbs_default_free_unit_content, -// (void *)desc, 0); -// if(!unit->content_ref) { -// av_freep(&unit->content); -// return AVERROR(ENOMEM); -// } - -// return 0; -// } - -// static int cbs_clone_unit_content(AVBufferRef **clone_ref, -// CodedBitstreamUnit *unit, -// const CodedBitstreamUnitTypeDescriptor *desc) { -// uint8_t *src, *copy; -// uint8_t **src_ptr, **copy_ptr; -// AVBufferRef **src_buf, **copy_buf; -// int err, i; - -// av_assert0(unit->content); -// src = unit->content; - -// copy = av_memdup(src, desc->content_size); -// if(!copy) -// return AVERROR(ENOMEM); - -// for(i = 0; i < desc->nb_ref_offsets; i++) { -// src_ptr = (uint8_t **)(src + desc->ref_offsets[i]); -// src_buf = (AVBufferRef **)(src_ptr + 1); -// copy_ptr = (uint8_t **)(copy + desc->ref_offsets[i]); -// copy_buf = (AVBufferRef **)(copy_ptr + 1); - -// if(!*src_ptr) { -// av_assert0(!*src_buf); -// continue; -// } -// if(!*src_buf) { -// // We can't handle a non-refcounted pointer here - we don't -// // have enough information to handle whatever structure lies -// // at the other end of it. -// err = AVERROR(EINVAL); -// goto fail; -// } - -// // src_ptr is required to point somewhere inside src_buf. If it -// // doesn't, there is a bug somewhere. -// av_assert0(*src_ptr >= (*src_buf)->data && -// *src_ptr < (*src_buf)->data + (*src_buf)->size); - -// *copy_buf = av_buffer_ref(*src_buf); -// if(!*copy_buf) { -// err = AVERROR(ENOMEM); -// goto fail; -// } -// *copy_ptr = (*copy_buf)->data + (*src_ptr - (*src_buf)->data); -// } - -// *clone_ref = av_buffer_create(copy, desc->content_size, -// desc->content_free ? desc->content_free : -// cbs_default_free_unit_content, -// (void *)desc, 0); -// if(!*clone_ref) { -// err = AVERROR(ENOMEM); -// goto fail; -// } - -// return 0; - -// fail: -// for(--i; i >= 0; i--) -// av_buffer_unref((AVBufferRef **)(copy + desc->ref_offsets[i])); -// av_freep(©); -// *clone_ref = NULL; -// return err; -// } - -// int ff_cbs_make_unit_refcounted(CodedBitstreamContext *ctx, -// CodedBitstreamUnit *unit) { -// const CodedBitstreamUnitTypeDescriptor *desc; -// AVBufferRef *ref; -// int err; - -// av_assert0(unit->content); -// if(unit->content_ref) { -// // Already refcounted, nothing to do. -// return 0; -// } - -// desc = cbs_find_unit_type_desc(ctx, unit); -// if(!desc) -// return AVERROR(ENOSYS); - -// switch(desc->content_type) { -// case CBS_CONTENT_TYPE_POD: -// ref = av_buffer_alloc(desc->content_size); -// if(!ref) -// return AVERROR(ENOMEM); -// memcpy(ref->data, unit->content, desc->content_size); -// err = 0; -// break; - -// case CBS_CONTENT_TYPE_INTERNAL_REFS: -// err = cbs_clone_unit_content(&ref, unit, desc); -// break; - -// case CBS_CONTENT_TYPE_COMPLEX: -// if(!desc->content_clone) -// return AVERROR_PATCHWELCOME; -// err = desc->content_clone(&ref, unit); -// break; - -// default: -// av_assert0(0 && "Invalid content type."); -// } - -// if(err < 0) -// return err; - -// unit->content_ref = ref; -// unit->content = ref->data; -// return 0; -// } - -// int ff_cbs_make_unit_writable(CodedBitstreamContext *ctx, -// CodedBitstreamUnit *unit) { -// const CodedBitstreamUnitTypeDescriptor *desc; -// AVBufferRef *ref; -// int err; - -// // This can only be applied to refcounted units. -// err = ff_cbs_make_unit_refcounted(ctx, unit); -// if(err < 0) -// return err; -// av_assert0(unit->content && unit->content_ref); - -// if(av_buffer_is_writable(unit->content_ref)) -// return 0; - -// desc = cbs_find_unit_type_desc(ctx, unit); -// if(!desc) -// return AVERROR(ENOSYS); - -// switch(desc->content_type) { -// case CBS_CONTENT_TYPE_POD: -// err = av_buffer_make_writable(&unit->content_ref); -// break; - -// case CBS_CONTENT_TYPE_INTERNAL_REFS: -// err = cbs_clone_unit_content(&ref, unit, desc); -// break; - -// case CBS_CONTENT_TYPE_COMPLEX: -// if(!desc->content_clone) -// return AVERROR_PATCHWELCOME; -// err = desc->content_clone(&ref, unit); -// break; - -// default: -// av_assert0(0 && "Invalid content type."); -// } -// if(err < 0) -// return err; - -// if(desc->content_type != CBS_CONTENT_TYPE_POD) { -// av_buffer_unref(&unit->content_ref); -// unit->content_ref = ref; -// } -// unit->content = unit->content_ref->data; -// return 0; -// } - -// const uint8_t ff_log2_tab[256] = { -// 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -// 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, -// 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -// 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, -// 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, -// 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, -// 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, -// 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 -// }; \ No newline at end of file From ea548ac449f612be41348bd90e447ac708a70618 Mon Sep 17 00:00:00 2001 From: Caio Vidal Date: Mon, 28 Feb 2022 11:03:39 -0300 Subject: [PATCH 5/9] revert sunshine.conf --- assets/sunshine.conf | 348 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 318 insertions(+), 30 deletions(-) diff --git a/assets/sunshine.conf b/assets/sunshine.conf index 0543134435d..7987fac987f 100644 --- a/assets/sunshine.conf +++ b/assets/sunshine.conf @@ -1,30 +1,318 @@ -key_rightalt_to_key_win = disabled -gamepad = x360 -upnp = disabled -min_log_level = 2 -origin_pin_allowed = pc -origin_web_ui_allowed = lan -hevc_mode = 0 -qsv_preset = 7 -qsv_cavlc = 1 -nv_preset = default -nv_rc = auto -nv_coder = auto -amd_quality = default -amd_rc = auto -vt_coder = auto -vt_software = auto -vt_realtime = enabled -fps = [10,30,60,90,120] -resolutions = [ - 352x240, - 480x360, - 858x480, - 1280x720, - 1920x1080, - 2560x1080, - 3440x1440, - 1920x1200, - 3860x2160, - 3840x1600 -] +# If no external IP address is given, Sunshine will attempt to automatically detect external ip-address +# external_ip = 123.456.789.12 + +# Set the familly of ports used by Sunshine +# port = 47989 + +# The private key must be 2048 bits +# pkey = /dir/pkey.pem + +# The certificate must be signed with a 2048 bit key +# cert = /dir/cert.pem + +# The name displayed by Moonlight +# If not specified, the PC's hostname is used +# sunshine_name = Sunshine + +# The minimum log level printed to standard out +# +# none -> no logs are printed to standard out +# +# verbose = [0] +# debug = [1] +# info = [2] +# warning = [3] +# error = [4] +# fatal = [5] +# none = [6] +# +# min_log_level = info + +# The origin of the remote endpoint address that is not denied for HTTP method /pin +# Could be any of the following values: +# pc|lan|wan +# pc: Only localhost may access /pin +# lan: Only those in LAN may access /pin +# wan: Anyone may access /pin +# +# origin_pin_allowed = pc + +# The origin of the remote endpoint address that is not denied for HTTPS Web UI +# Could be any of the following values: +# pc|lan|wan +# pc: Only localhost may access the Web Manager +# lan: Only those in LAN may access the Web Manager +# wan: Anyone may access the Web Manager +# +# origin_web_ui_allowed = lan + +# If UPnP is enabled, Sunshine will attempt to open ports for streaming over the internet +# To enable it, uncomment the following line: +# upnp = on + +# The file where current state of Sunshine is stored +# file_state = sunshine_state.json + +# The file where user credentials for the UI are stored +# By default, credentials are stored in `file_state` +# credentials_file = sunshine_state.json + +# The display modes advertised by Sunshine +# +# Some versions of Moonlight, such as Moonlight-nx (Switch), +# rely on this list to ensure that the requested resolutions and fps +# are supported. +# +# fps = [10, 30, 60, 90, 120] +# resolutions = [ +# 352x240, +# 480x360, +# 858x480, +# 1280x720, +# 1920x1080, +# 2560x1080, +# 3440x1440, +# 1920x1200, +# 3860x2160, +# 3840x1600, +# ] + +# Sometimes it may be usefull to map keybindings. +# Wayland won't allow clients to capture the Win Key for example +# +# See https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes +# +# Note: +# keybindings needs to have a multiple of two elements +# keybindings = [ +# 0x10, 0xA0, +# 0x11, 0xA2, +# 0x12, 0xA4, +# 0x4A, 0x4B +# ] + +# It may be possible that you cannot send the Windows Key from Moonlight directly. +# In those cases it may be useful to make Sunshine think the Right Alt key is the Windows key +# key_rightalt_to_key_win = enabled + +# How long to wait in milliseconds for data from moonlight before shutting down the stream +# ping_timeout = 10000 + +# The file where configuration for the different applications that Sunshine can run during a stream +# file_apps = apps.json + +# Percentage of error correcting packets per data packet in each video frame +# Higher values can correct for more network packet loss, but at the cost of increasing bandwidth usage +# The default value of 20 is what GeForce Experience uses +# +# The value must be greater than 0 and lower than or equal to 255 +# fec_percentage = 20 + +# When multicasting, it could be usefull to have different configurations for each connected Client. +# For example: +# Clients connected through WAN and LAN have different bitrate contstraints. +# Decoders may require different settings for color +# +# Unlike simply broadcasting to multiple Client, this will generate distinct video streams. +# Note, CPU usage increases for each distinct video stream generated +# channels = 1 + +# The back/select button on the controller +# On the Shield, the home and powerbutton are not passed to Moonlight +# If, after the timeout, the back button is still pressed down, Home/Guide button press is emulated. +# If back_button_timeout < 0, then the Home/Guide button will not be emulated +# back_button_timeout = 2000 + +# !! Windows only !! +# Gamepads supported by Sunshine +# Possible values: +# x360 -- xbox 360 controller +# ds4 -- dualshock controller (PS4) +# gamepad = x360 + +# Control how fast keys will repeat themselves +# The initial delay in milliseconds before repeating keys +# key_repeat_delay = 500 +# +# How often keys repeat every second +# This configurable option supports decimals +# key_repeat_frequency = 24.9 + +# The name of the audio sink used for Audio Loopback +# If you do not specify this variable, pulseaudio will select the default monitor device. +# +# You can find the name of the audio sink using the following command: +# !! Linux only !! +# pacmd list-sinks | grep "name:" if running vanilla pulseaudio +# pPipewire: Use `pactl info | grep Source`. In some causes you'd need to use the `sink` device. Try `pactl info | grep Sink`, if _Source_ doesn't work +# audio_sink = alsa_output.pci-0000_09_00.3.analog-stereo +# +# !! Windows only !! +# tools\audio-info.exe +# audio_sink = {0.0.0.00000000}.{FD47D9CC-4218-4135-9CE2-0C195C87405B} +# +# The virtual sink, is the audio device that's virtual (Like Steam Streaming Speakers), it allows Sunshine +# to stream audio, while muting the speakers. +# virtual_sink = {0.0.0.00000000}.{8edba70c-1125-467c-b89c-15da389bc1d4} + +# +# !! MacOS only !! +# audio_sink = BlackHole 2ch + +# !! Windows only !! +# You can select the video card you want to stream: +# The appropriate values can be found using the following command: +# tools\dxgi-info.exe +# adapter_name = Radeon RX 580 Series +# output_name = \\.\DISPLAY1 + +# !! Linux only !! +# Set the display number to stream. +# You can find them by the following command: +# xrandr --listmonitors +# Example output: "0: +HDMI-1 1920/518x1200/324+0+0 HDMI-1" +# ^ <-- You need this. +# output_name = 0 + +############################################### +# FFmpeg software encoding parameters +# Honestly, I have no idea what the optimal values would be. +# Play around with this :) + +# Quantitization Parameter +# Some devices don't support Constant Bit Rate. For those devices, QP is used instead +# Higher value means more compression, but less quality +# qp = 28 + +# Minimum number of threads used by ffmpeg to encode the video. +# Increasing the value slightly reduces encoding efficiency, but the tradeoff is usually +# worth it to gain the use of more CPU cores for encoding. The ideal value is the lowest +# value that can reliably encode at your desired streaming settings on your hardware. +# min_threads = 1 + +# Allows the client to request HEVC Main or HEVC Main10 video streams. +# HEVC is more CPU-intensive to encode, so enabling this may reduce performance when using software encoding. +# If set to 0 (default), Sunshine will specify support for HEVC based on encoder +# If set to 1, Sunshine will not advertise support for HEVC +# If set to 2, Sunshine will advertise support for HEVC Main profile +# If set to 3, Sunshine will advertise support for HEVC Main and Main10 (HDR) profiles +# hevc_mode = 2 + +# Force a specific encoder, otherwise Sunshine will use the first encoder that is available +# supported encoders: +# nvenc +# amdvce # NOTE: alpha stage. The cursor is not yet displayed +# software +# +# encoder = nvenc +##################################### Software ##################################### +# See x264 --fullhelp for the different presets +# sw_preset = superfast +# sw_tune = zerolatency +# + +##################################### NVENC ##################################### +###### presets ########### +# default +# hp -- high performance +# hq -- high quality +# slow -- hq 2 passes +# medium -- hq 1 pass +# fast -- hp 1 pass +# bd +# ll -- low latency +# llhq +# llhp +# lossless +# losslesshp +########################## +# nv_preset = llhq +# +####### rate control ##### +# auto -- let ffmpeg decide rate control +# constqp -- constant QP mode +# vbr -- variable bitrate +# cbr -- constant bitrate +# cbr_hq -- cbr high quality +# cbr_ld_hq -- cbr low delay high quality +# vbr_hq -- vbr high quality +########################## +# nv_rc = auto + +###### h264 entropy ###### +# auto -- let ffmpeg nvenc decide the entropy encoding +# cabac +# cavlc +########################## +# nv_coder = auto + +##################################### AMD ##################################### +###### presets ########### +# default +# speed +# balanced +########################## +# amd_quality = balanced +# +####### rate control ##### +# auto -- let ffmpeg decide rate control +# constqp -- constant QP mode +# vbr_latency -- Latency Constrained Variable Bitrate +# vbr_peak -- Peak Contrained Variable Bitrate +# cbr -- constant bitrate +########################## +# amd_rc = auto + +###### h264 entropy ###### +# auto -- let ffmpeg nvenc decide the entropy encoding +# cabac +# cavlc +########################## +# amd_coder = auto + +#################################### VAAPI ################################### +####### adapter ########## +# Unlike with `amdvce` and `nvenc`, it doesn't matter if video encoding is done +# on a different GPU. +# Run the following commands: +# 1. ls /dev/dri/renderD* +# to find all devices capable of VAAPI +# 2. vainfo --display drm --device /dev/dri/renderD129 | grep -E "((VAProfileH264High|VAProfileHEVCMain|VAProfileHEVCMain10).*VAEntrypointEncSlice)|Driver version" +# Lists the name and capabilities of the device. +# To be supported by Sunshine, it needs to have at the very minimum: +# VAProfileH264High : VAEntrypointEncSlice +# adapter_name = /dev/dri/renderD128 + +################################# VideoToolbox ############################### +####### software encoding ########## +# Video Toolbox can be allowed/required to use software encoding instead of +# hardware accelerated encoding. +# auto -- let sunshine decide on encoding +# disabled -- disable software encoding +# allowed -- allow software encoding +# forced -- force software encoding +########################## +# vt_software = auto +# +####### realtime encoding ########## +# Disabling realtime encoding might result in a delayed frame encoding or frame drop +########################## +# vt_realtime = enabled +# +###### h264/hevc entropy ###### +# auto -- let ffmpeg decide the entropy encoding +# cabac +# cavlc +########################## +# vt_coder = auto + + +############################################## +# Some configurable parameters, are merely toggles for specific features +# The first occurrence turns it on, the second occurence turns it off, the third occurence turns it on again, etc, etc +# Here, you change the default state of any flag +# +# To set the initial state of flags -0 and -1 to on, set the following flags: +# flags = 012 +# +# See: sunshine --help for all options under the header: flags \ No newline at end of file From d93971c8bf171b89a11c3c6a8665cfd34f0cc64c Mon Sep 17 00:00:00 2001 From: Caio Vidal Date: Thu, 3 Mar 2022 10:39:47 -0300 Subject: [PATCH 6/9] qsv support --- sunshine/video.cpp | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/sunshine/video.cpp b/sunshine/video.cpp index 6fdf0e18edd..6c949bd2fda 100644 --- a/sunshine/video.cpp +++ b/sunshine/video.cpp @@ -22,6 +22,7 @@ extern "C" { #ifdef _WIN32 extern "C" { #include +#include } #endif @@ -81,7 +82,7 @@ class swdevice_t : public platf::hwdevice_t { int convert(platf::img_t &img) override { av_frame_make_writable(sw_frame.get()); - const int linesizes[2] { + const int linesizes[2] { img.row_pitch, 0 }; @@ -486,21 +487,20 @@ static encoder_t quicksync { { { { "forced-idr"s, 1 }, - { "preset"s, &config::video.qsv.preset }, + { "preset"s, &config::video.qsv.preset }, }, std::make_optional({ "qp"s, &config::video.qp }), "hevc_qsv"s, }, { { - { "preset"s, &config::video.qsv.preset }, - { "cavlc"s, &config::video.qsv.cavlc }, - + { "preset"s, &config::video.qsv.preset }, + { "cavlc"s, &config::video.qsv.cavlc } }, std::make_optional({ "qp"s, &config::video.qp }), "h264_qsv"s, }, - H264_ONLY, + H264_ONLY | PARALLEL_ENCODING, qsv_make_hwdevice_ctx }; #endif @@ -526,9 +526,9 @@ static encoder_t software { "libx265"s, }, { - { + { { "preset"s, &config::video.sw.preset }, - { "tune"s, &config::video.sw.tune }, + { "tune"s, &config::video.sw.tune } }, std::make_optional("qp"s, &config::video.qp), "libx264"s, @@ -801,7 +801,7 @@ int encode(int64_t frame_nr, session_t &session, frame_t::pointer frame, safe::m } while(ret >= 0) { - auto packet = std::make_unique(nullptr); + auto packet = std::make_unique(nullptr); ret = avcodec_receive_packet(ctx.get(), packet.get()); if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { @@ -1062,6 +1062,9 @@ std::optional make_session(const encoder_t &encoder, const config_t & if(!video_format[encoder_t::NALU_PREFIX_5b]) { auto nalu_prefix = config.videoFormat ? hevc_nalu : h264_nalu; + session.replacements.emplace_back("\000\000\000\001\'"sv, "\000\000\000\001g"sv); //sps + session.replacements.emplace_back("\000\000\000\001("sv, "\000\000\000\001h"sv); //pps + session.replacements.emplace_back("\000\000\001%"sv, "\000\000\001e"sv); //idr session.replacements.emplace_back(nalu_prefix.substr(1), nalu_prefix); } @@ -1809,7 +1812,11 @@ util::Either qsv_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ct AVBufferRef *hw_device_ctx = NULL; - auto err = av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_QSV, NULL, NULL, 0); + AVDictionary *child_device_opts = NULL; + + av_dict_set(&child_device_opts, "child_device_type", "d3d11va", 0); + + auto err = av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_QSV, "d3d11va", child_device_opts, 0); if(err) { char err_str[AV_ERROR_MAX_STRING_SIZE] { 0 }; From 11dd4139b2ccbbd4fbd0250e6164c435bf97f035 Mon Sep 17 00:00:00 2001 From: Caio Vidal Date: Sat, 5 Mar 2022 12:20:00 -0300 Subject: [PATCH 7/9] force idr frames --- sunshine/video.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sunshine/video.cpp b/sunshine/video.cpp index 6c949bd2fda..28e240be738 100644 --- a/sunshine/video.cpp +++ b/sunshine/video.cpp @@ -486,7 +486,7 @@ static encoder_t quicksync { AV_PIX_FMT_NV12, AV_PIX_FMT_P010, { { - { "forced-idr"s, 1 }, + { "forced_idr"s, "1" }, { "preset"s, &config::video.qsv.preset }, }, std::make_optional({ "qp"s, &config::video.qp }), @@ -495,12 +495,13 @@ static encoder_t quicksync { { { { "preset"s, &config::video.qsv.preset }, - { "cavlc"s, &config::video.qsv.cavlc } + { "cavlc"s, &config::video.qsv.cavlc }, + { "forced_idr"s, "1" }, }, std::make_optional({ "qp"s, &config::video.qp }), "h264_qsv"s, }, - H264_ONLY | PARALLEL_ENCODING, + PARALLEL_ENCODING, qsv_make_hwdevice_ctx }; #endif From 5b3665230fc53afb649868ebdf9320ebfacb0f7f Mon Sep 17 00:00:00 2001 From: Caio Vidal Date: Thu, 10 Mar 2022 08:13:07 -0300 Subject: [PATCH 8/9] Add child device opt --- assets/web/config.html | 2 +- sunshine/video.cpp | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/assets/web/config.html b/assets/web/config.html index 0e65988aa2f..47f1bd661da 100644 --- a/assets/web/config.html +++ b/assets/web/config.html @@ -392,7 +392,7 @@

Configuration

v-model="config.output_name" />
- You can select the video card you want to stream:
+ You can select the display you want to stream:
The appropriate values can be found using the following command:
tools\dxgi-info.exe

diff --git a/sunshine/video.cpp b/sunshine/video.cpp index 28e240be738..a0a6c86d1c5 100644 --- a/sunshine/video.cpp +++ b/sunshine/video.cpp @@ -82,7 +82,7 @@ class swdevice_t : public platf::hwdevice_t { int convert(platf::img_t &img) override { av_frame_make_writable(sw_frame.get()); - const int linesizes[2] { + const int linesizes[2] { img.row_pitch, 0 }; @@ -497,6 +497,7 @@ static encoder_t quicksync { { "preset"s, &config::video.qsv.preset }, { "cavlc"s, &config::video.qsv.cavlc }, { "forced_idr"s, "1" }, + //{ "async_depth"s, "1" } }, std::make_optional({ "qp"s, &config::video.qp }), "h264_qsv"s, @@ -527,10 +528,8 @@ static encoder_t software { "libx265"s, }, { - { - { "preset"s, &config::video.sw.preset }, - { "tune"s, &config::video.sw.tune } - }, + { { "preset"s, &config::video.sw.preset }, + { "tune"s, &config::video.sw.tune } }, std::make_optional("qp"s, &config::video.qp), "libx264"s, }, @@ -1813,11 +1812,13 @@ util::Either qsv_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ct AVBufferRef *hw_device_ctx = NULL; - AVDictionary *child_device_opts = NULL; + AVDictionary *child_device_opts = NULL; + + av_dict_set(&child_device_opts, "child_device", "1", 0); + av_dict_set(&child_device_opts, "child_device_type", "d3d11va", 0); - av_dict_set(&child_device_opts, "child_device_type", "d3d11va", 0); - auto err = av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_QSV, "d3d11va", child_device_opts, 0); + auto err = av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_QSV, NULL, child_device_opts, 0); if(err) { char err_str[AV_ERROR_MAX_STRING_SIZE] { 0 }; From 72274709ff49d1dd47874c1cb2e11d382c7019c1 Mon Sep 17 00:00:00 2001 From: Caio Vidal Date: Thu, 10 Mar 2022 16:30:20 -0300 Subject: [PATCH 9/9] Add child device config to qsv encoder --- assets/web/config.html | 15 +++++++++++ sunshine/config.cpp | 9 ++++--- sunshine/config.h | 1 + sunshine/video.cpp | 56 ++++++++++++++++++++++++++---------------- 4 files changed, 57 insertions(+), 24 deletions(-) diff --git a/assets/web/config.html b/assets/web/config.html index 47f1bd661da..737f60a71f3 100644 --- a/assets/web/config.html +++ b/assets/web/config.html @@ -653,6 +653,21 @@

Configuration

+
+ + +
+ You can select your intel device index:
+ Usually 0 or 1
+
+
+
diff --git a/sunshine/config.cpp b/sunshine/config.cpp index 188ff0e35d8..876f3cd5f01 100644 --- a/sunshine/config.cpp +++ b/sunshine/config.cpp @@ -1,8 +1,10 @@ #include +#include #include #include #include #include +#include #include #include @@ -175,7 +177,7 @@ enum preset_e : int { }; enum cavlc_e : int { - _auto = false, + _auto = false, enabled = true, disabled = false }; @@ -228,14 +230,14 @@ video_t video { "superfast"s, // preset "zerolatency"s, // tune }, // software - { nv::llhq, std::nullopt, -1 }, // nv { qsv::medium, - qsv::disabled }, //qsv + qsv::disabled, + "" }, //qsv { amd::balanced, std::nullopt, std::nullopt, @@ -734,6 +736,7 @@ void apply_config(std::unordered_map &&vars) { int_f(vars, "qsv_preset", video.qsv.preset); int_f(vars, "qsv_cavlc", video.qsv.cavlc); + string_f(vars, "qsv_child_device", video.qsv.child_device); int_f(vars, "amd_quality", video.amd.quality, amd::quality_from_view); diff --git a/sunshine/config.h b/sunshine/config.h index d8e43166a2f..c416d2db8b5 100644 --- a/sunshine/config.h +++ b/sunshine/config.h @@ -30,6 +30,7 @@ struct video_t { struct { std::optional preset; std::optional cavlc; + std::string child_device; } qsv; struct { diff --git a/sunshine/video.cpp b/sunshine/video.cpp index a0a6c86d1c5..ae599dfd3ad 100644 --- a/sunshine/video.cpp +++ b/sunshine/video.cpp @@ -75,7 +75,6 @@ util::Either vaapi_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ util::Either cuda_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ctx); util::Either qsv_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ctx); -int hwframe_ctx(ctx_t &ctx, buffer_t &hwdevice, AVPixelFormat format); class swdevice_t : public platf::hwdevice_t { public: @@ -321,8 +320,12 @@ struct encoder_t { int flags; std::function(platf::hwdevice_t *hwdevice)> make_hwdevice_ctx; + int hwframe_initial_pool_size; }; +int hwframe_ctx(ctx_t &ctx, buffer_t &hwdevice, AVPixelFormat format, const encoder_t &encoder); + + class session_t { public: session_t() = default; @@ -443,6 +446,8 @@ static encoder_t nvenc { PARALLEL_ENCODING, cuda_make_hwdevice_ctx #endif + , + -1 }; #ifdef _WIN32 @@ -474,7 +479,8 @@ static encoder_t amdvce { "h264_amf"s, }, DEFAULT, - dxgi_make_hwdevice_ctx + dxgi_make_hwdevice_ctx, + -1 }; @@ -503,7 +509,8 @@ static encoder_t quicksync { "h264_qsv"s, }, PARALLEL_ENCODING, - qsv_make_hwdevice_ctx + qsv_make_hwdevice_ctx, + 20 }; #endif @@ -535,7 +542,9 @@ static encoder_t software { }, H264_ONLY | PARALLEL_ENCODING, - nullptr + nullptr, + -1 + }; #ifdef __linux__ @@ -563,7 +572,8 @@ static encoder_t vaapi { }, LIMITED_GOP_SIZE | PARALLEL_ENCODING | SINGLE_SLICE_ONLY, - vaapi_make_hwdevice_ctx + vaapi_make_hwdevice_ctx, + nullptr }; #endif @@ -594,6 +604,7 @@ static encoder_t videotoolbox { }, DEFAULT, + nullptr, nullptr }; #endif @@ -957,7 +968,7 @@ std::optional make_session(const encoder_t &encoder, const config_t & } hwdevice_ctx = std::move(buf_or_error.left()); - if(hwframe_ctx(ctx, hwdevice_ctx, sw_fmt)) { + if(hwframe_ctx(ctx, hwdevice_ctx, sw_fmt, encoder)) { return std::nullopt; } @@ -1717,15 +1728,18 @@ int init() { return 0; } -int hwframe_ctx(ctx_t &ctx, buffer_t &hwdevice, AVPixelFormat format) { +int hwframe_ctx(ctx_t &ctx, buffer_t &hwdevice, AVPixelFormat format, const encoder_t &encoder) { buffer_t frame_ref { av_hwframe_ctx_alloc(hwdevice.get()) }; - auto frame_ctx = (AVHWFramesContext *)frame_ref->data; - frame_ctx->format = ctx->pix_fmt; - frame_ctx->sw_format = format; - frame_ctx->height = ctx->height; - frame_ctx->width = ctx->width; - frame_ctx->initial_pool_size = 20; + auto frame_ctx = (AVHWFramesContext *)frame_ref->data; + frame_ctx->format = ctx->pix_fmt; + frame_ctx->sw_format = format; + frame_ctx->height = ctx->height; + frame_ctx->width = ctx->width; + + if(encoder.hwframe_initial_pool_size >= 0) { + frame_ctx->initial_pool_size = encoder.hwframe_initial_pool_size; + } if(auto err = av_hwframe_ctx_init(frame_ref.get()); err < 0) { return err; @@ -1737,14 +1751,14 @@ int hwframe_ctx(ctx_t &ctx, buffer_t &hwdevice, AVPixelFormat format) { } // Linux only declaration -typedef int (*vaapi_make_hwdevice_ctx_fn)(platf::hwdevice_t *base, AVBufferRef **hw_device_buf); +typedef int (*vaapi_make_hwdevice_ctx_fn)(platf::hwdevice_t *hwdevice_ctx, AVBufferRef **hw_device_buf); -util::Either vaapi_make_hwdevice_ctx(platf::hwdevice_t *base) { +util::Either vaapi_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ctx) { buffer_t hw_device_buf; // If an egl hwdevice - if(base->data) { - if(((vaapi_make_hwdevice_ctx_fn)base->data)(base, &hw_device_buf)) { + if(hwdevice_ctx->data) { + if(((vaapi_make_hwdevice_ctx_fn)hwdevice_ctx->data)(hwdevice_ctx, &hw_device_buf)) { return -1; } @@ -1763,7 +1777,7 @@ util::Either vaapi_make_hwdevice_ctx(platf::hwdevice_t *base) { return hw_device_buf; } -util::Either cuda_make_hwdevice_ctx(platf::hwdevice_t *base) { +util::Either cuda_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ctx) { buffer_t hw_device_buf; auto status = av_hwdevice_ctx_create(&hw_device_buf, AV_HWDEVICE_TYPE_CUDA, nullptr, nullptr, 1 /* AV_CUDA_USE_PRIMARY_CONTEXT */); @@ -1814,9 +1828,9 @@ util::Either qsv_make_hwdevice_ctx(platf::hwdevice_t *hwdevice_ct AVDictionary *child_device_opts = NULL; - av_dict_set(&child_device_opts, "child_device", "1", 0); - av_dict_set(&child_device_opts, "child_device_type", "d3d11va", 0); - + if(!config::video.qsv.child_device.empty()) { + av_dict_set(&child_device_opts, "child_device", config::video.qsv.child_device.data(), 0); + } auto err = av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_QSV, NULL, child_device_opts, 0);