diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c index 3f8a510331..1f1b8347dc 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", \ };