Skip to content

Commit 1b24471

Browse files
committed
avcodec/nvenc: split interlaced output field slices
Signed-off-by: Timo Rothenpieler <timo@rothenpieler.org>
1 parent b8a5930 commit 1b24471

File tree

2 files changed

+104
-3
lines changed

2 files changed

+104
-3
lines changed

libavcodec/nvenc.c

Lines changed: 102 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121

2222
#include "config.h"
2323

24+
#include "h2645_parse.h"
25+
#include "h264.h"
2426
#include "nvenc.h"
2527

2628
#include "libavutil/hwcontext_cuda.h"
@@ -1073,6 +1075,15 @@ static av_cold int nvenc_setup_encoder(AVCodecContext *avctx)
10731075
ctx->init_encode_params.frameRateNum = avctx->time_base.den;
10741076
ctx->init_encode_params.frameRateDen = avctx->time_base.num * avctx->ticks_per_frame;
10751077

1078+
/* if (avctx->ticks_per_frame == 1) {
1079+
if(avctx->time_base.den < INT_MAX/2) {
1080+
avctx->time_base.den *= 2;
1081+
} else {
1082+
avctx->time_base.num /= 2;
1083+
}
1084+
avctx->ticks_per_frame = 2;
1085+
} */
1086+
10761087
ctx->init_encode_params.enableEncodeAsync = 0;
10771088
ctx->init_encode_params.enablePTD = 1;
10781089

@@ -1678,6 +1689,55 @@ static int nvenc_set_timestamp(AVCodecContext *avctx,
16781689
return 0;
16791690
}
16801691

