]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/v4l2_m2m_enc.c
avcodec: Constify AVCodecs
[ffmpeg] / libavcodec / v4l2_m2m_enc.c
index 5a08e4ed1d720778c0ed77be4195c4a3cd97f988..043fe80c695fff5b4767b9c8226a5c2652f62793 100644 (file)
 #include <linux/videodev2.h>
 #include <sys/ioctl.h>
 #include <search.h>
+#include "encode.h"
 #include "libavcodec/avcodec.h"
+#include "libavcodec/internal.h"
 #include "libavutil/pixdesc.h"
 #include "libavutil/pixfmt.h"
 #include "libavutil/opt.h"
+#include "profiles.h"
 #include "v4l2_context.h"
 #include "v4l2_m2m.h"
 #include "v4l2_fmt.h"
@@ -192,6 +195,7 @@ static int v4l2_prepare_encoder(V4L2m2mContext *s)
     /* set ext ctrls */
     v4l2_set_ext_ctrl(s, MPEG_CID(HEADER_MODE), MPEG_VIDEO(HEADER_MODE_SEPARATE), "header mode", 0);
     v4l2_set_ext_ctrl(s, MPEG_CID(BITRATE) , avctx->bit_rate, "bit rate", 1);
+    v4l2_set_ext_ctrl(s, MPEG_CID(FRAME_RC_ENABLE), 1, "frame level rate control", 0);
     v4l2_set_ext_ctrl(s, MPEG_CID(GOP_SIZE), avctx->gop_size,"gop size", 1);
 
     av_log(avctx, AV_LOG_DEBUG,
@@ -203,11 +207,11 @@ static int v4l2_prepare_encoder(V4L2m2mContext *s)
     switch (avctx->codec_id) {
     case AV_CODEC_ID_H264:
         if (avctx->profile != FF_PROFILE_UNKNOWN) {
-        val = v4l2_h264_profile_from_ff(avctx->profile);
-        if (val < 0)
-            av_log(avctx, AV_LOG_WARNING, "h264 profile not found\n");
-        else
-            v4l2_set_ext_ctrl(s, MPEG_CID(H264_PROFILE), val, "h264 profile", 1);
+            val = v4l2_h264_profile_from_ff(avctx->profile);
+            if (val < 0)
+                av_log(avctx, AV_LOG_WARNING, "h264 profile not found\n");
+            else
+                v4l2_set_ext_ctrl(s, MPEG_CID(H264_PROFILE), val, "h264 profile", 1);
         }
         qmin_cid = MPEG_CID(H264_MIN_QP);
         qmax_cid = MPEG_CID(H264_MAX_QP);
@@ -216,11 +220,11 @@ static int v4l2_prepare_encoder(V4L2m2mContext *s)
         break;
     case AV_CODEC_ID_MPEG4:
         if (avctx->profile != FF_PROFILE_UNKNOWN) {
-        val = v4l2_mpeg4_profile_from_ff(avctx->profile);
-        if (val < 0)
-            av_log(avctx, AV_LOG_WARNING, "mpeg4 profile not found\n");
-        else
-            v4l2_set_ext_ctrl(s, MPEG_CID(MPEG4_PROFILE), val, "mpeg4 profile", 1);
+            val = v4l2_mpeg4_profile_from_ff(avctx->profile);
+            if (val < 0)
+                av_log(avctx, AV_LOG_WARNING, "mpeg4 profile not found\n");
+            else
+                v4l2_set_ext_ctrl(s, MPEG_CID(MPEG4_PROFILE), val, "mpeg4 profile", 1);
         }
         qmin_cid = MPEG_CID(MPEG4_MIN_QP);
         qmax_cid = MPEG_CID(MPEG4_MAX_QP);
@@ -251,11 +255,18 @@ static int v4l2_prepare_encoder(V4L2m2mContext *s)
         return 0;
     }
 
-    if (qmin != avctx->qmin || qmax != avctx->qmax)
-        av_log(avctx, AV_LOG_WARNING, "Encoder adjusted: qmin (%d), qmax (%d)\n", qmin, qmax);
+    if (avctx->qmin >= 0 && avctx->qmax >= 0 && avctx->qmin > avctx->qmax) {
+        av_log(avctx, AV_LOG_WARNING, "Invalid qmin:%d qmax:%d. qmin should not "
+                                      "exceed qmax\n", avctx->qmin, avctx->qmax);
+    } else {
+        qmin = avctx->qmin >= 0 ? avctx->qmin : qmin;
+        qmax = avctx->qmax >= 0 ? avctx->qmax : qmax;
+    }
 
-    v4l2_set_ext_ctrl(s, qmin_cid, qmin, "minimum video quantizer scale", 0);
-    v4l2_set_ext_ctrl(s, qmax_cid, qmax, "maximum video quantizer scale", 0);
+    v4l2_set_ext_ctrl(s, qmin_cid, qmin, "minimum video quantizer scale",
+                      avctx->qmin >= 0);
+    v4l2_set_ext_ctrl(s, qmax_cid, qmax, "maximum video quantizer scale",
+                      avctx->qmax >= 0);
 
     return 0;
 }
