Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ffmpeg: Improve Cgo logging #214

Merged
merged 2 commits into from
Nov 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 34 additions & 61 deletions ffmpeg/decoder.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "transcoder.h"
#include "decoder.h"
#include "logging.h"

#include <libavutil/pixfmt.h>

Expand Down Expand Up @@ -27,19 +28,14 @@ static void send_first_pkt(struct input_ctx *ictx)

int ret = avcodec_send_packet(ictx->vc, ictx->first_pkt);
if (ret < 0) {
char errstr[AV_ERROR_MAX_STRING_SIZE];
av_strerror(ret, errstr, sizeof errstr);
fprintf(stderr, "Error sending flush packet : %s\n", errstr);
LPMS_ERR(packet_cleanup, "Error sending flush packet");
} else ictx->sentinel_count++;
packet_cleanup:
return;
}

int process_in(struct input_ctx *ictx, AVFrame *frame, AVPacket *pkt)
{
#define dec_err(msg) { \
if (!ret) ret = -1; \
fprintf(stderr, "dec_cleanup: "msg); \
goto dec_cleanup; \
}
int ret = 0;

// Read a packet and attempt to decode it.
Expand All @@ -50,7 +46,7 @@ int process_in(struct input_ctx *ictx, AVFrame *frame, AVPacket *pkt)
AVCodecContext *decoder = NULL;
ret = av_read_frame(ictx->ic, pkt);
if (ret == AVERROR_EOF) goto dec_flush;
else if (ret < 0) dec_err("Unable to read input\n");
else if (ret < 0) LPMS_ERR(dec_cleanup, "Unable to read input");
ist = ictx->ic->streams[pkt->stream_index];
if (ist->index == ictx->vi && ictx->vc) decoder = ictx->vc;
else if (ist->index == ictx->ai && ictx->ac) decoder = ictx->ac;
Expand All @@ -63,15 +59,15 @@ int process_in(struct input_ctx *ictx, AVFrame *frame, AVPacket *pkt)
}

ret = lpms_send_packet(ictx, decoder, pkt);
if (ret < 0) dec_err("Error sending packet to decoder\n");
if (ret < 0) LPMS_ERR(dec_cleanup, "Error sending packet to decoder");
ret = lpms_receive_frame(ictx, decoder, frame);
if (ret == AVERROR(EAGAIN)) {
// Distinguish from EAGAIN that may occur with
// av_read_frame or avcodec_send_packet
ret = lpms_ERR_PACKET_ONLY;
break;
}
else if (ret < 0) dec_err("Error receiving frame from decoder\n");
else if (ret < 0) LPMS_ERR(dec_cleanup, "Error receiving frame from decoder");
break;

drop_packet:
Expand Down Expand Up @@ -113,8 +109,6 @@ int process_in(struct input_ctx *ictx, AVFrame *frame, AVPacket *pkt)
if (!ret) return ret;
}
return AVERROR_EOF;

#undef dec_err
}

