--- libavcodec/nvenc.c | 187 ++++++++++++++--------------------------------------- 1 file changed, 50 insertions(+), 137 deletions(-)
diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c index 19312dc..d3856a4 100644 --- a/libavcodec/nvenc.c +++ b/libavcodec/nvenc.c @@ -27,6 +27,7 @@ #include <nvEncodeAPI.h> +#include "libavutil/fifo.h" #include "libavutil/internal.h" #include "libavutil/imgutils.h" #include "libavutil/avassert.h" @@ -89,15 +90,6 @@ typedef struct NvencData } u; } NvencData; -typedef struct NvencDataList -{ - NvencData* data; - - uint32_t pos; - uint32_t count; - uint32_t size; -} NvencDataList; - typedef struct NvencDynLoadFunctions { PCUINIT cu_init; @@ -141,9 +133,9 @@ typedef struct NvencContext int max_surface_count; NvencSurface *surfaces; - NvencDataList output_surface_queue; - NvencDataList output_surface_ready_queue; - NvencDataList timestamp_list; + AVFifoBuffer *output_surface_queue; + AVFifoBuffer *output_surface_ready_queue; + AVFifoBuffer *timestamp_list; int64_t last_dts; void *nvencoder; @@ -279,105 +271,18 @@ static int input_string_to_uint32(AVCodecContext *avctx, const NvencValuePair *p return AVERROR(EINVAL); } -static NvencData* data_queue_dequeue(NvencDataList* queue) -{ - uint32_t mask; - uint32_t read_pos; - - av_assert0(queue); - av_assert0(queue->size); - av_assert0(queue->data); - - if (!queue->count) - return NULL; - - /* Size always is a multiple of two */ - mask = queue->size - 1; - read_pos = (queue->pos - queue->count) & mask; - queue->count--; - - return &queue->data[read_pos]; -} - -static int data_queue_enqueue(NvencDataList* queue, NvencData *data) -{ - NvencDataList new_queue; - NvencData* tmp_data; - uint32_t mask; - - if (!queue->size) { - /* size always has to be a multiple of two */ - queue->size = 4; - queue->pos = 0; - queue->count = 0; - - queue->data = av_malloc(queue->size * sizeof(*(queue->data))); - - if (!queue->data) { - queue->size = 0; - return AVERROR(ENOMEM); - } - } - - if (queue->count == queue->size) { - new_queue.size = queue->size << 1; - new_queue.pos = 0; - new_queue.count = 0; - new_queue.data = av_malloc(new_queue.size * sizeof(*(queue->data))); - - if (!new_queue.data) - return AVERROR(ENOMEM); - - while (tmp_data = data_queue_dequeue(queue)) - data_queue_enqueue(&new_queue, tmp_data); - - av_free(queue->data); - *queue = new_queue; - } - - mask = queue->size - 1; - - queue->data[queue->pos] = *data; - queue->pos = (queue->pos + 1) & mask; - queue->count++; - - return 0; -} - -static int out_surf_queue_enqueue(NvencDataList* queue, NvencSurface* surface) -{ - NvencData data; - data.u.surface = surface; - - return data_queue_enqueue(queue, &data); -} - -static NvencSurface* out_surf_queue_dequeue(NvencDataList* queue) +static void timestamp_queue_enqueue(AVFifoBuffer* queue, int64_t timestamp) { - NvencData* res = data_queue_dequeue(queue); - - if (!res) - return NULL; - - return res->u.surface; + av_fifo_generic_write(queue, ×tamp, sizeof(timestamp), NULL); } -static int timestamp_queue_enqueue(NvencDataList* queue, int64_t timestamp) +static int64_t timestamp_queue_dequeue(AVFifoBuffer* queue) { - NvencData data; - data.u.timestamp = timestamp; + int64_t timestamp = AV_NOPTS_VALUE; + if (av_fifo_size(queue) > 0) + av_fifo_generic_read(queue, ×tamp, sizeof(timestamp), NULL); - return data_queue_enqueue(queue, &data); -} - -static int64_t timestamp_queue_dequeue(NvencDataList* queue) -{ - NvencData* res = data_queue_dequeue(queue); - - if (!res) - return AV_NOPTS_VALUE; - - return res->u.timestamp; + return timestamp; } #define CHECK_LOAD_FUNC(t, f, s) \ @@ -1218,6 +1123,16 @@ static av_cold int nvenc_setup_surfaces(AVCodecContext *avctx, int* surfaceCount return AVERROR(ENOMEM); } + ctx->timestamp_list = av_fifo_alloc(ctx->max_surface_count * sizeof(int64_t)); + if (!ctx->timestamp_list) + return AVERROR(ENOMEM); + ctx->output_surface_queue = av_fifo_alloc(ctx->max_surface_count * sizeof(NvencSurface*)); + if (!ctx->output_surface_queue) + return AVERROR(ENOMEM); + ctx->output_surface_ready_queue = av_fifo_alloc(ctx->max_surface_count * sizeof(NvencSurface*)); + if (!ctx->output_surface_ready_queue) + return AVERROR(ENOMEM); + for(*surfaceCount = 0; *surfaceCount < ctx->max_surface_count; ++*surfaceCount) { res = nvenc_alloc_surface(avctx, *surfaceCount); if (res) @@ -1298,11 +1213,15 @@ static av_cold int nvenc_encode_init(AVCodecContext *avctx) return 0; error: + av_fifo_freep(&ctx->timestamp_list); + av_fifo_freep(&ctx->output_surface_ready_queue); + av_fifo_freep(&ctx->output_surface_queue); for (i = 0; i < surfaceCount; ++i) { p_nvenc->nvEncDestroyInputBuffer(ctx->nvencoder, ctx->surfaces[i].input_surface); p_nvenc->nvEncDestroyBitstreamBuffer(ctx->nvencoder, ctx->surfaces[i].output_surface); } + av_freep(&ctx->surfaces); if (ctx->nvencoder) p_nvenc->nvEncDestroyEncoder(ctx->nvencoder); @@ -1325,14 +1244,15 @@ static av_cold int nvenc_encode_close(AVCodecContext *avctx) NV_ENCODE_API_FUNCTION_LIST *p_nvenc = &dl_fn->nvenc_funcs; int i; - av_freep(&ctx->timestamp_list.data); - av_freep(&ctx->output_surface_ready_queue.data); - av_freep(&ctx->output_surface_queue.data); + av_fifo_freep(&ctx->timestamp_list); + av_fifo_freep(&ctx->output_surface_ready_queue); + av_fifo_freep(&ctx->output_surface_queue); for (i = 0; i < ctx->max_surface_count; ++i) { p_nvenc->nvEncDestroyInputBuffer(ctx->nvencoder, ctx->surfaces[i].input_surface); p_nvenc->nvEncDestroyBitstreamBuffer(ctx->nvencoder, ctx->surfaces[i].output_surface); } + av_freep(&ctx->surfaces); ctx->max_surface_count = 0; p_nvenc->nvEncDestroyEncoder(ctx->nvencoder); @@ -1548,7 +1468,7 @@ FF_ENABLE_DEPRECATION_WARNINGS (lock_params.frameAvgQP - 1) * FF_QP2LAMBDA, NULL, 0, pict_type); pkt->pts = lock_params.outputTimeStamp; - pkt->dts = timestamp_queue_dequeue(&ctx->timestamp_list); + pkt->dts = timestamp_queue_dequeue(ctx->timestamp_list); /* when there're b frame(s), set dts offset */ if (ctx->encode_config.frameIntervalP >= 2) @@ -1569,11 +1489,20 @@ FF_ENABLE_DEPRECATION_WARNINGS error: av_free(slice_offsets); - timestamp_queue_dequeue(&ctx->timestamp_list); + timestamp_queue_dequeue(ctx->timestamp_list); return res; } +static int output_ready(NvencContext *ctx, int flush) +{ + int nb_ready, nb_pending; + + nb_ready = av_fifo_size(ctx->output_surface_ready_queue) / sizeof(NvencSurface*); + nb_pending = av_fifo_size(ctx->output_surface_queue) / sizeof(NvencSurface*); + return nb_ready > 0 && (flush || nb_ready + nb_pending >= ctx->buffer_delay); +} + static int nvenc_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *frame, int *got_packet) { @@ -1621,48 +1550,32 @@ static int nvenc_encode_frame(AVCodecContext *avctx, AVPacket *pkt, nvenc_codec_specific_pic_params(avctx, &pic_params); - res = timestamp_queue_enqueue(&ctx->timestamp_list, frame->pts); - - if (res) { - inSurf->lockCount = 0; - return res; - } + timestamp_queue_enqueue(ctx->timestamp_list, frame->pts); } else { pic_params.encodePicFlags = NV_ENC_PIC_FLAG_EOS; } nv_status = p_nvenc->nvEncEncodePicture(ctx->nvencoder, &pic_params); - if (frame && nv_status == NV_ENC_ERR_NEED_MORE_INPUT) { - res = out_surf_queue_enqueue(&ctx->output_surface_queue, inSurf); - - if (res) - return res; - } + if (frame && nv_status == NV_ENC_ERR_NEED_MORE_INPUT) + av_fifo_generic_write(ctx->output_surface_queue, &inSurf, sizeof(inSurf), NULL); if (nv_status != NV_ENC_SUCCESS && nv_status != NV_ENC_ERR_NEED_MORE_INPUT) { return nvenc_print_error(avctx, nv_status, "EncodePicture failed!"); } if (nv_status != NV_ENC_ERR_NEED_MORE_INPUT) { - while (ctx->output_surface_queue.count) { - tmpoutsurf = out_surf_queue_dequeue(&ctx->output_surface_queue); - res = out_surf_queue_enqueue(&ctx->output_surface_ready_queue, tmpoutsurf); - - if (res) - return res; + while (av_fifo_size(ctx->output_surface_queue) > 0) { + av_fifo_generic_read(ctx->output_surface_queue, &tmpoutsurf, sizeof(tmpoutsurf), NULL); + av_fifo_generic_write(ctx->output_surface_ready_queue, &tmpoutsurf, sizeof(tmpoutsurf), NULL); } - if (frame) { - res = out_surf_queue_enqueue(&ctx->output_surface_ready_queue, inSurf); - - if (res) - return res; - } + if (frame) + av_fifo_generic_write(ctx->output_surface_ready_queue, &inSurf, sizeof(inSurf), NULL); } - if (ctx->output_surface_ready_queue.count && (!frame || ctx->output_surface_ready_queue.count + ctx->output_surface_queue.count >= ctx->buffer_delay)) { - tmpoutsurf = out_surf_queue_dequeue(&ctx->output_surface_ready_queue); + if (output_ready(ctx, !frame)) { + av_fifo_generic_read(ctx->output_surface_ready_queue, &tmpoutsurf, sizeof(tmpoutsurf), NULL); res = process_output_surface(avctx, pkt, tmpoutsurf);
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel