[FFmpeg-devel,07/25] avcodec/v4l2_m2m: decouple v4l2_m2m helpers from AVCodecContext

Submitted by Aman Gupta on Sept. 3, 2019, 1:02 a.m.

Details

Message ID 20190903010230.96236-8-ffmpeg@tmm1.net
State Accepted
Commit c0c7946196710d0579a9c85bf65289d5a123ab89
Headers show

Commit Message

Aman Gupta Sept. 3, 2019, 1:02 a.m.
From: Aman Gupta <aman@tmm1.net>

This will allow re-use of the m2m backend with AVFilterContext

Signed-off-by: Aman Gupta <aman@tmm1.net>
---
 libavcodec/v4l2_context.c |  9 +++----
 libavcodec/v4l2_m2m.c     | 50 +++++++++++++++++++--------------------
 libavcodec/v4l2_m2m.h     | 18 +++++++-------
 libavcodec/v4l2_m2m_dec.c | 14 +++++++----
 libavcodec/v4l2_m2m_enc.c | 13 +++++++---
 5 files changed, 60 insertions(+), 44 deletions(-)

Patch hide | download patch | download mbox

diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c
index 90356bb740..b02142a5d6 100644
--- a/libavcodec/v4l2_context.c
+++ b/libavcodec/v4l2_context.c
@@ -48,9 +48,9 @@  static inline V4L2m2mContext *ctx_to_m2mctx(V4L2Context *ctx)
         container_of(ctx, V4L2m2mContext, capture);
 }
 
-static inline AVCodecContext *logger(V4L2Context *ctx)
+static inline AVClass *logger(V4L2Context *ctx)
 {
-    return ctx_to_m2mctx(ctx)->avctx;
+    return ctx_to_m2mctx(ctx)->priv;
 }
 
 static inline unsigned int v4l2_get_width(struct v4l2_format *fmt)
