Skip to content

Commit

Permalink
Perf commit
Browse files Browse the repository at this point in the history
  • Loading branch information
cyberj0g committed Feb 23, 2022
1 parent febc417 commit d18200f
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 420 deletions.
66 changes: 23 additions & 43 deletions ffmpeg/decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ int process_in(struct input_ctx *ictx, AVFrame *frame, AVPacket *pkt)

// Read a packet and attempt to decode it.
// If decoding was not possible, return the packet anyway for streamcopy
av_packet_unref(pkt);
av_init_packet(pkt);
while (1) {
AVStream *ist = NULL;
AVCodecContext *decoder = NULL;
Expand Down Expand Up @@ -92,25 +92,22 @@ int process_in(struct input_ctx *ictx, AVFrame *frame, AVPacket *pkt)
// get back all sent frames, or we've made SENTINEL_MAX attempts to retrieve
// buffered frames with no success.
// TODO this is unnecessary for SW decoding! SW process should match audio
// last stable with Netint:
//if (ictx->hw_type != AV_HWDEVICE_TYPE_MEDIACODEC) {
if (ictx->vc && !ictx->flushed && ictx->pkt_diff > 0) {
ictx->flushing = 1;
ret = send_first_pkt(ictx);
if (ret < 0) {
ictx->flushed = 1;
return ret;
}
ret = lpms_receive_frame(ictx, ictx->vc, frame);
pkt->stream_index = ictx->vi;
// Keep flushing if we haven't received all frames back but stop after SENTINEL_MAX tries.
if (ictx->pkt_diff != 0 && ictx->sentinel_count <= SENTINEL_MAX && (!ret || ret == AVERROR(EAGAIN))) {
return 0; // ignore actual return value and keep flushing
} else {
ictx->flushed = 1;
}
}
//}
if (ictx->vc && !ictx->flushed && ictx->pkt_diff > 0) {
ictx->flushing = 1;
ret = send_first_pkt(ictx);
if (ret < 0) {
ictx->flushed = 1;
return ret;
}
ret = lpms_receive_frame(ictx, ictx->vc, frame);
pkt->stream_index = ictx->vi;
// Keep flushing if we haven't received all frames back but stop after SENTINEL_MAX tries.
if (ictx->pkt_diff != 0 && ictx->sentinel_count <= SENTINEL_MAX && (!ret || ret == AVERROR(EAGAIN))) {
return 0; // ignore actual return value and keep flushing
} else {
ictx->flushed = 1;
}
}
// Flush audio decoder.
if (ictx->ac) {
avcodec_send_packet(ictx->ac, NULL);
Expand Down Expand Up @@ -215,41 +212,25 @@ int open_audio_decoder(input_params *params, struct input_ctx *ctx)
return ret;
}

char* get_hw_decoder(int ff_codec_id)
{
switch (ff_codec_id) {
case AV_CODEC_ID_H264:
return "h264_cuvid";
case AV_CODEC_ID_HEVC:
return "hevc_cuvid";
case AV_CODEC_ID_VP8:
return "vp8_cuvid";
case AV_CODEC_ID_VP9:
return "vp9_cuvid";
default:
return "";
}
}

int open_video_decoder(input_params *params, struct input_ctx *ctx)
{
int ret = 0;
AVCodec *codec = NULL;
AVDictionary **opts = NULL;
AVFormatContext *ic = ctx->ic;

// open video decoder
ctx->vi = av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0);
if (ctx->dv) ; // skip decoding video
else if (ctx->vi < 0) {
LPMS_WARN("No video stream found in input");
} else {
if (AV_HWDEVICE_TYPE_CUDA == params->hw_type) {
char* decoder_name = get_hw_decoder(codec->id);
if (!*decoder_name) {
if (AV_CODEC_ID_H264 != codec->id) {
ret = lpms_ERR_INPUT_CODEC;
LPMS_ERR(open_decoder_err, "Input codec does not support hardware acceleration");
LPMS_ERR(open_decoder_err, "Non H264 codec detected in input");
}
AVCodec *c = avcodec_find_decoder_by_name(decoder_name);
AVCodec *c = avcodec_find_decoder_by_name("h264_cuvid");
if (c) codec = c;
else LPMS_WARN("Nvidia decoder not found; defaulting to software");
if (AV_PIX_FMT_YUV420P != ic->streams[ctx->vi]->codecpar->format &&
Expand All @@ -272,14 +253,14 @@ int open_video_decoder(input_params *params, struct input_ctx *ctx)
if (ret < 0) LPMS_ERR(open_decoder_err, "Unable to assign video params");
vc->opaque = (void*)ctx;
// XXX Could this break if the original device falls out of scope in golang?
if (params->hw_type == AV_HWDEVICE_TYPE_CUDA) {
if (params->hw_type != AV_HWDEVICE_TYPE_MEDIACODEC) {
// First set the hw device then set the hw frame
ret = av_hwdevice_ctx_create(&ctx->hw_device_ctx, params->hw_type, params->device, NULL, 0);
if (ret < 0) LPMS_ERR(open_decoder_err, "Unable to open hardware context for decoding")
ctx->hw_type = params->hw_type;
vc->hw_device_ctx = av_buffer_ref(ctx->hw_device_ctx);
vc->get_format = get_hw_pixfmt;
}
ctx->hw_type = params->hw_type;
vc->pkt_timebase = ic->streams[ctx->vi]->time_base;
av_opt_set(vc->priv_data, "xcoder-params", ctx->xcoderParams, 0);
ret = avcodec_open2(vc, codec, opts);
Expand All @@ -290,7 +271,6 @@ int open_video_decoder(input_params *params, struct input_ctx *ctx)

open_decoder_err:
free_input(ctx);
if (ret == AVERROR_UNKNOWN) ret = lpms_ERR_UNRECOVERABLE;
return ret;
}

Expand Down
18 changes: 6 additions & 12 deletions ffmpeg/decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
#include "transcoder.h"

struct input_ctx {
Expand Down Expand Up @@ -38,20 +37,16 @@ struct input_ctx {

// transmuxing specific fields:
// last non-zero duration
int64_t last_duration[MAX_OUTPUT_SIZE];
// keep track of last dts in each stream.
// used while transmuxing, to skip packets with invalid dts.
int64_t last_dts[MAX_OUTPUT_SIZE];
int64_t last_duration;
//
int64_t dts_diff[MAX_OUTPUT_SIZE];
int64_t last_dts;
//
int discontinuity[MAX_OUTPUT_SIZE];
int64_t dts_diff;
//
int discontinuity;
// Transmuxing mode. Close output in lpms_transcode_stop instead of
// at the end of lpms_transcode call.
int transmuxing;
// In HW transcoding, demuxer is opened once and used,
// so it is necessary to check whether the input pixel format does not change in the middle.
enum AVPixelFormat last_format;
};

// Exported methods
Expand All @@ -60,11 +55,10 @@ enum AVPixelFormat hw2pixfmt(AVCodecContext *ctx);
int open_input(input_params *params, struct input_ctx *ctx);
int open_video_decoder(input_params *params, struct input_ctx *ctx);
int open_audio_decoder(input_params *params, struct input_ctx *ctx);
char* get_hw_decoder(int ff_codec_id);
void free_input(struct input_ctx *inctx);

// Utility functions
static inline int is_flush_frame(AVFrame *frame)
inline int is_flush_frame(AVFrame *frame)
{
return -1 == frame->pts;
}
Expand Down
Loading

0 comments on commit d18200f

Please sign in to comment.