@@ -278,11 +289,28 @@ static int v4l2_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
     V4L2m2mContext *s = ((V4L2m2mPriv*)avctx->priv_data)->context;
     V4L2Context *const capture = &s->capture;
     V4L2Context *const output = &s->output;
+    AVFrame *frame = s->frame;
     int ret;
 
     if (s->draining)
         goto dequeue;
 
+    if (!frame->buf[0]) {
+        ret = ff_encode_get_frame(avctx, frame);
+        if (ret < 0 && ret != AVERROR_EOF)
+            return ret;
+
+        if (ret == AVERROR_EOF)
+            frame = NULL;
+    }
+
+    ret = v4l2_send_frame(avctx, frame);
+    if (ret != AVERROR(EAGAIN))
+        av_frame_unref(frame);
+
+    if (ret < 0 && ret != AVERROR(EAGAIN))
+        return ret;
+
     if (!output->streamon) {
         ret = ff_v4l2_context_set_status(output, VIDIOC_STREAMON);
         if (ret) {
@@ -361,24 +389,39 @@ static av_cold int v4l2_encode_close(AVCodecContext *avctx)
 #define OFFSET(x) offsetof(V4L2m2mPriv, x)
 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
 
+#define V4L_M2M_CAPTURE_OPTS \
+    V4L_M2M_DEFAULT_OPTS,\
+    { "num_capture_buffers", "Number of buffers in the capture context", \
+        OFFSET(num_capture_buffers), AV_OPT_TYPE_INT, {.i64 = 4 }, 4, INT_MAX, FLAGS }
+
+static const AVOption mpeg4_options[] = {
+    V4L_M2M_CAPTURE_OPTS,
+    FF_MPEG4_PROFILE_OPTS
+    { NULL },
+};
+
 static const AVOption options[] = {
-    V4L_M2M_DEFAULT_OPTS,
-    { "num_capture_buffers", "Number of buffers in the capture context",
-        OFFSET(num_capture_buffers), AV_OPT_TYPE_INT, {.i64 = 4 }, 4, INT_MAX, FLAGS },
+    V4L_M2M_CAPTURE_OPTS,
+    { NULL },
+};
+
+static const AVCodecDefault v4l2_m2m_defaults[] = {
+    { "qmin", "-1" },
+    { "qmax", "-1" },
     { NULL },
 };
 
-#define M2MENC_CLASS(NAME) \
+#define M2MENC_CLASS(NAME, OPTIONS_NAME) \
     static const AVClass v4l2_m2m_ ## NAME ## _enc_class = { \
         .class_name = #NAME "_v4l2m2m_encoder", \
         .item_name  = av_default_item_name, \
-        .option     = options, \
+        .option     = OPTIONS_NAME, \
         .version    = LIBAVUTIL_VERSION_INT, \
     };
 
-#define M2MENC(NAME, LONGNAME, CODEC) \
-    M2MENC_CLASS(NAME) \
-    AVCodec ff_ ## NAME ## _v4l2m2m_encoder = { \
+#define M2MENC(NAME, LONGNAME, OPTIONS_NAME, CODEC) \
+    M2MENC_CLASS(NAME, OPTIONS_NAME) \
+    const AVCodec ff_ ## NAME ## _v4l2m2m_encoder = { \
         .name           = #NAME "_v4l2m2m" , \
         .long_name      = NULL_IF_CONFIG_SMALL("V4L2 mem2mem " LONGNAME " encoder wrapper"), \
         .type           = AVMEDIA_TYPE_VIDEO, \
@@ -386,15 +429,16 @@ static const AVOption options[] = {
         .priv_data_size = sizeof(V4L2m2mPriv), \
         .priv_class     = &v4l2_m2m_ ## NAME ##_enc_class, \
         .init           = v4l2_encode_init, \
-        .send_frame     = v4l2_send_frame, \
         .receive_packet = v4l2_receive_packet, \
         .close          = v4l2_encode_close, \
+        .defaults       = v4l2_m2m_defaults, \
         .capabilities   = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY, \
+        .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP, \
         .wrapper_name   = "v4l2m2m", \
-    };
+    }
 
-M2MENC(mpeg4,"MPEG4", AV_CODEC_ID_MPEG4);
-M2MENC(h263, "H.263", AV_CODEC_ID_H263);
-M2MENC(h264, "H.264", AV_CODEC_ID_H264);
-M2MENC(hevc, "HEVC",  AV_CODEC_ID_HEVC);
-M2MENC(vp8,  "VP8",   AV_CODEC_ID_VP8);
+M2MENC(mpeg4,"MPEG4", mpeg4_options, AV_CODEC_ID_MPEG4);
+M2MENC(h263, "H.263", options,       AV_CODEC_ID_H263);
+M2MENC(h264, "H.264", options,       AV_CODEC_ID_H264);
+M2MENC(hevc, "HEVC",  options,       AV_CODEC_ID_HEVC);
+M2MENC(vp8,  "VP8",   options,       AV_CODEC_ID_VP8);