// FIXME: name me and the other function better
Expand All @@ -125,7 +119,7 @@ enum AVPixelFormat hw2pixfmt(AVCodecContext *ctx)
for (int i = 0;; i++) {
const AVCodecHWConfig *config = avcodec_get_hw_config(decoder, i);
if (!config) {
fprintf(stderr, "Decoder %s does not support hw decoding\n", decoder->name);
LPMS_WARN("Decoder does not support hw decoding");
return AV_PIX_FMT_NONE;
}
if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX &&
Expand All @@ -142,17 +136,14 @@ enum AVPixelFormat hw2pixfmt(AVCodecContext *ctx)
static enum AVPixelFormat get_hw_pixfmt(AVCodecContext *vc, const enum AVPixelFormat *pix_fmts)
{
AVHWFramesContext *frames;
int ret;
int ret = 0;

// XXX Ideally this would be auto initialized by the HW device ctx
// However the initialization doesn't occur in time to set up filters
// So we do it here. Also see avcodec_get_hw_frames_parameters
av_buffer_unref(&vc->hw_frames_ctx);
vc->hw_frames_ctx = av_hwframe_ctx_alloc(vc->hw_device_ctx);
if (!vc->hw_frames_ctx) {
fprintf(stderr, "Unable to allocate hwframe context for decoding\n");
return AV_PIX_FMT_NONE;
}
if (!vc->hw_frames_ctx) LPMS_ERR(pixfmt_cleanup, "Unable to allocate hwframe context for decoding");

frames = (AVHWFramesContext*)vc->hw_frames_ctx->data;
frames->format = hw2pixfmt(vc);
Expand All @@ -167,10 +158,7 @@ static enum AVPixelFormat get_hw_pixfmt(AVCodecContext *vc, const enum AVPixelFo

ret = av_hwframe_ctx_init(vc->hw_frames_ctx);
if (AVERROR(ENOSYS) == ret) ret = lpms_ERR_INPUT_PIXFMT; // most likely
if (ret < 0) {
fprintf(stderr,"Unable to initialize a hardware frame pool\n");
return AV_PIX_FMT_NONE;
}
if (ret < 0) LPMS_ERR(pixfmt_cleanup, "Unable to initialize a hardware frame pool");

/*
fprintf(stderr, "selected format: hw %s sw %s\n",
Expand All @@ -182,16 +170,14 @@ fprintf(stderr,"possible format: %s\n", av_get_pix_fmt_name(*p));
*/

return frames->format;

pixfmt_cleanup:
return AV_PIX_FMT_NONE;
}


int open_audio_decoder(input_params *params, struct input_ctx *ctx)
{
#define ad_err(msg) { \
if (!ret) ret = -1; \
fprintf(stderr, msg); \
goto open_audio_err; \
}
int ret = 0;
AVCodec *codec = NULL;
AVFormatContext *ic = ctx->ic;
Expand All @@ -200,33 +186,27 @@ int open_audio_decoder(input_params *params, struct input_ctx *ctx)
ctx->ai = av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO, -1, -1, &codec, 0);
if (ctx->da) ; // skip decoding audio
else if (ctx->ai < 0) {
fprintf(stderr, "No audio stream found in input\n");
LPMS_INFO("No audio stream found in input");
} else {
AVCodecContext * ac = avcodec_alloc_context3(codec);
if (!ac) ad_err("Unable to alloc audio codec\n");
if (ctx->ac) fprintf(stderr, "Audio context already open! %p\n", ctx->ac);
if (!ac) LPMS_ERR(open_audio_err, "Unable to alloc audio codec");
if (ctx->ac) LPMS_WARN("An audio context was already open!");
ctx->ac = ac;
ret = avcodec_parameters_to_context(ac, ic->streams[ctx->ai]->codecpar);
if (ret < 0) ad_err("Unable to assign audio params\n");
if (ret < 0) LPMS_ERR(open_audio_err, "Unable to assign audio params");
ret = avcodec_open2(ac, codec, NULL);
if (ret < 0) ad_err("Unable to open audio decoder\n");
if (ret < 0) LPMS_ERR(open_audio_err, "Unable to open audio decoder");
}

return 0;

open_audio_err:
free_input(ctx);
return ret;
#undef ad_err
}

