X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fv4l2_context.c;h=bdc2b841530adc3e9d9ec6e5adafaa1e029996ab;hb=9f6a06d9271a11781717fd0b134db2bcd716508e;hp=efcb0426e49060f2c70432240a761141dbf86909;hpb=1b98bfb932ad36667ea7f18e24c54978623f6654;p=ffmpeg diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c index efcb0426e49..bdc2b841530 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) @@ -63,6 +63,24 @@ static inline unsigned int v4l2_get_height(struct v4l2_format *fmt) return V4L2_TYPE_IS_MULTIPLANAR(fmt->type) ? fmt->fmt.pix_mp.height : fmt->fmt.pix.height; } +static AVRational v4l2_get_sar(V4L2Context *ctx) +{ + struct AVRational sar = { 0, 1 }; + struct v4l2_cropcap cropcap; + int ret; + + memset(&cropcap, 0, sizeof(cropcap)); + cropcap.type = ctx->type; + + ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_CROPCAP, &cropcap); + if (ret) + return sar; + + sar.num = cropcap.pixelaspect.numerator; + sar.den = cropcap.pixelaspect.denominator; + return sar; +} + static inline unsigned int v4l2_resolution_changed(V4L2Context *ctx, struct v4l2_format *fmt2) { struct v4l2_format *fmt1 = &ctx->format; @@ -96,7 +114,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 */ @@ -172,12 +190,14 @@ static int v4l2_handle_event(V4L2Context *ctx) if (full_reinit) { s->output.height = v4l2_get_height(&out_fmt); s->output.width = v4l2_get_width(&out_fmt); + s->output.sample_aspect_ratio = v4l2_get_sar(&s->output); } reinit = v4l2_resolution_changed(&s->capture, &cap_fmt); if (reinit) { s->capture.height = v4l2_get_height(&cap_fmt); s->capture.width = v4l2_get_width(&cap_fmt); + s->capture.sample_aspect_ratio = v4l2_get_sar(&s->capture); } if (full_reinit || reinit) @@ -193,7 +213,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"); @@ -226,6 +247,8 @@ static int v4l2_stop_decode(V4L2Context *ctx) /* DECODER_CMD is optional */ if (errno == ENOTTY) return ff_v4l2_context_set_status(ctx, VIDIOC_STREAMOFF); + else + return AVERROR(errno); } return 0; @@ -244,6 +267,8 @@ static int v4l2_stop_encode(V4L2Context *ctx) /* ENCODER_CMD is optional */ if (errno == ENOTTY) return ff_v4l2_context_set_status(ctx, VIDIOC_STREAMOFF); + else + return AVERROR(errno); } return 0; @@ -263,6 +288,12 @@ static V4L2Buffer* v4l2_dequeue_v4l2buf(V4L2Context *ctx, int timeout) /* if we are draining and there are no more capture buffers queued in the driver we are done */ if (!V4L2_TYPE_IS_OUTPUT(ctx->type) && ctx_to_m2mctx(ctx)->draining) { for (i = 0; i < ctx->num_buffers; i++) { + /* capture buffer initialization happens during decode hence + * detection happens at runtime + */ + if (!ctx->buffers) + break; + if (ctx->buffers[i].status == V4L2BUF_IN_DRIVER) goto start; } @@ -562,7 +593,7 @@ int ff_v4l2_context_enqueue_packet(V4L2Context* ctx, const AVPacket* pkt) avbuf = v4l2_getfree_v4l2buf(ctx); if (!avbuf) - return AVERROR(ENOMEM); + return AVERROR(EAGAIN); ret = ff_v4l2_buffer_avpkt_to_buf(pkt, avbuf); if (ret) @@ -571,16 +602,16 @@ int ff_v4l2_context_enqueue_packet(V4L2Context* ctx, const AVPacket* pkt) return ff_v4l2_buffer_enqueue(avbuf); } -int ff_v4l2_context_dequeue_frame(V4L2Context* ctx, AVFrame* frame) +int ff_v4l2_context_dequeue_frame(V4L2Context* ctx, AVFrame* frame, int timeout) { V4L2Buffer* avbuf = NULL; /* - * blocks until: + * timeout=-1 blocks until: * 1. decoded frame available * 2. an input buffer is ready to be dequeued */ - avbuf = v4l2_dequeue_v4l2buf(ctx, -1); + avbuf = v4l2_dequeue_v4l2buf(ctx, timeout); if (!avbuf) { if (ctx->done) return AVERROR_EOF; @@ -611,7 +642,7 @@ int ff_v4l2_context_dequeue_packet(V4L2Context* ctx, AVPacket* pkt) return ff_v4l2_buffer_buf_to_avpkt(pkt, avbuf); } -int ff_v4l2_context_get_format(V4L2Context* ctx) +int ff_v4l2_context_get_format(V4L2Context* ctx, int probe) { struct v4l2_format_update fmt = { 0 }; int ret; @@ -621,7 +652,7 @@ int ff_v4l2_context_get_format(V4L2Context* ctx) if (ret) return ret; - fmt.update_avfmt = 1; + fmt.update_avfmt = !probe; v4l2_save_to_context(ctx, &fmt); /* format has been tried already */ @@ -678,23 +709,24 @@ int ff_v4l2_context_init(V4L2Context* ctx) req.memory = V4L2_MEMORY_MMAP; req.type = ctx->type; ret = ioctl(s->fd, VIDIOC_REQBUFS, &req); - if (ret < 0) + if (ret < 0) { + av_log(logger(ctx), AV_LOG_ERROR, "%s VIDIOC_REQBUFS failed: %s\n", ctx->name, strerror(errno)); return AVERROR(errno); + } ctx->num_buffers = req.count; ctx->buffers = av_mallocz(ctx->num_buffers * sizeof(V4L2Buffer)); if (!ctx->buffers) { - av_log(logger(ctx), AV_LOG_ERROR, "%s malloc enomem\n", ctx->name); - return AVERROR(ENOMEM); + av_log(logger(ctx), AV_LOG_ERROR, "%s malloc enomem\n", ctx->name); + return AVERROR(ENOMEM); } for (i = 0; i < req.count; i++) { ctx->buffers[i].context = ctx; ret = ff_v4l2_buffer_initialize(&ctx->buffers[i], i); if (ret < 0) { - av_log(logger(ctx), AV_LOG_ERROR, "%s buffer initialization (%s)\n", ctx->name, av_err2str(ret)); - av_free(ctx->buffers); - return ret; + av_log(logger(ctx), AV_LOG_ERROR, "%s buffer[%d] initialization (%s)\n", ctx->name, i, av_err2str(ret)); + goto error; } } @@ -707,4 +739,12 @@ int ff_v4l2_context_init(V4L2Context* ctx) V4L2_TYPE_IS_MULTIPLANAR(ctx->type) ? ctx->format.fmt.pix_mp.plane_fmt[0].bytesperline : ctx->format.fmt.pix.bytesperline); return 0; + +error: + v4l2_release_buffers(ctx); + + av_free(ctx->buffers); + ctx->buffers = NULL; + + return ret; }