1692+
static int get_second_slice_offset(AVCodecContext *avctx, const uint8_t *buf, int length, int *offset)
1693+
{
1694+
NvencContext *ctx = avctx->priv_data;
1695+
1696+
H2645Packet h2645_pkt = { 0 };
1697+
int idx = -1, count = 0, slice_count = 0;
1698+
int i, res;
1699+
1700+
// NVENC does not support HEVC interlaced encoding, so don't even bother.
1701+
if (avctx->codec->id != AV_CODEC_ID_H264 || ctx->encode_config.frameFieldMode != NV_ENC_PARAMS_FRAME_FIELD_MODE_FIELD) {
1702+
*offset = 0;
1703+
return 0;
1704+
}
1705+
1706+
res = ff_h2645_packet_split(&h2645_pkt, buf, length, avctx, 0, 0, avctx->codec->id, 1);
1707+
if (res < 0)
1708+
return res;
1709+
1710+
for (i = 0; i < h2645_pkt.nb_nals; i++)
1711+
if (h2645_pkt.nals[i].type == H264_NAL_SLICE || h2645_pkt.nals[i].type == H264_NAL_IDR_SLICE)
1712+
slice_count++;
1713+
1714+
if (slice_count < 2)
1715+
goto fail;
1716+
1717+
for (i = 0; i < h2645_pkt.nb_nals; i++) {
1718+
if (h2645_pkt.nals[i].type == H264_NAL_SLICE || h2645_pkt.nals[i].type == H264_NAL_IDR_SLICE) {
1719+
if (++count == slice_count / 2) {
1720+
idx = i;
1721+
break;
1722+
}
1723+
}
1724+
}
1725+
1726+
if (i >= h2645_pkt.nb_nals || idx < 0)
1727+
goto fail;
1728+
1729+
*offset = h2645_pkt.nals[idx + 1].raw_data - 4 - buf;
1730+
1731+
ff_h2645_packet_uninit(&h2645_pkt);
1732+
1733+
return 0;
1734+
1735+
fail:
1736+
ff_h2645_packet_uninit(&h2645_pkt);
1737+
*offset = 0;
1738+
return 0;
1739+
}
1740+
16811741
static int process_output_surface(AVCodecContext *avctx, AVPacket *pkt, NvencSurface *tmpoutsurf)
16821742
{
16831743
NvencContext *ctx = avctx->priv_data;
@@ -1688,10 +1748,16 @@ static int process_output_surface(AVCodecContext *avctx, AVPacket *pkt, NvencSur
16881748
uint32_t *slice_offsets = NULL;
16891749
NV_ENC_LOCK_BITSTREAM lock_params = { 0 };
16901750
NVENCSTATUS nv_status;
1751+
int main_size, second_slice_offset = -1;
16911752
int res = 0;
16921753

16931754
enum AVPictureType pict_type;
16941755

1756+
if (ctx->extra_packet) {
1757+
av_log(avctx, AV_LOG_ERROR, "extra_packet already allocated!\n");
1758+
return AVERROR_BUG;
1759+
}
1760+
16951761
switch (avctx->codec->id) {
16961762
case AV_CODEC_ID_H264:
16971763
slice_mode_data = ctx->encode_config.encodeCodecConfig.h264Config.sliceModeData * 2;
@@ -1721,12 +1787,32 @@ static int process_output_surface(AVCodecContext *avctx, AVPacket *pkt, NvencSur
17211787
goto error;
17221788
}
17231789

1724-
if (res = ff_alloc_packet2(avctx, pkt, lock_params.bitstreamSizeInBytes, 0)) {
1790+
res = get_second_slice_offset(avctx, lock_params.bitstreamBufferPtr, lock_params.bitstreamSizeInBytes, &second_slice_offset);
1791+
if (res < 0)
1792+
goto error;
1793+
1794+
main_size = second_slice_offset > 0 ? second_slice_offset : lock_params.bitstreamSizeInBytes;
1795+
1796+
if (res = ff_alloc_packet2(avctx, pkt, main_size, 0)) {
17251797
p_nvenc->nvEncUnlockBitstream(ctx->nvencoder, tmpoutsurf->output_surface);
17261798
goto error;
17271799
}
17281800

1729-
memcpy(pkt->data, lock_params.bitstreamBufferPtr, lock_params.bitstreamSizeInBytes);
1801+
memcpy(pkt->data, lock_params.bitstreamBufferPtr, main_size);
1802+
1803+
if (second_slice_offset > 0) {
1804+
ctx->extra_packet = av_packet_alloc();
1805+
if (!ctx->extra_packet) {
1806+
res = AVERROR(ENOMEM);
1807+
goto error;
1808+
}
1809+
1810+
res = av_new_packet(ctx->extra_packet, lock_params.bitstreamSizeInBytes - second_slice_offset);
1811+
if (res < 0)
1812+
goto error;
1813+
1814+
memcpy(ctx->extra_packet->data, (uint8_t*)lock_params.bitstreamBufferPtr + second_slice_offset, ctx->extra_packet->size);
1815+
}
17301816

17311817
nv_status = p_nvenc->nvEncUnlockBitstream(ctx->nvencoder, tmpoutsurf->output_surface);
17321818
if (nv_status != NV_ENC_SUCCESS)
@@ -1776,6 +1862,15 @@ FF_ENABLE_DEPRECATION_WARNINGS
17761862
if (res < 0)
17771863
goto error2;
17781864

1865+
if (ctx->extra_packet) {
1866+
//TODO: The timebase needs to be fixed(if ticks_per_frame == 1).
1867+
ctx->extra_packet->dts = AV_NOPTS_VALUE;
1868+
ctx->extra_packet->pts = AV_NOPTS_VALUE;
1869+
1870+
ff_side_data_set_encoder_stats(ctx->extra_packet,
1871+
(lock_params.frameAvgQP - 1) * FF_QP2LAMBDA, NULL, 0, pict_type);
1872+
}
1873+
17791874
av_free(slice_offsets);
17801875

17811876
return 0;
@@ -1933,7 +2028,11 @@ int ff_nvenc_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
19332028
if (!ctx->cu_context || !ctx->nvencoder)
19342029
return AVERROR(EINVAL);
19352030

1936-
if (output_ready(avctx, ctx->encoder_flushing)) {
2031+
if (ctx->extra_packet) {
2032+
av_packet_move_ref(pkt, ctx->extra_packet);
2033+
av_packet_free(&ctx->extra_packet);
2034+
return 0;
2035+
} else if (output_ready(avctx, ctx->encoder_flushing)) {
19372036
av_fifo_generic_read(ctx->output_surface_ready_queue, &tmp_out_surf, sizeof(tmp_out_surf), NULL);
19382037

19392038
cu_res = dl_fn->cuda_dl->cuCtxPushCurrent(ctx->cu_context);

libavcodec/nvenc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ typedef struct NvencContext
118118

119119
int encoder_flushing;
120120

121+
AVPacket *extra_packet;
122+
121123
struct {
122124
CUdeviceptr ptr;
123125
NV_ENC_REGISTERED_PTR regptr;

0 commit comments

Comments
 (0)