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)
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;
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 */
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)
}
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");
/* DECODER_CMD is optional */
if (errno == ENOTTY)
return ff_v4l2_context_set_status(ctx, VIDIOC_STREAMOFF);
+ else
+ return AVERROR(errno);
}
return 0;
/* ENCODER_CMD is optional */
if (errno == ENOTTY)
return ff_v4l2_context_set_status(ctx, VIDIOC_STREAMOFF);
+ else
+ return AVERROR(errno);
}
return 0;
/* 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;
}
avbuf = v4l2_getfree_v4l2buf(ctx);
if (!avbuf)
- return AVERROR(ENOMEM);
+ return AVERROR(EAGAIN);
ret = ff_v4l2_buffer_avpkt_to_buf(pkt, avbuf);
if (ret)
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;
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;
if (ret)
return ret;
- fmt.update_avfmt = 1;
+ fmt.update_avfmt = !probe;
v4l2_save_to_context(ctx, &fmt);
/* format has been tried already */
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));
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;
}
}
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;
}