@@ -96,7 +96,7 @@  static inline int v4l2_get_framesize_compressed(V4L2Context* ctx, int width, int
     const int SZ_4K = 0x1000;
     int size;
 
-    if (av_codec_is_decoder(s->avctx->codec))
+    if (s->avctx && av_codec_is_decoder(s->avctx->codec))
         return ((width * height * 3 / 2) / 2) + 128;
 
     /* encoder */
@@ -193,7 +193,8 @@  static int v4l2_handle_event(V4L2Context *ctx)
     }
 
     if (reinit) {
-        ret = ff_set_dimensions(s->avctx, s->capture.width, s->capture.height);
+        if (s->avctx)
+            ret = ff_set_dimensions(s->avctx, s->capture.width, s->capture.height);
         if (ret < 0)
             av_log(logger(ctx), AV_LOG_WARNING, "update avcodec height and width\n");
 
diff --git a/libavcodec/v4l2_m2m.c b/libavcodec/v4l2_m2m.c
index 827662b9a5..358f587797 100644
--- a/libavcodec/v4l2_m2m.c
+++ b/libavcodec/v4l2_m2m.c
@@ -63,6 +63,7 @@  static inline int v4l2_mplane_video(struct v4l2_capability *cap)
 static int v4l2_prepare_contexts(V4L2m2mContext* s, int probe)
 {
     struct v4l2_capability cap;
+    void *log_ctx = s->priv;
     int ret;
 
     s->capture.done = s->output.done = 0;
@@ -76,7 +77,7 @@  static int v4l2_prepare_contexts(V4L2m2mContext* s, int probe)
     if (ret < 0)
         return ret;
 
-    av_log(s->avctx, probe ? AV_LOG_DEBUG : AV_LOG_INFO,
+    av_log(log_ctx, probe ? AV_LOG_DEBUG : AV_LOG_INFO,
                      "driver '%s' on card '%s' in %s mode\n", cap.driver, cap.card,
                      v4l2_mplane_video(&cap) ? "mplane" :
                      v4l2_splane_video(&cap) ? "splane" : "unknown");
@@ -98,6 +99,7 @@  static int v4l2_prepare_contexts(V4L2m2mContext* s, int probe)
 
 static int v4l2_probe_driver(V4L2m2mContext* s)
 {
+    void *log_ctx = s->priv;
     int ret;
 
     s->fd = open(s->devname, O_RDWR | O_NONBLOCK, 0);
@@ -110,20 +112,20 @@  static int v4l2_probe_driver(V4L2m2mContext* s)
 
     ret = ff_v4l2_context_get_format(&s->output, 1);
     if (ret) {
-        av_log(s->avctx, AV_LOG_DEBUG, "v4l2 output format not supported\n");
+        av_log(log_ctx, AV_LOG_DEBUG, "v4l2 output format not supported\n");
         goto done;
     }
 
     ret = ff_v4l2_context_get_format(&s->capture, 1);
     if (ret) {
-        av_log(s->avctx, AV_LOG_DEBUG, "v4l2 capture format not supported\n");
+        av_log(log_ctx, AV_LOG_DEBUG, "v4l2 capture format not supported\n");
         goto done;
     }
 
 done:
     if (close(s->fd) < 0) {
         ret = AVERROR(errno);
-        av_log(s->avctx, AV_LOG_ERROR, "failure closing %s (%s)\n", s->devname, av_err2str(AVERROR(errno)));
+        av_log(log_ctx, AV_LOG_ERROR, "failure closing %s (%s)\n", s->devname, av_err2str(AVERROR(errno)));
     }
 
     s->fd = -1;
@@ -133,7 +135,7 @@  done:
 
 static int v4l2_configure_contexts(V4L2m2mContext* s)
 {
-    void *log_ctx = s->avctx;
+    void *log_ctx = s->priv;
     int ret;
     struct v4l2_format ofmt, cfmt;
 
@@ -174,7 +176,7 @@  static int v4l2_configure_contexts(V4L2m2mContext* s)
     }
 
     /* decoder's buffers need to be updated at a later stage */
-    if (!av_codec_is_decoder(s->avctx->codec)) {
+    if (!s->avctx || !av_codec_is_decoder(s->avctx->codec)) {
         ret = ff_v4l2_context_init(&s->capture);
         if (ret) {
             av_log(log_ctx, AV_LOG_ERROR, "no v4l2 capture context's buffers\n");
@@ -202,20 +204,21 @@  error:
  ******************************************************************************/
 int ff_v4l2_m2m_codec_reinit(V4L2m2mContext* s)
 {
+    void *log_ctx = s->priv;
     int ret;
 
-    av_log(s->avctx, AV_LOG_DEBUG, "reinit context\n");
+    av_log(log_ctx, AV_LOG_DEBUG, "reinit context\n");
 
     /* 1. streamoff */
     ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF);
     if (ret)
-        av_log(s->avctx, AV_LOG_ERROR, "capture VIDIOC_STREAMOFF\n");
+        av_log(log_ctx, AV_LOG_ERROR, "capture VIDIOC_STREAMOFF\n");
 
     /* 2. unmap the capture buffers (v4l2 and ffmpeg):
      *    we must wait for all references to be released before being allowed
      *    to queue new buffers.
      */
-    av_log(s->avctx, AV_LOG_DEBUG, "waiting for user to release AVBufferRefs\n");
+    av_log(log_ctx, AV_LOG_DEBUG, "waiting for user to release AVBufferRefs\n");
     if (atomic_load(&s->refcount))
         while(sem_wait(&s->refsync) == -1 && errno == EINTR);
 
@@ -224,14 +227,14 @@  int ff_v4l2_m2m_codec_reinit(V4L2m2mContext* s)
     /* 3. get the new capture format */
     ret = ff_v4l2_context_get_format(&s->capture, 0);
     if (ret) {
-        av_log(s->avctx, AV_LOG_ERROR, "query the new capture format\n");
+        av_log(log_ctx, AV_LOG_ERROR, "query the new capture format\n");
         return ret;
     }
 
     /* 4. set the capture format */
     ret = ff_v4l2_context_set_format(&s->capture);
     if (ret) {
-        av_log(s->avctx, AV_LOG_ERROR, "setting capture format\n");
+        av_log(log_ctx, AV_LOG_ERROR, "setting capture format\n");
         return ret;
     }
 
@@ -304,7 +307,7 @@  int ff_v4l2_m2m_codec_full_reinit(V4L2m2mContext *s)
     }
 
     /* decoder's buffers need to be updated at a later stage */
-    if (!av_codec_is_decoder(s->avctx->codec)) {
+    if (!s->avctx || !av_codec_is_decoder(s->avctx->codec)) {
         ret = ff_v4l2_context_init(&s->capture);
         if (ret) {
             av_log(log_ctx, AV_LOG_ERROR, "no v4l2 capture context's buffers\n");
@@ -330,19 +333,18 @@  static void v4l2_m2m_destroy_context(void *opaque, uint8_t *context)
     av_free(s);
 }
 
-int ff_v4l2_m2m_codec_end(AVCodecContext *avctx)
+int ff_v4l2_m2m_codec_end(V4L2m2mPriv *priv)
 {
-    V4L2m2mPriv *priv = avctx->priv_data;
     V4L2m2mContext* s = priv->context;
     int ret;
 
     ret = ff_v4l2_context_set_status(&s->output, VIDIOC_STREAMOFF);
     if (ret)
-        av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s\n", s->output.name);
+        av_log(priv, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s\n", s->output.name);
 
     ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF);
     if (ret)
-        av_log(avctx, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s\n", s->capture.name);
+        av_log(priv, AV_LOG_ERROR, "VIDIOC_STREAMOFF %s\n", s->capture.name);
 
     ff_v4l2_context_release(&s->output);
 
@@ -352,15 +354,14 @@  int ff_v4l2_m2m_codec_end(AVCodecContext *avctx)
     return 0;
 }
 
-int ff_v4l2_m2m_codec_init(AVCodecContext *avctx)
+int ff_v4l2_m2m_codec_init(V4L2m2mPriv *priv)
 {
     int ret = AVERROR(EINVAL);
     struct dirent *entry;
     char node[PATH_MAX];
     DIR *dirp;
 
-    V4L2m2mContext *s = ((V4L2m2mPriv*)avctx->priv_data)->context;
-    s->avctx = avctx;
+    V4L2m2mContext *s = priv->context;
 
     dirp = opendir("/dev");
     if (!dirp)
@@ -372,7 +373,7 @@  int ff_v4l2_m2m_codec_init(AVCodecContext *avctx)
             continue;
 
         snprintf(node, sizeof(node), "/dev/%s", entry->d_name);
-        av_log(s->avctx, AV_LOG_DEBUG, "probing device %s\n", node);
+        av_log(priv, AV_LOG_DEBUG, "probing device %s\n", node);
         strncpy(s->devname, node, strlen(node) + 1);
         ret = v4l2_probe_driver(s);
         if (!ret)
@@ -382,21 +383,19 @@  int ff_v4l2_m2m_codec_init(AVCodecContext *avctx)
     closedir(dirp);
 
     if (ret) {
-        av_log(s->avctx, AV_LOG_ERROR, "Could not find a valid device\n");
+        av_log(priv, AV_LOG_ERROR, "Could not find a valid device\n");
         memset(s->devname, 0, sizeof(s->devname));
 
         return ret;
     }
 
-    av_log(s->avctx, AV_LOG_INFO, "Using device %s\n", node);
+    av_log(priv, AV_LOG_INFO, "Using device %s\n", node);
 
     return v4l2_configure_contexts(s);
 }
 
-int ff_v4l2_m2m_create_context(AVCodecContext *avctx, V4L2m2mContext **s)
+int ff_v4l2_m2m_create_context(V4L2m2mPriv *priv, V4L2m2mContext **s)
 {
-    V4L2m2mPriv *priv = avctx->priv_data;
-
     *s = av_mallocz(sizeof(V4L2m2mContext));
     if (!*s)
         return AVERROR(ENOMEM);
@@ -410,6 +409,7 @@  int ff_v4l2_m2m_create_context(AVCodecContext *avctx, V4L2m2mContext **s)
 
     /* assign the context */
     priv->context = *s;
+    (*s)->priv = priv;
 
     /* populate it */
     priv->context->capture.num_buffers = priv->num_capture_buffers;
diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h
index 0d4671beb1..c860e96ef5 100644
--- a/libavcodec/v4l2_m2m.h
+++ b/libavcodec/v4l2_m2m.h
@@ -59,10 +59,12 @@  typedef struct V4L2m2mContext {
 
     /* Reference to self; only valid while codec is active. */
     AVBufferRef *self_ref;
+
+    /* reference back to V4L2m2mPriv */
+    void *priv;
 } V4L2m2mContext;
 
-typedef struct V4L2m2mPriv
-{
+typedef struct V4L2m2mPriv {
     AVClass *class;
 
     V4L2m2mContext *context;
@@ -75,33 +77,33 @@  typedef struct V4L2m2mPriv
 /**
  * Allocate a new context and references for a V4L2 M2M instance.
  *
- * @param[in] ctx The AVCodecContext instantiated by the encoder/decoder.
+ * @param[in] ctx The V4L2m2mPriv instantiated by the encoder/decoder.
  * @param[out] ctx The V4L2m2mContext.
  *
  * @returns 0 in success, a negative error code otherwise.
  */
-int ff_v4l2_m2m_create_context(AVCodecContext *avctx, V4L2m2mContext **s);
+int ff_v4l2_m2m_create_context(V4L2m2mPriv *priv, V4L2m2mContext **s);
 
 
 /**
  * Probes the video nodes looking for the required codec capabilities.
  *
- * @param[in] ctx The AVCodecContext instantiated by the encoder/decoder.
+ * @param[in] ctx The V4L2m2mPriv instantiated by the encoder/decoder.
  *
  * @returns 0 if a driver is found, a negative number otherwise.
  */
-int ff_v4l2_m2m_codec_init(AVCodecContext *avctx);
+int ff_v4l2_m2m_codec_init(V4L2m2mPriv *priv);
 
 /**
  * Releases all the codec resources if all AVBufferRefs have been returned to the
  * ctx. Otherwise keep the driver open.
  *
- * @param[in] The AVCodecContext instantiated by the encoder/decoder.
+ * @param[in] The V4L2m2mPriv instantiated by the encoder/decoder.
  *
  * @returns 0
  *
  */
-int ff_v4l2_m2m_codec_end(AVCodecContext *avctx);
+int ff_v4l2_m2m_codec_end(V4L2m2mPriv *priv);
 
 /**
  * Reinitializes the V4L2m2mContext when the driver cannot continue processing
diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c
index 5fb8ddd542..596e435463 100644
--- a/libavcodec/v4l2_m2m_dec.c
+++ b/libavcodec/v4l2_m2m_dec.c
@@ -169,9 +169,10 @@  static av_cold int v4l2_decode_init(AVCodecContext *avctx)
 {
     V4L2Context *capture, *output;
     V4L2m2mContext *s;
+    V4L2m2mPriv *priv = avctx->priv_data;
     int ret;
 
-    ret = ff_v4l2_m2m_create_context(avctx, &s);
+    ret = ff_v4l2_m2m_create_context(priv, &s);
     if (ret < 0)
         return ret;
 
@@ -191,19 +192,24 @@  static av_cold int v4l2_decode_init(AVCodecContext *avctx)
     capture->av_codec_id = AV_CODEC_ID_RAWVIDEO;
     capture->av_pix_fmt = avctx->pix_fmt;
 
-    ret = ff_v4l2_m2m_codec_init(avctx);
+    ret = ff_v4l2_m2m_codec_init(priv);
     if (ret) {
-        V4L2m2mPriv *priv = avctx->priv_data;
         av_log(avctx, AV_LOG_ERROR, "can't configure decoder\n");
         s->self_ref = NULL;
         av_buffer_unref(&priv->context_ref);
 
         return ret;
     }
+    s->avctx = avctx;
 
     return v4l2_prepare_decoder(s);
 }
 
+static av_cold int v4l2_decode_close(AVCodecContext *avctx)
+{
+    return ff_v4l2_m2m_codec_end(avctx->priv_data);
+}
+
 #define OFFSET(x) offsetof(V4L2m2mPriv, x)
 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
 
@@ -231,7 +237,7 @@  AVCodec ff_ ## NAME ## _v4l2m2m_decoder = { \
     .priv_class     = &v4l2_m2m_ ## NAME ## _dec_class,\
     .init           = v4l2_decode_init,\
     .receive_frame  = v4l2_receive_frame,\
-    .close          = ff_v4l2_m2m_codec_end,\
+    .close          = v4l2_decode_close,\
     .bsfs           = bsf_name, \
     .capabilities   = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY | \
                       AV_CODEC_CAP_AVOID_PROBING, \
diff --git a/libavcodec/v4l2_m2m_enc.c b/libavcodec/v4l2_m2m_enc.c
index a0d5bcf760..8014e442a8 100644
--- a/libavcodec/v4l2_m2m_enc.c
+++ b/libavcodec/v4l2_m2m_enc.c
@@ -285,9 +285,10 @@  static av_cold int v4l2_encode_init(AVCodecContext *avctx)
 {
     V4L2Context *capture, *output;
     V4L2m2mContext *s;
+    V4L2m2mPriv *priv = avctx->priv_data;
     int ret;
 
-    ret = ff_v4l2_m2m_create_context(avctx, &s);
+    ret = ff_v4l2_m2m_create_context(priv, &s);
     if (ret < 0)
         return ret;
 
@@ -306,15 +307,21 @@  static av_cold int v4l2_encode_init(AVCodecContext *avctx)
     capture->av_codec_id = avctx->codec_id;
     capture->av_pix_fmt = AV_PIX_FMT_NONE;
 
-    ret = ff_v4l2_m2m_codec_init(avctx);
+    ret = ff_v4l2_m2m_codec_init(priv);
     if (ret) {
         av_log(avctx, AV_LOG_ERROR, "can't configure encoder\n");
         return ret;
     }
+    s->avctx = avctx;
 
     return v4l2_prepare_encoder(s);
 }
 
+static av_cold int v4l2_encode_close(AVCodecContext *avctx)
+{
+    return ff_v4l2_m2m_codec_end(avctx->priv_data);
+}
+
 #define OFFSET(x) offsetof(V4L2m2mPriv, x)
 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
 
@@ -343,7 +350,7 @@  AVCodec ff_ ## NAME ## _v4l2m2m_encoder = { \
     .init           = v4l2_encode_init,\
     .send_frame     = v4l2_send_frame,\
     .receive_packet = v4l2_receive_packet,\
-    .close          = ff_v4l2_m2m_codec_end,\
+    .close          = v4l2_encode_close,\
     .capabilities   = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY, \
     .wrapper_name   = "v4l2m2m", \
 };