int open_video_decoder(input_params *params, struct input_ctx *ctx)
{
#define dd_err(msg) { \
if (!ret) ret = -1; \
fprintf(stderr, msg); \
goto open_decoder_err; \
}
int ret = 0;
AVCodec *codec = NULL;
AVFormatContext *ic = ctx->ic;
Expand All @@ -235,84 +215,77 @@ int open_video_decoder(input_params *params, struct input_ctx *ctx)
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) {
fprintf(stderr, "No video stream found in input\n");
LPMS_WARN("No video stream found in input");
} else {
if (AV_HWDEVICE_TYPE_CUDA == params->hw_type) {
if (AV_CODEC_ID_H264 != codec->id) {
ret = lpms_ERR_INPUT_CODEC;
dd_err("Non H264 codec detected in input\n");
LPMS_ERR(open_decoder_err, "Non H264 codec detected in input");
}
AVCodec *c = avcodec_find_decoder_by_name("h264_cuvid");
if (c) codec = c;
else fprintf(stderr, "Cuvid decoder not found; defaulting to software\n");
else LPMS_WARN("Nvidia decoder not found; defaulting to software");
if (AV_PIX_FMT_YUV420P != ic->streams[ctx->vi]->codecpar->format &&
AV_PIX_FMT_YUVJ420P != ic->streams[ctx->vi]->codecpar->format) {
// TODO check whether the color range is truncated if yuvj420p is used
ret = lpms_ERR_INPUT_PIXFMT;
dd_err("Non 4:2:0 pixel format detected in input\n");
LPMS_ERR(open_decoder_err, "Non 4:2:0 pixel format detected in input");
}
}
AVCodecContext *vc = avcodec_alloc_context3(codec);
if (!vc) dd_err("Unable to alloc video codec\n");
if (!vc) LPMS_ERR(open_decoder_err, "Unable to alloc video codec");
ctx->vc = vc;
ret = avcodec_parameters_to_context(vc, ic->streams[ctx->vi]->codecpar);
if (ret < 0) dd_err("Unable to assign video params\n");
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_NONE) {
// 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) dd_err("Unable to open hardware context for decoding\n")
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;
}
vc->pkt_timebase = ic->streams[ctx->vi]->time_base;
ret = avcodec_open2(vc, codec, NULL);
if (ret < 0) dd_err("Unable to open video decoder\n");
if (ret < 0) LPMS_ERR(open_decoder_err, "Unable to open video decoder");
}

return 0;

open_decoder_err:
free_input(ctx);
return ret;
#undef dd_err
}

int open_input(input_params *params, struct input_ctx *ctx)
{
#define dd_err(msg) { \
if (!ret) ret = -1; \
fprintf(stderr, msg); \
goto open_input_err; \
}
AVFormatContext *ic = NULL;
char *inp = params->fname;
int ret = 0;

// open demuxer
ret = avformat_open_input(&ic, inp, NULL, NULL);
if (ret < 0) dd_err("demuxer: Unable to open input\n");
if (ret < 0) LPMS_ERR(open_input_err, "demuxer: Unable to open input");
ctx->ic = ic;
ret = avformat_find_stream_info(ic, NULL);
if (ret < 0) dd_err("Unable to find input info\n");
if (ret < 0) LPMS_ERR(open_input_err, "Unable to find input info");
ret = open_video_decoder(params, ctx);
if (ret < 0) dd_err("Unable to open video decoder\n")
if (ret < 0) LPMS_ERR(open_input_err, "Unable to open video decoder")
ret = open_audio_decoder(params, ctx);
if (ret < 0) dd_err("Unable to open audio decoder\n")
if (ret < 0) LPMS_ERR(open_input_err, "Unable to open audio decoder")
ctx->last_frame_v = av_frame_alloc();
if (!ctx->last_frame_v) dd_err("Unable to alloc last_frame_v");
if (!ctx->last_frame_v) LPMS_ERR(open_input_err, "Unable to alloc last_frame_v");
ctx->last_frame_a = av_frame_alloc();
if (!ctx->last_frame_a) dd_err("Unable to alloc last_frame_a");
if (!ctx->last_frame_a) LPMS_ERR(open_input_err, "Unable to alloc last_frame_a");

return 0;

open_input_err:
fprintf(stderr, "Freeing input based on OPEN INPUT error\n");
LPMS_INFO("Freeing input based on OPEN INPUT error");
free_input(ctx);
return ret;
#undef dd_err
}

void free_input(struct input_ctx *inctx)
Expand Down
Loading