summaryrefslogtreecommitdiff
path: root/libavcodec/libopenh264enc.c
diff options
context:
space:
mode:
Diffstat (limited to 'libavcodec/libopenh264enc.c')
-rw-r--r--libavcodec/libopenh264enc.c98
1 files changed, 86 insertions, 12 deletions
diff --git a/libavcodec/libopenh264enc.c b/libavcodec/libopenh264enc.c
index fb153c4d58..33b7f6c7a8 100644
--- a/libavcodec/libopenh264enc.c
+++ b/libavcodec/libopenh264enc.c
@@ -2,20 +2,20 @@
* OpenH264 video encoder
* Copyright (C) 2014 Martin Storsjo
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -46,12 +46,12 @@ typedef struct SVCContext {
#define OFFSET(x) offsetof(SVCContext, x)
#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
- { "slice_mode", "Slice mode", OFFSET(slice_mode), AV_OPT_TYPE_INT, { .i64 = SM_AUTO_SLICE }, SM_SINGLE_SLICE, SM_RESERVED, VE, "slice_mode" },
- { "fixed", "A fixed number of slices", 0, AV_OPT_TYPE_CONST, { .i64 = SM_FIXEDSLCNUM_SLICE }, 0, 0, VE, "slice_mode" },
- { "rowmb", "One slice per row of macroblocks", 0, AV_OPT_TYPE_CONST, { .i64 = SM_ROWMB_SLICE }, 0, 0, VE, "slice_mode" },
- { "auto", "Automatic number of slices according to number of threads", 0, AV_OPT_TYPE_CONST, { .i64 = SM_AUTO_SLICE }, 0, 0, VE, "slice_mode" },
- { "loopfilter", "Enable loop filter", OFFSET(loopfilter), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, VE },
- { "profile", "Set profile restrictions", OFFSET(profile), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE },
+ { "slice_mode", "set slice mode", OFFSET(slice_mode), AV_OPT_TYPE_INT, { .i64 = SM_AUTO_SLICE }, SM_SINGLE_SLICE, SM_RESERVED, VE, "slice_mode" },
+ { "fixed", "a fixed number of slices", 0, AV_OPT_TYPE_CONST, { .i64 = SM_FIXEDSLCNUM_SLICE }, 0, 0, VE, "slice_mode" },
+ { "rowmb", "one slice per row of macroblocks", 0, AV_OPT_TYPE_CONST, { .i64 = SM_ROWMB_SLICE }, 0, 0, VE, "slice_mode" },
+ { "auto", "automatic number of slices according to number of threads", 0, AV_OPT_TYPE_CONST, { .i64 = SM_AUTO_SLICE }, 0, 0, VE, "slice_mode" },
+ { "loopfilter", "enable loop filter", OFFSET(loopfilter), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, VE },
+ { "profile", "set profile restrictions", OFFSET(profile), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE },
{ NULL }
};
@@ -59,6 +59,56 @@ static const AVClass class = {
"libopenh264enc", av_default_item_name, options, LIBAVUTIL_VERSION_INT
};
+// Convert ffmpeg log level to equivalent libopenh264 log level. Given the
+// conversions below, you must set the ffmpeg log level to something greater
+// than AV_LOG_DEBUG if you want to see WELS_LOG_DETAIL messages.
+static int ffmpeg_to_libopenh264_log_level (
+ int ffmpeg_log_level
+ )
+{
+ if (ffmpeg_log_level > AV_LOG_DEBUG) return WELS_LOG_DETAIL;
+ else if (ffmpeg_log_level >= AV_LOG_DEBUG) return WELS_LOG_DEBUG;
+ else if (ffmpeg_log_level >= AV_LOG_INFO) return WELS_LOG_INFO;
+ else if (ffmpeg_log_level >= AV_LOG_WARNING) return WELS_LOG_WARNING;
+ else if (ffmpeg_log_level >= AV_LOG_ERROR) return WELS_LOG_ERROR;
+ else return WELS_LOG_QUIET;
+}
+
+// Convert libopenh264 log level to equivalent ffmpeg log level.
+static int libopenh264_to_ffmpeg_log_level (
+ int libopenh264_log_level
+ )
+{
+ if (libopenh264_log_level >= WELS_LOG_DETAIL) return AV_LOG_TRACE;
+ else if (libopenh264_log_level >= WELS_LOG_DEBUG) return AV_LOG_DEBUG;
+ else if (libopenh264_log_level >= WELS_LOG_INFO) return AV_LOG_INFO;
+ else if (libopenh264_log_level >= WELS_LOG_WARNING) return AV_LOG_WARNING;
+ else if (libopenh264_log_level >= WELS_LOG_ERROR) return AV_LOG_ERROR;
+ else return AV_LOG_QUIET;
+}
+
+// This function will be provided to the libopenh264 library. The function will be called
+// when libopenh264 wants to log a message (error, warning, info, etc.). The signature for
+// this function (defined in .../codec/api/svc/codec_api.h) is:
+//
+// typedef void (*WelsTraceCallback) (void* ctx, int level, const char* string);
+
+static void libopenh264_trace_callback (
+ void * ctx,
+ int level,
+ char const * msg
+ )
+{
+ // The message will be logged only if the requested EQUIVALENT ffmpeg log level is
+ // less than or equal to the current ffmpeg log level. Note, however, that before
+ // this function is called, welsCodecTrace::CodecTrace() will have already discarded
+ // the message (and this function will not be called) if the requested libopenh264
+ // log level "level" is greater than the current libopenh264 log level.
+ int equiv_ffmpeg_log_level = libopenh264_to_ffmpeg_log_level(level);
+ if (equiv_ffmpeg_log_level <= av_log_get_level())
+ av_log(ctx, equiv_ffmpeg_log_level, "%s\n", msg);
+}
+
static av_cold int svc_encode_close(AVCodecContext *avctx)
{
SVCContext *s = avctx->priv_data;
@@ -73,6 +123,8 @@ static av_cold int svc_encode_init(AVCodecContext *avctx)
SVCContext *s = avctx->priv_data;
SEncParamExt param = { 0 };
int err = AVERROR_UNKNOWN;
+ int equiv_libopenh264_log_level;
+ WelsTraceCallback callback_function;
// Mingw GCC < 4.7 on x86_32 uses an incorrect/buggy ABI for the WelsGetCodecVersion
// function (for functions returning larger structs), thus skip the check in those
@@ -90,9 +142,31 @@ static av_cold int svc_encode_init(AVCodecContext *avctx)
return AVERROR_UNKNOWN;
}
+ // Set libopenh264 message logging level for this instance of the encoder using
+ // the current ffmpeg log level converted to the equivalent libopenh264 level.
+ //
+ // The client should have the ffmpeg level set to the desired value before creating
+ // the libopenh264 encoder. Once the encoder has been created, the libopenh264
+ // log level is fixed for that encoder. Changing the ffmpeg log level to a LOWER
+ // value, in the expectation that higher level libopenh264 messages will no longer
+ // be logged, WILL have the expected effect. However, changing the ffmpeg log level
+ // to a HIGHER value, in the expectation that higher level libopenh264 messages will
+ // now be logged, WILL NOT have the expected effect. This is because the higher
+ // level messages will be discarded by the libopenh264 logging system before our
+ // message logging callback function can be invoked.
+ equiv_libopenh264_log_level = ffmpeg_to_libopenh264_log_level(av_log_get_level());
+ (*s->encoder)->SetOption(s->encoder,ENCODER_OPTION_TRACE_LEVEL,&equiv_libopenh264_log_level);
+
+ // Set the logging callback function to one that uses av_log() (see implementation above).
+ callback_function = (WelsTraceCallback) libopenh264_trace_callback;
+ (*s->encoder)->SetOption(s->encoder,ENCODER_OPTION_TRACE_CALLBACK,(void *)&callback_function);
+
+ // Set the AVCodecContext as the libopenh264 callback context so that it can be passed to av_log().
+ (*s->encoder)->SetOption(s->encoder,ENCODER_OPTION_TRACE_CALLBACK_CONTEXT,(void *)&avctx);
+
(*s->encoder)->GetDefaultParams(s->encoder, &param);
- param.fMaxFrameRate = avctx->time_base.den / avctx->time_base.num;
+ param.fMaxFrameRate = 1/av_q2d(avctx->time_base);
param.iPicWidth = avctx->width;
param.iPicHeight = avctx->height;
param.iTargetBitrate = avctx->bit_rate;
@@ -202,7 +276,7 @@ static int svc_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
}
av_log(avctx, AV_LOG_DEBUG, "%d slices\n", fbi.sLayerInfo[fbi.iLayerNum - 1].iNalCount);
- if ((ret = ff_alloc_packet(avpkt, size))) {
+ if ((ret = ff_alloc_packet2(avctx, avpkt, size, size))) {
av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n");
return ret;
}