From ebba1d8af1e99e91bce2fc8696feb62a3bd1ab4e Mon Sep 17 00:00:00 2001 From: Jai Luthra Date: Sat, 21 Nov 2020 04:34:36 +0530 Subject: [PATCH 1/2] ffmpeg: Improve Cgo logging --- ffmpeg/decoder.c | 95 ++++++++++++------------------- ffmpeg/encoder.c | 132 ++++++++++++++------------------------------ ffmpeg/filter.c | 65 ++++++++-------------- ffmpeg/logging.h | 22 ++++++++ ffmpeg/transcoder.c | 36 +++++------- 5 files changed, 137 insertions(+), 213 deletions(-) create mode 100644 ffmpeg/logging.h diff --git a/ffmpeg/decoder.c b/ffmpeg/decoder.c index c72552dd41..5b5fd2c9ac 100644 --- a/ffmpeg/decoder.c +++ b/ffmpeg/decoder.c @@ -1,5 +1,6 @@ #include "transcoder.h" #include "decoder.h" +#include "logging.h" #include @@ -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. @@ -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; @@ -63,7 +59,7 @@ 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 @@ -71,7 +67,7 @@ int process_in(struct input_ctx *ictx, AVFrame *frame, AVPacket *pkt) 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: @@ -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 @@ -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 && @@ -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); @@ -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", @@ -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; @@ -200,16 +186,16 @@ 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; @@ -217,16 +203,10 @@ int open_audio_decoder(input_params *params, struct input_ctx *ctx) 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; @@ -235,41 +215,41 @@ 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; @@ -277,42 +257,35 @@ int open_video_decoder(input_params *params, struct input_ctx *ctx) 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) diff --git a/ffmpeg/encoder.c b/ffmpeg/encoder.c index 1c57485d6f..43d4086f2b 100644 --- a/ffmpeg/encoder.c +++ b/ffmpeg/encoder.c @@ -1,4 +1,5 @@ #include "encoder.h" +#include "logging.h" #include #include @@ -6,24 +7,18 @@ static int add_video_stream(struct output_ctx *octx, struct input_ctx *ictx) { -#define vs_err(msg) { \ - if (!ret) ret = -1; \ - fprintf(stderr, "Error adding video stream: " msg); \ - goto add_video_err; \ -} - // video stream to muxer int ret = 0; AVStream *st = avformat_new_stream(octx->oc, NULL); - if (!st) vs_err("Unable to alloc video stream\n"); + if (!st) LPMS_ERR(add_video_err, "Unable to alloc video stream"); octx->vi = st->index; st->avg_frame_rate = octx->fps; if (is_copy(octx->video->name)) { AVStream *ist = ictx->ic->streams[ictx->vi]; - if (ictx->vi < 0 || !ist) vs_err("Input video stream does not exist\n"); + if (ictx->vi < 0 || !ist) LPMS_ERR(add_video_err, "Input video stream does not exist"); st->time_base = ist->time_base; ret = avcodec_parameters_copy(st->codecpar, ist->codecpar); - if (ret < 0) vs_err("Error copying video params from input stream\n"); + if (ret < 0) LPMS_ERR(add_video_err, "Error copying video params from input stream"); // Sometimes the codec tag is wonky for some reason, so correct it ret = av_codec_get_tag2(octx->oc->oformat->codec_tag, st->codecpar->codec_id, &st->codecpar->codec_tag); avformat_transfer_internal_stream_timing_info(octx->oc->oformat, st, ist, AVFMT_TBCF_DEMUXER); @@ -41,24 +36,17 @@ static int add_video_stream(struct output_ctx *octx, struct input_ctx *ictx) octx->gop_pts_len = av_rescale_q(octx->gop_time, gop_tb, dest_tb); octx->next_kf_pts = 0; // force for first frame } - if (ret < 0) vs_err("Error setting video params from encoder\n"); - } else vs_err("No video encoder, not a copy; what is this?\n"); + if (ret < 0) LPMS_ERR(add_video_err, "Error setting video params from encoder"); + } else LPMS_ERR(add_video_err, "No video encoder, not a copy; what is this?"); return 0; add_video_err: // XXX free anything here? return ret; -#undef vs_err } static int add_audio_stream(struct input_ctx *ictx, struct output_ctx *octx) { -#define as_err(msg) { \ - if (!ret) ret = -1; \ - fprintf(stderr, "Error adding audio stream: " msg); \ - goto add_audio_err; \ -} - if (ictx->ai < 0 || octx->da) { // Don't need to add an audio stream if no input audio exists, // or we're dropping the output audio stream @@ -68,25 +56,25 @@ static int add_audio_stream(struct input_ctx *ictx, struct output_ctx *octx) // audio stream to muxer int ret = 0; AVStream *st = avformat_new_stream(octx->oc, NULL); - if (!st) as_err("Unable to alloc audio stream\n"); + if (!st) LPMS_ERR(add_audio_err, "Unable to alloc audio stream"); if (is_copy(octx->audio->name)) { AVStream *ist = ictx->ic->streams[ictx->ai]; - if (ictx->ai < 0 || !ist) as_err("Input audio stream does not exist\n"); + if (ictx->ai < 0 || !ist) LPMS_ERR(add_audio_err, "Input audio stream does not exist"); st->time_base = ist->time_base; ret = avcodec_parameters_copy(st->codecpar, ist->codecpar); - if (ret < 0) as_err("Error copying audio params from input stream\n"); + if (ret < 0) LPMS_ERR(add_audio_err, "Error copying audio params from input stream"); // Sometimes the codec tag is wonky for some reason, so correct it ret = av_codec_get_tag2(octx->oc->oformat->codec_tag, st->codecpar->codec_id, &st->codecpar->codec_tag); avformat_transfer_internal_stream_timing_info(octx->oc->oformat, st, ist, AVFMT_TBCF_DEMUXER); } else if (octx->ac) { st->time_base = octx->ac->time_base; ret = avcodec_parameters_from_context(st->codecpar, octx->ac); - if (ret < 0) as_err("Error setting audio params from encoder\n"); + if (ret < 0) LPMS_ERR(add_audio_err, "Error setting audio params from encoder"); } else if (is_drop(octx->audio->name)) { // Supposed to exit this function early if there's a drop - as_err("Shouldn't ever happen here\n"); + LPMS_ERR(add_audio_err, "Shouldn't ever happen here"); } else { - as_err("No audio encoder; not a copy; what is this?\n"); + LPMS_ERR(add_audio_err, "No audio encoder; not a copy; what is this?"); } octx->ai = st->index; @@ -97,18 +85,11 @@ static int add_audio_stream(struct input_ctx *ictx, struct output_ctx *octx) add_audio_err: // XXX free anything here? return ret; -#undef as_err } static int open_audio_output(struct input_ctx *ictx, struct output_ctx *octx, AVOutputFormat *fmt) { -#define ao_err(msg) { \ - if (!ret) ret = -1; \ - fprintf(stderr, msg"\n"); \ - goto audio_output_err; \ -} - int ret = 0; AVCodec *codec = NULL; AVCodecContext *ac = NULL; @@ -118,14 +99,14 @@ static int open_audio_output(struct input_ctx *ictx, struct output_ctx *octx, // initialize audio filters ret = init_audio_filters(ictx, octx); - if (ret < 0) ao_err("Unable to open audio filter") + if (ret < 0) LPMS_ERR(audio_output_err, "Unable to open audio filter") // open encoder codec = avcodec_find_encoder_by_name(octx->audio->name); - if (!codec) ao_err("Unable to find audio encoder"); + if (!codec) LPMS_ERR(audio_output_err, "Unable to find audio encoder"); // open audio encoder ac = avcodec_alloc_context3(codec); - if (!ac) ao_err("Unable to alloc audio encoder"); + if (!ac) LPMS_ERR(audio_output_err, "Unable to alloc audio encoder"); octx->ac = ac; ac->sample_fmt = av_buffersink_get_format(octx->af.sink_ctx); ac->channel_layout = av_buffersink_get_channel_layout(octx->af.sink_ctx); @@ -134,18 +115,16 @@ static int open_audio_output(struct input_ctx *ictx, struct output_ctx *octx, ac->time_base = av_buffersink_get_time_base(octx->af.sink_ctx); if (fmt->flags & AVFMT_GLOBALHEADER) ac->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; ret = avcodec_open2(ac, codec, &octx->audio->opts); - if (ret < 0) ao_err("Error opening audio encoder"); + if (ret < 0) LPMS_ERR(audio_output_err, "Error opening audio encoder"); av_buffersink_set_frame_size(octx->af.sink_ctx, ac->frame_size); } ret = add_audio_stream(ictx, octx); - if (ret < 0) ao_err("Error adding audio stream") + if (ret < 0) LPMS_ERR(audio_output_err, "Error adding audio stream") audio_output_err: // TODO clean up anything here? return ret; - -#undef ao_err } void close_output(struct output_ctx *octx) @@ -174,11 +153,6 @@ void free_output(struct output_ctx *octx) int open_output(struct output_ctx *octx, struct input_ctx *ictx) { -#define em_err(msg) { \ - if (!ret) ret = -1; \ - fprintf(stderr, msg); \ - goto open_output_err; \ -} int ret = 0, inp_has_stream; AVOutputFormat *fmt = NULL; @@ -188,23 +162,23 @@ int open_output(struct output_ctx *octx, struct input_ctx *ictx) // open muxer fmt = av_guess_format(octx->muxer->name, octx->fname, NULL); - if (!fmt) em_err("Unable to guess output format\n"); + if (!fmt) LPMS_ERR(open_output_err, "Unable to guess output format"); ret = avformat_alloc_output_context2(&oc, fmt, NULL, octx->fname); - if (ret < 0) em_err("Unable to alloc output context\n"); + if (ret < 0) LPMS_ERR(open_output_err, "Unable to alloc output context"); octx->oc = oc; // add video encoder if a decoder exists and this output requires one if (ictx->vc && needs_decoder(octx->video->name)) { ret = init_video_filters(ictx, octx); - if (ret < 0) em_err("Unable to open video filter"); + if (ret < 0) LPMS_ERR(open_output_err, "Unable to open video filter"); codec = avcodec_find_encoder_by_name(octx->video->name); - if (!codec) em_err("Unable to find encoder"); + if (!codec) LPMS_ERR(open_output_err, "Unable to find encoder"); // open video encoder // XXX use avoptions rather than manual enumeration vc = avcodec_alloc_context3(codec); - if (!vc) em_err("Unable to alloc video encoder\n"); + if (!vc) LPMS_ERR(open_output_err, "Unable to alloc video encoder"); octx->vc = vc; vc->width = av_buffersink_get_w(octx->vf.sink_ctx); vc->height = av_buffersink_get_h(octx->vf.sink_ctx); @@ -217,12 +191,12 @@ int open_output(struct output_ctx *octx, struct input_ctx *ictx) if (av_buffersink_get_hw_frames_ctx(octx->vf.sink_ctx)) { vc->hw_frames_ctx = av_buffer_ref(av_buffersink_get_hw_frames_ctx(octx->vf.sink_ctx)); - if (!vc->hw_frames_ctx) em_err("Unable to alloc hardware context\n"); + if (!vc->hw_frames_ctx) LPMS_ERR(open_output_err, "Unable to alloc hardware context"); } vc->pix_fmt = av_buffersink_get_format(octx->vf.sink_ctx); // XXX select based on encoder + input support if (fmt->flags & AVFMT_GLOBALHEADER) vc->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; ret = avcodec_open2(vc, codec, &octx->video->opts); - if (ret < 0) em_err("Error opening video encoder\n"); + if (ret < 0) LPMS_ERR(open_output_err, "Error opening video encoder"); octx->hw_type = ictx->hw_type; } @@ -230,71 +204,59 @@ int open_output(struct output_ctx *octx, struct input_ctx *ictx) inp_has_stream = ictx->vi >= 0; if (inp_has_stream && !octx->dv) { ret = add_video_stream(octx, ictx); - if (ret < 0) em_err("Error adding video stream\n"); + if (ret < 0) LPMS_ERR(open_output_err, "Error adding video stream"); } ret = open_audio_output(ictx, octx, fmt); - if (ret < 0) em_err("Error opening audio output\n"); + if (ret < 0) LPMS_ERR(open_output_err, "Error opening audio output"); if (!(fmt->flags & AVFMT_NOFILE)) { ret = avio_open(&octx->oc->pb, octx->fname, AVIO_FLAG_WRITE); - if (ret < 0) em_err("Error opening output file\n"); + if (ret < 0) LPMS_ERR(open_output_err, "Error opening output file"); } ret = avformat_write_header(oc, &octx->muxer->opts); - if (ret < 0) em_err("Error writing header\n"); + if (ret < 0) LPMS_ERR(open_output_err, "Error writing header"); return 0; open_output_err: free_output(octx); return ret; -#undef em_err } int reopen_output(struct output_ctx *octx, struct input_ctx *ictx) { -#define ro_err(msg) { \ - if (!ret) ret = -1; \ - fprintf(stderr, msg); \ - return ret; \ -} int ret = 0; // re-open muxer for HW encoding AVOutputFormat *fmt = av_guess_format(octx->muxer->name, octx->fname, NULL); - if (!fmt) ro_err("Unable to guess format for reopen\n"); + if (!fmt) LPMS_ERR(reopen_out_err, "Unable to guess format for reopen"); ret = avformat_alloc_output_context2(&octx->oc, fmt, NULL, octx->fname); - if (ret < 0) ro_err("Unable to alloc reopened out context\n"); + if (ret < 0) LPMS_ERR(reopen_out_err, "Unable to alloc reopened out context"); // re-attach video encoder if (octx->vc) { ret = add_video_stream(octx, ictx); - if (ret < 0) ro_err("Unable to re-add video stream\n"); - } else fprintf(stderr, "no video stream\n"); + if (ret < 0) LPMS_ERR(reopen_out_err, "Unable to re-add video stream"); + } else LPMS_INFO("No video stream!?"); // re-attach audio encoder ret = open_audio_output(ictx, octx, fmt); - if (ret < 0) ro_err("Unable to re-add audio stream\n"); + if (ret < 0) LPMS_ERR(reopen_out_err, "Unable to re-add audio stream"); if (!(fmt->flags & AVFMT_NOFILE)) { ret = avio_open(&octx->oc->pb, octx->fname, AVIO_FLAG_WRITE); - if (ret < 0) ro_err("Error re-opening output file\n"); + if (ret < 0) LPMS_ERR(reopen_out_err, "Error re-opening output file"); } ret = avformat_write_header(octx->oc, &octx->muxer->opts); - if (ret < 0) ro_err("Error re-writing header\n"); - return ret; -#undef ro_err -} + if (ret < 0) LPMS_ERR(reopen_out_err, "Error re-writing header"); -static int encode(AVCodecContext* encoder, AVFrame *frame, struct output_ctx* octx, AVStream* ost) { -#define encode_err(msg) { \ - char errstr[AV_ERROR_MAX_STRING_SIZE] = {0}; \ - if (!ret) { fprintf(stderr, "should not happen\n"); ret = AVERROR(ENOMEM); } \ - if (ret < -1) av_strerror(ret, errstr, sizeof errstr); \ - fprintf(stderr, "%s: %s\n", msg, errstr); \ - goto encode_cleanup; \ +reopen_out_err: + return ret; } +static int encode(AVCodecContext* encoder, AVFrame *frame, struct output_ctx* octx, AVStream* ost) +{ int ret = 0; AVPacket pkt = {0}; @@ -312,7 +274,7 @@ static int encode(AVCodecContext* encoder, AVFrame *frame, struct output_ctx* oc if (AV_HWDEVICE_TYPE_NONE == octx->hw_type || frame) { ret = avcodec_send_frame(encoder, frame); if (AVERROR_EOF == ret) ; // continue ; drain encoder - else if (ret < 0) encode_err("Error sending frame to encoder"); + else if (ret < 0) LPMS_ERR(encode_cleanup, "Error sending frame to encoder"); } if (AVMEDIA_TYPE_VIDEO == ost->codecpar->codec_type && @@ -324,7 +286,7 @@ static int encode(AVCodecContext* encoder, AVFrame *frame, struct output_ctx* oc av_init_packet(&pkt); ret = avcodec_receive_packet(encoder, &pkt); if (AVERROR(EAGAIN) == ret || AVERROR_EOF == ret) goto encode_cleanup; - if (ret < 0) encode_err("Error receiving packet from encoder\n"); + if (ret < 0) LPMS_ERR(encode_cleanup, "Error receiving packet from encoder"); ret = mux(&pkt, encoder->time_base, octx, ost); if (ret < 0) goto encode_cleanup; av_packet_unref(&pkt); @@ -333,8 +295,6 @@ static int encode(AVCodecContext* encoder, AVFrame *frame, struct output_ctx* oc encode_cleanup: av_packet_unref(&pkt); return ret; - -#undef encode_err } int mux(AVPacket *pkt, AVRational tb, struct output_ctx *octx, AVStream *ost) @@ -358,16 +318,9 @@ int mux(AVPacket *pkt, AVRational tb, struct output_ctx *octx, AVStream *ost) int process_out(struct input_ctx *ictx, struct output_ctx *octx, AVCodecContext *encoder, AVStream *ost, struct filter_ctx *filter, AVFrame *inf) { -#define proc_err(msg) { \ - char errstr[AV_ERROR_MAX_STRING_SIZE] = {0}; \ - if (!ret) { fprintf(stderr, "u done messed up\n"); ret = AVERROR(ENOMEM); } \ - if (ret < -1) av_strerror(ret, errstr, sizeof errstr); \ - fprintf(stderr, "%s: %s\n", msg, errstr); \ - goto proc_cleanup; \ -} int ret = 0; - if (!encoder) proc_err("Trying to transmux; not supported") + if (!encoder) LPMS_ERR(proc_cleanup, "Trying to transmux; not supported") if (!filter || !filter->active) { // No filter in between decoder and encoder, so use input frame directly @@ -406,6 +359,5 @@ int process_out(struct input_ctx *ictx, struct output_ctx *octx, AVCodecContext proc_cleanup: return ret; -#undef proc_err } diff --git a/ffmpeg/filter.c b/ffmpeg/filter.c index 64259df055..761be7c0ec 100644 --- a/ffmpeg/filter.c +++ b/ffmpeg/filter.c @@ -1,4 +1,5 @@ #include "filter.h" +#include "logging.h" #include #include @@ -7,11 +8,6 @@ int init_video_filters(struct input_ctx *ictx, struct output_ctx *octx) { -#define filters_err(msg) { \ - if (!ret) ret = -1; \ - fprintf(stderr, msg); \ - goto init_video_filters_cleanup; \ -} char args[512]; int ret = 0; const AVFilter *buffersrc = avfilter_get_by_name("buffer"); @@ -25,8 +21,8 @@ int init_video_filters(struct input_ctx *ictx, struct output_ctx *octx) enum AVPixelFormat in_pix_fmt = ictx->vc->pix_fmt; // no need for filters with the following conditions - if (vf->active) goto init_video_filters_cleanup; // already initialized - if (!needs_decoder(octx->video->name)) goto init_video_filters_cleanup; + if (vf->active) goto vf_init_cleanup; // already initialized + if (!needs_decoder(octx->video->name)) goto vf_init_cleanup; outputs = avfilter_inout_alloc(); inputs = avfilter_inout_alloc(); @@ -34,7 +30,7 @@ int init_video_filters(struct input_ctx *ictx, struct output_ctx *octx) vf->pts_diff = INT64_MIN; if (!outputs || !inputs || !vf->graph) { ret = AVERROR(ENOMEM); - filters_err("Unble to allocate filters\n"); + LPMS_ERR(vf_init_cleanup, "Unable to allocate filters"); } if (ictx->vc->hw_device_ctx) in_pix_fmt = hw2pixfmt(ictx->vc); @@ -47,7 +43,7 @@ int init_video_filters(struct input_ctx *ictx, struct output_ctx *octx) ret = avfilter_graph_create_filter(&vf->src_ctx, buffersrc, "in", args, NULL, vf->graph); - if (ret < 0) filters_err("Cannot create video buffer source\n"); + if (ret < 0) LPMS_ERR(vf_init_cleanup, "Cannot create video buffer source"); if (ictx->vc && ictx->vc->hw_frames_ctx) { // XXX a bit problematic in that it's set before decoder is fully ready AVBufferSrcParameters *srcpar = av_buffersrc_parameters_alloc(); @@ -60,11 +56,11 @@ int init_video_filters(struct input_ctx *ictx, struct output_ctx *octx) /* buffer video sink: to terminate the filter chain. */ ret = avfilter_graph_create_filter(&vf->sink_ctx, buffersink, "out", NULL, NULL, vf->graph); - if (ret < 0) filters_err("Cannot create video buffer sink\n"); + if (ret < 0) LPMS_ERR(vf_init_cleanup, "Cannot create video buffer sink"); ret = av_opt_set_int_list(vf->sink_ctx, "pix_fmts", pix_fmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN); - if (ret < 0) filters_err("Cannot set output pixel format\n"); + if (ret < 0) LPMS_ERR(vf_init_cleanup, "Cannot set output pixel format"); /* * Set the endpoints for the filter graph. The filter_graph will @@ -95,32 +91,26 @@ int init_video_filters(struct input_ctx *ictx, struct output_ctx *octx) ret = avfilter_graph_parse_ptr(vf->graph, filters_descr, &inputs, &outputs, NULL); - if (ret < 0) filters_err("Unable to parse video filters desc\n"); + if (ret < 0) LPMS_ERR(vf_init_cleanup, "Unable to parse video filters desc"); ret = avfilter_graph_config(vf->graph, NULL); - if (ret < 0) filters_err("Unable configure video filtergraph\n"); + if (ret < 0) LPMS_ERR(vf_init_cleanup, "Unable configure video filtergraph"); vf->frame = av_frame_alloc(); - if (!vf->frame) filters_err("Unable to allocate video frame\n"); + if (!vf->frame) LPMS_ERR(vf_init_cleanup, "Unable to allocate video frame"); vf->active = 1; -init_video_filters_cleanup: +vf_init_cleanup: avfilter_inout_free(&inputs); avfilter_inout_free(&outputs); return ret; -#undef filters_err } int init_audio_filters(struct input_ctx *ictx, struct output_ctx *octx) { -#define af_err(msg) { \ - if (!ret) ret = -1; \ - fprintf(stderr, msg); \ - goto init_audio_filters_cleanup; \ -} int ret = 0; char args[512]; char filters_descr[256]; @@ -132,8 +122,8 @@ int init_audio_filters(struct input_ctx *ictx, struct output_ctx *octx) AVRational time_base = ictx->ic->streams[ictx->ai]->time_base; // no need for filters with the following conditions - if (af->active) goto init_audio_filters_cleanup; // already initialized - if (!needs_decoder(octx->audio->name)) goto init_audio_filters_cleanup; + if (af->active) goto af_init_cleanup; // already initialized + if (!needs_decoder(octx->audio->name)) goto af_init_cleanup; outputs = avfilter_inout_alloc(); inputs = avfilter_inout_alloc(); @@ -141,7 +131,7 @@ int init_audio_filters(struct input_ctx *ictx, struct output_ctx *octx) if (!outputs || !inputs || !af->graph) { ret = AVERROR(ENOMEM); - af_err("Unble to allocate audio filters\n"); + LPMS_ERR(af_init_cleanup, "Unable to allocate audio filters"); } /* buffer audio source: the decoded frames from the decoder will be inserted here. */ @@ -158,12 +148,12 @@ int init_audio_filters(struct input_ctx *ictx, struct output_ctx *octx) ret = avfilter_graph_create_filter(&af->src_ctx, buffersrc, "in", args, NULL, af->graph); - if (ret < 0) af_err("Cannot create audio buffer source\n"); + if (ret < 0) LPMS_ERR(af_init_cleanup, "Cannot create audio buffer source"); /* buffer audio sink: to terminate the filter chain. */ ret = avfilter_graph_create_filter(&af->sink_ctx, buffersink, "out", NULL, NULL, af->graph); - if (ret < 0) af_err("Cannot create audio buffer sink\n"); + if (ret < 0) LPMS_ERR(af_init_cleanup, "Cannot create audio buffer sink"); /* * Set the endpoints for the filter graph. The filter_graph will @@ -194,31 +184,23 @@ int init_audio_filters(struct input_ctx *ictx, struct output_ctx *octx) ret = avfilter_graph_parse_ptr(af->graph, filters_descr, &inputs, &outputs, NULL); - if (ret < 0) af_err("Unable to parse audio filters desc\n"); + if (ret < 0) LPMS_ERR(af_init_cleanup, "Unable to parse audio filters desc"); ret = avfilter_graph_config(af->graph, NULL); - if (ret < 0) af_err("Unable configure audio filtergraph\n"); + if (ret < 0) LPMS_ERR(af_init_cleanup, "Unable configure audio filtergraph"); af->frame = av_frame_alloc(); - if (!af->frame) af_err("Unable to allocate audio frame\n"); + if (!af->frame) LPMS_ERR(af_init_cleanup, "Unable to allocate audio frame"); af->active = 1; -init_audio_filters_cleanup: +af_init_cleanup: avfilter_inout_free(&inputs); avfilter_inout_free(&outputs); return ret; -#undef af_err } -#define fg_err(msg) { \ - char errstr[AV_ERROR_MAX_STRING_SIZE] = {0}; \ - if (!ret) { fprintf(stderr, "u done messed up\n"); ret = AVERROR(ENOMEM); } \ - if (ret < -1) av_strerror(ret, errstr, sizeof errstr); \ - fprintf(stderr, "%s: %s\n", msg, errstr); \ - return ret; \ -} int filtergraph_write(AVFrame *inf, struct input_ctx *ictx, struct output_ctx *octx, struct filter_ctx *filter, int is_video) { int ret = 0; @@ -267,8 +249,9 @@ int filtergraph_write(AVFrame *inf, struct input_ctx *ictx, struct output_ctx *o inf->pts = filter->custom_pts; ret = av_buffersrc_write_frame(filter->src_ctx, inf); inf->pts = old_pts; - if (ret < 0) fg_err("Error feeding the filtergraph"); + if (ret < 0) LPMS_ERR(fg_write_cleanup, "Error feeding the filtergraph"); } +fg_write_cleanup: return ret; } @@ -281,7 +264,7 @@ int filtergraph_read(struct input_ctx *ictx, struct output_ctx *octx, struct fil frame->pict_type = AV_PICTURE_TYPE_NONE; if (AVERROR(EAGAIN) == ret || AVERROR_EOF == ret) return ret; - else if (ret < 0) fg_err("Error consuming the filtergraph\n"); + else if (ret < 0) LPMS_ERR(fg_read_cleanup, "Error consuming the filtergraph"); if (frame && ((int64_t) frame->opaque == INT64_MIN)) { // opaque being INT64_MIN means it's a flush packet @@ -299,9 +282,9 @@ int filtergraph_read(struct input_ctx *ictx, struct output_ctx *octx, struct fil } frame->pts += filter->pts_diff; // Re-calculate by adding back this segment's difference calculated at start } +fg_read_cleanup: return ret; } -#undef fg_err void free_filter(struct filter_ctx *filter) { diff --git a/ffmpeg/logging.h b/ffmpeg/logging.h new file mode 100644 index 0000000000..d384c473f5 --- /dev/null +++ b/ffmpeg/logging.h @@ -0,0 +1,22 @@ +#ifndef _LPMS_LOGGING_H_ +#define _LPMS_LOGGING_H_ + +// LOGGING MACROS + +#define LPMS_ERR(label, msg) {\ +char errstr[AV_ERROR_MAX_STRING_SIZE] = {0}; \ +if (!ret) ret = AVERROR(EINVAL); \ +if (ret <-1) av_strerror(ret, errstr, sizeof errstr); \ +av_log(NULL, AV_LOG_ERROR, "ERROR: %s:%d] %s : %s\n", __FILE__, __LINE__, msg, errstr); \ +goto label; \ +} + +#define LPMS_WARN(msg) {\ +av_log(NULL, AV_LOG_WARNING, "WARNING: %s:%d] %s\n", __FILE__, __LINE__, msg); \ +} + +#define LPMS_INFO(msg) {\ +av_log(NULL, AV_LOG_INFO, "%s:%d] %s\n", __FILE__, __LINE__, msg); \ +} + +#endif // _LPMS_LOGGING_H_ diff --git a/ffmpeg/transcoder.c b/ffmpeg/transcoder.c index ae5259eca8..0358f80acc 100644 --- a/ffmpeg/transcoder.c +++ b/ffmpeg/transcoder.c @@ -2,6 +2,7 @@ #include "decoder.h" #include "filter.h" #include "encoder.h" +#include "logging.h" #include #include @@ -114,13 +115,6 @@ int transcode(struct transcode_thread *h, input_params *inp, output_params *params, output_results *results, output_results *decoded_results) { -#define main_err(msg) { \ - char errstr[AV_ERROR_MAX_STRING_SIZE] = {0}; \ - if (!ret) ret = AVERROR(EINVAL); \ - if (ret < -1) av_strerror(ret, errstr, sizeof errstr); \ - fprintf(stderr, "%s: %s\n", msg, errstr); \ - goto transcode_cleanup; \ -} int ret = 0, i = 0; int reopen_decoders = 1; struct input_ctx *ictx = &h->ictx; @@ -129,7 +123,7 @@ int transcode(struct transcode_thread *h, AVPacket ipkt = {0}; AVFrame *dframe = NULL; - if (!inp) main_err("transcoder: Missing input params\n") + if (!inp) LPMS_ERR(transcode_cleanup, "Missing input params") // by default we re-use decoder between segments of same stream // unless we are using SW deocder and had to re-open IO or demuxer @@ -137,22 +131,22 @@ int transcode(struct transcode_thread *h, // reopen demuxer for the input segment if needed // XXX could open_input() be re-used here? ret = avformat_open_input(&ictx->ic, inp->fname, NULL, NULL); - if (ret < 0) main_err("Unable to reopen demuxer"); + if (ret < 0) LPMS_ERR(transcode_cleanup, "Unable to reopen demuxer"); ret = avformat_find_stream_info(ictx->ic, NULL); - if (ret < 0) main_err("Unable to find info for reopened stream") + if (ret < 0) LPMS_ERR(transcode_cleanup, "Unable to find info for reopened stream") } else if (!ictx->ic->pb) { // reopen input segment file IO context if needed ret = avio_open(&ictx->ic->pb, inp->fname, AVIO_FLAG_READ); - if (ret < 0) main_err("Unable to reopen file"); + if (ret < 0) LPMS_ERR(transcode_cleanup, "Unable to reopen file"); } else reopen_decoders = 0; if (reopen_decoders) { // XXX check to see if we can also reuse decoder for sw decoding if (AV_HWDEVICE_TYPE_CUDA != ictx->hw_type) { ret = open_video_decoder(inp, ictx); - if (ret < 0) main_err("Unable to reopen video decoder"); + if (ret < 0) LPMS_ERR(transcode_cleanup, "Unable to reopen video decoder"); } ret = open_audio_decoder(inp, ictx); - if (ret < 0) main_err("Unable to reopen audio decoder") + if (ret < 0) LPMS_ERR(transcode_cleanup, "Unable to reopen audio decoder") } // populate output contexts @@ -176,18 +170,18 @@ int transcode(struct transcode_thread *h, // XXX valgrind this line up if (!h->initialized || AV_HWDEVICE_TYPE_NONE == octx->hw_type) { ret = open_output(octx, ictx); - if (ret < 0) main_err("transcoder: Unable to open output"); + if (ret < 0) LPMS_ERR(transcode_cleanup, "Unable to open output"); continue; } // non-first segment of a HW session ret = reopen_output(octx, ictx); - if (ret < 0) main_err("transcoder: Unable to re-open output for HW session"); + if (ret < 0) LPMS_ERR(transcode_cleanup, "Unable to re-open output for HW session"); } av_init_packet(&ipkt); dframe = av_frame_alloc(); - if (!dframe) main_err("transcoder: Unable to allocate frame\n"); + if (!dframe) LPMS_ERR(transcode_cleanup, "Unable to allocate frame"); while (1) { // DEMUXING & DECODING @@ -199,7 +193,7 @@ int transcode(struct transcode_thread *h, if (ret == AVERROR_EOF) break; // Bail out on streams that appear to be broken else if (lpms_ERR_PACKET_ONLY == ret) ; // keep going for stream copy - else if (ret < 0) main_err("transcoder: Could not decode; stopping\n"); + else if (ret < 0) LPMS_ERR(transcode_cleanup, "Could not decode; stopping"); ist = ictx->ic->streams[ipkt.stream_index]; has_frame = lpms_ERR_PACKET_ONLY != ret; @@ -221,7 +215,7 @@ int transcode(struct transcode_thread *h, dur = av_rescale_q(1, av_inv_q(ist->r_frame_rate), ist->time_base); } else { // TODO use better heuristics for this; look at how ffmpeg does it - fprintf(stderr, "Could not determine next pts; filter might drop\n"); + LPMS_WARN("Could not determine next pts; filter might drop"); } dframe->pkt_duration = dur; av_frame_unref(last_frame); @@ -261,14 +255,14 @@ int transcode(struct transcode_thread *h, if (ipkt.pts == AV_NOPTS_VALUE) continue; pkt = av_packet_clone(&ipkt); - if (!pkt) main_err("transcoder: Error allocating packet\n"); + if (!pkt) LPMS_ERR(transcode_cleanup, "Error allocating packet for copy"); ret = mux(pkt, ist->time_base, octx, ost); av_packet_free(&pkt); } else if (has_frame) { ret = process_out(ictx, octx, encoder, ost, filter, dframe); } if (AVERROR(EAGAIN) == ret || AVERROR_EOF == ret) continue; - else if (ret < 0) main_err("transcoder: Error encoding\n"); + else if (ret < 0) LPMS_ERR(transcode_cleanup, "Error encoding"); } whileloop_end: av_packet_unref(&ipkt); @@ -277,7 +271,7 @@ int transcode(struct transcode_thread *h, // flush outputs for (i = 0; i < nb_outputs; i++) { ret = flush_outputs(ictx, &outputs[i]); - if (ret < 0) main_err("transcoder: Unable to fully flush outputs") + if (ret < 0) LPMS_ERR(transcode_cleanup, "Unable to fully flush outputs") } transcode_cleanup: From 5b0c88182f2c2a9233c736468625f20148529615 Mon Sep 17 00:00:00 2001 From: Jai Luthra Date: Thu, 26 Nov 2020 23:17:12 +0530 Subject: [PATCH 2/2] ffmpeg: Make logging level configurable --- ffmpeg/ffmpeg.go | 20 +++++++++++++++++++- ffmpeg/transcoder.c | 5 ++--- ffmpeg/transcoder.h | 14 +++++++++++++- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/ffmpeg/ffmpeg.go b/ffmpeg/ffmpeg.go index 270ec6ed75..fb5c372166 100644 --- a/ffmpeg/ffmpeg.go +++ b/ffmpeg/ffmpeg.go @@ -396,6 +396,24 @@ func (t *Transcoder) StopTranscoder() { t.stopped = true } +type LogLevel C.enum_LPMSLogLevel + +const ( + FFLogTrace = C.LPMS_LOG_TRACE + FFLogDebug = C.LPMS_LOG_DEBUG + FFLogVerbose = C.LPMS_LOG_VERBOSE + FFLogInfo = C.LPMS_LOG_INFO + FFLogWarning = C.LPMS_LOG_WARNING + FFLogError = C.LPMS_LOG_ERROR + FFLogFatal = C.LPMS_LOG_FATAL + FFLogPanic = C.LPMS_LOG_PANIC + FFLogQuiet = C.LPMS_LOG_QUIET +) + +func InitFFmpegWithLogLevel(level LogLevel) { + C.lpms_init(C.enum_LPMSLogLevel(level)) +} + func InitFFmpeg() { - C.lpms_init() + InitFFmpegWithLogLevel(FFLogWarning) } diff --git a/ffmpeg/transcoder.c b/ffmpeg/transcoder.c index 0358f80acc..5806ba5efd 100644 --- a/ffmpeg/transcoder.c +++ b/ffmpeg/transcoder.c @@ -78,9 +78,9 @@ struct transcode_thread { }; -void lpms_init() +void lpms_init(enum LPMSLogLevel max_level) { - av_log_set_level(AV_LOG_WARNING); + av_log_set_level(max_level); } // @@ -298,7 +298,6 @@ int transcode(struct transcode_thread *h, if (ictx->vc && AV_HWDEVICE_TYPE_NONE == ictx->hw_type) avcodec_free_context(&ictx->vc); for (i = 0; i < nb_outputs; i++) close_output(&outputs[i]); return ret == AVERROR_EOF ? 0 : ret; -#undef main_err } int lpms_transcode(input_params *inp, output_params *params, diff --git a/ffmpeg/transcoder.h b/ffmpeg/transcoder.h index b2038c050d..0d2a4a5746 100644 --- a/ffmpeg/transcoder.h +++ b/ffmpeg/transcoder.h @@ -53,7 +53,19 @@ typedef struct { int64_t pixels; } output_results; -void lpms_init(); +enum LPMSLogLevel { + LPMS_LOG_TRACE = AV_LOG_TRACE, + LPMS_LOG_DEBUG = AV_LOG_DEBUG, + LPMS_LOG_VERBOSE = AV_LOG_VERBOSE, + LPMS_LOG_INFO = AV_LOG_INFO, + LPMS_LOG_WARNING = AV_LOG_WARNING, + LPMS_LOG_ERROR = AV_LOG_ERROR, + LPMS_LOG_FATAL = AV_LOG_FATAL, + LPMS_LOG_PANIC = AV_LOG_PANIC, + LPMS_LOG_QUIET = AV_LOG_QUIET +}; + +void lpms_init(enum LPMSLogLevel max_level); int lpms_transcode(input_params *inp, output_params *params, output_results *results, int nb_outputs, output_results *decoded_results); struct transcode_thread* lpms_transcode_new(); void lpms_transcode_stop(struct transcode_thread* handle);