[FFmpeg-devel] FireWire DV/HDV input device using libiec61883

Stefano Sabatini stefasab at gmail.com
Sun Jul 1 01:24:05 CEST 2012


On date Saturday 2012-06-30 16:35:25 +0200, Georg Lippitsch encoded:
> Hi,
> 
> since it's quite a long time ago I posted my first version of the
> FireWire input patch, I start a new thread.
> Here is a new version of the patch, which uses the new Linux kernel
> FireWire stack and libiec61883 instead of the old deprecated one.
> 
> I fixed most of the issues discussed in the former thread, and also
> rewrote the capture loop using threads. This allows stable
> operation, even if iec61883_read_packet() is not called frequently
> enough. If incoming frames are not processed fast enough, they can
> be buffered up to a specified limit.
> 
> 
> Regards,
> 
> Georg

> From 0551eba2b5164e9c277a07d0b9a11f8ee47b4c3d Mon Sep 17 00:00:00 2001
> From: Georg Lippitsch <georg.lippitsch at gmx.at>
> Date: Mon, 23 Apr 2012 16:01:17 +0200
> Subject: [PATCH] FireWire DV/HDV input device using libiec61883
> 
> ---
>  configure                |    3 +
>  doc/indevs.texi          |   49 +++++
>  libavdevice/Makefile     |    1 +
>  libavdevice/alldevices.c |    1 +
>  libavdevice/iec61883.c   |  461 ++++++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 515 insertions(+), 0 deletions(-)
>  create mode 100644 libavdevice/iec61883.c
> 
> diff --git a/configure b/configure
> index b3719f8..1723197 100755
> --- a/configure
> +++ b/configure
> @@ -1627,6 +1627,7 @@ dshow_indev_deps="IBaseFilter"
>  dshow_indev_extralibs="-lpsapi -lole32 -lstrmiids -luuid"
>  dv1394_indev_deps="dv1394 dv_demuxer"
>  fbdev_indev_deps="linux_fb_h"
> +iec61883_indev_deps="iec61883"
>  jack_indev_deps="jack_jack_h sem_timedwait"
>  lavfi_indev_deps="avfilter"
>  libcdio_indev_deps="libcdio"
> @@ -2764,6 +2765,7 @@ case $target_os in
>      linux)
>          add_cppflags -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600
>          enable dv1394
> +        enable iec61883
>          ;;
>      irix*)
>          target_os=irix
> @@ -3194,6 +3196,7 @@ enabled avisynth   && require2 vfw32 "windows.h vfw.h" AVIFileInit -lavifil32
>  enabled fontconfig && require_pkg_config fontconfig "fontconfig/fontconfig.h" FcInit
>  enabled frei0r     && { check_header frei0r.h || die "ERROR: frei0r.h header not found"; }
>  enabled gnutls     && require_pkg_config gnutls gnutls/gnutls.h gnutls_global_init
> +enabled iec61883   && require libiec61883 libiec61883/iec61883.h iec61883_cmp_connect -lraw1394 -lavc1394 -lrom1394 -liec61883
>  enabled libaacplus && require  "libaacplus >= 2.0.0" aacplus.h aacplusEncOpen -laacplus
>  enabled libass     && require_pkg_config libass ass/ass.h ass_library_init
>  enabled libbluray  && require libbluray libbluray/bluray.h bd_open -lbluray
> diff --git a/doc/indevs.texi b/doc/indevs.texi
> index e699e11..2596d41 100644
> --- a/doc/indevs.texi
> +++ b/doc/indevs.texi
> @@ -179,6 +179,55 @@ ffmpeg -f fbdev -frames:v 1 -r 1 -i /dev/fb0 screenshot.jpeg
>  
>  See also @url{http://linux-fbdev.sourceforge.net/}, and fbset(1).
>  
> + at section iec61883
> +
> +FireWire DV/HDV input device using libiec61883.
> +
> +The iec61883 capture device supports capturing from a video device
> +connected via IEEE1394 (FireWire), using libiec61883 and the new Linux
> +FireWire stack (juju). This is the default DV/HDV input method in Linux
> +Kernel 2.6.37 and later, since the old FireWire stack was removed.
> +
> +Specify the FireWire port to be used as input file, or "auto"
> +to choose the first port connected.
> +
> + at subsection Options
> +
> + at table @option
> +
> + at item dvtype
> +Override autodetection of DV/HDV. This should only be used if auto
> +detection does not work, or if usage of a different device type
> +should be prohibited. Treating a DV device as HDV (or vice versa) will
> +not work and result in undefined behavior.
> +The values @option{auto}, @option{dv} and @option{hdv} are supported.
> +
> + at item dvbuffer
> +Maxiumum size of buffer for incoming data, in frames. For DV, this

Set maximum ...

> +is an exact value. For HDV, it is not frame exact, since HDV does
> +not have a fixed frame size.

> +
> + at end table
> +
> + at subsection Examples
> +
> + at itemize
> +
> + at item
> +Grab and show the input of a FireWire DV/HDV device.
> + at example
> +ffplay -f iec61883 -i auto
> + at end example
> +
> + at item
> +Grab and record the input of a FireWire DV/HDV device,
> +using a packet buffer of 100000 packets if the source is HDV.
> + at example
> +ffmpeg -f iec61883 -i auto -hdvbuffer 100000 out.mpg
> + at end example
> +
> + at end itemize
> +
>  @section jack
>  
>  JACK input device.
> diff --git a/libavdevice/Makefile b/libavdevice/Makefile
> index 7f0c1d3..3db43fa 100644
> --- a/libavdevice/Makefile
> +++ b/libavdevice/Makefile
> @@ -19,6 +19,7 @@ OBJS-$(CONFIG_DSHOW_INDEV)               += dshow.o dshow_enummediatypes.o \
>                                              dshow_pin.o dshow_common.o
>  OBJS-$(CONFIG_DV1394_INDEV)              += dv1394.o
>  OBJS-$(CONFIG_FBDEV_INDEV)               += fbdev.o
> +OBJS-$(CONFIG_IEC61883_INDEV)            += iec61883.o
>  OBJS-$(CONFIG_JACK_INDEV)                += jack_audio.o timefilter.o
>  OBJS-$(CONFIG_LAVFI_INDEV)               += lavfi.o
>  OBJS-$(CONFIG_OPENAL_INDEV)              += openal-dec.o
> diff --git a/libavdevice/alldevices.c b/libavdevice/alldevices.c
> index 86ebfee..2a0bffb 100644
> --- a/libavdevice/alldevices.c
> +++ b/libavdevice/alldevices.c
> @@ -43,6 +43,7 @@ void avdevice_register_all(void)
>      REGISTER_INDEV    (DSHOW, dshow);
>      REGISTER_INDEV    (DV1394, dv1394);
>      REGISTER_INDEV    (FBDEV, fbdev);
> +    REGISTER_INDEV    (IEC61883, iec61883);
>      REGISTER_INDEV    (JACK, jack);
>      REGISTER_INDEV    (LAVFI, lavfi);
>      REGISTER_INDEV    (OPENAL, openal);
> diff --git a/libavdevice/iec61883.c b/libavdevice/iec61883.c
> new file mode 100644
> index 0000000..abbaa34
> --- /dev/null
> +++ b/libavdevice/iec61883.c
> @@ -0,0 +1,461 @@
> +
> +/*
> + * libiec61883 interface
> + * Copyright (c) 2012 Georg Lippitsch <georg.lippitsch at gmx.at>
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#include <sys/poll.h>
> +#include <libraw1394/raw1394.h>
> +#include <libavc1394/avc1394.h>
> +#include <libavc1394/rom1394.h>
> +#include <libiec61883/iec61883.h>
> +#include "libavformat/dv.h"
> +#include "libavformat/mpegts.h"
> +#include "libavutil/opt.h"
> +#include "avdevice.h"
> +
> +#define THREADS HAVE_PTHREADS
> +
> +#if THREADS
> +#include <pthread.h>
> +#endif
> +
> +#define MOTDCT_SPEC_ID      0x00005068
> +#define IEC61883_AUTO       0
> +#define IEC61883_DV         1
> +#define IEC61883_HDV        2
> +
> +/**
> + * For DV, one packet corresponds exactly to one frame.
> + * For HDV, these are MPEG2 transport stream packets.
> + * The queue is implemented as linked list.
> + */
> +typedef struct DVPacket {
> +    uint8_t *buf;                       ///< actual buffer data
> +    int len;                            ///< size of buffer allocated
> +    struct DVPacket *next;              ///< next DVPacket
> +} DVPacket;
> +
> +struct iec61883_data {
> +    AVClass *class;

> +    raw1394handle_t handle;             ///< handle for libraw1394

nit: handle -> raw1394? 

Consistent with below variable, and more descriptive.

> +    iec61883_dv_fb_t iec61883_dv;       ///< handle for libiec61883 when used with DV
> +    iec61883_mpeg2_t iec61883_mpeg2;    ///< handle for libiec61883 when used with HDV
> +
> +    DVDemuxContext *dv_demux;           ///< generic DV muxing/demuxing context
> +    MpegTSContext *mpeg_demux;          ///< generic HDV muxing/demuxing context
> +
> +    DVPacket *queue_first;              ///< first element of packet queue
> +    DVPacket *queue_last;               ///< last element of packet queue
> +
> +    int packets;                        ///< Number of packets queued
> +    int max_packets;                    ///< Max. number of packets in queue
> +
> +    int bandwidth;                      ///< returned by libiec61883
> +    int channel;                        ///< returned by libiec61883
> +    int input_port;                     ///< returned by libiec61883
> +    int type;                           ///< Stream type, to distinguish DV/HDV
> +    int node;                           ///< returned by libiec61883
> +    int output_port;                    ///< returned by libiec61883
> +    int thread_loop;                    ///< Condition for thread while-loop
> +    int receiving;                      ///< True as soon data from device available
> +    int eof;                            ///< True as soon as no more data available
> +
> +    struct pollfd raw1394_poll;         ///< to poll for new data from libraw1394
> +
> +    /** Parse function for DV/HDV differs, so this is set before packets arrive */
> +    int (*parse_queue)(struct iec61883_data *dv, AVPacket *pkt);
> +
> +#if THREADS

> +    pthread_t receive_thread;

Nit++: receive_task_thread;

> +    pthread_mutex_t mutex;
> +    pthread_cond_t cond;
> +#endif
> +};
> +
> +static int iec61883_callback(unsigned char *data, int length,
> +                             int complete, void *callback_data)
> +{
> +    struct iec61883_data *dv = callback_data;
> +    DVPacket *packet;
> +    int ret;
> +
> +#ifdef THREADS
> +    pthread_mutex_lock(&dv->mutex);
> +#endif
> +
> +    if (dv->packets >= dv->max_packets) {
> +        av_log(NULL, AV_LOG_ERROR, "DV packet queue overrun, dropping.\n");
> +        ret = 0;
> +        goto exit;
> +    }
> +
> +    packet = av_mallocz(sizeof(*packet));
> +    if (!packet) {
> +        ret = -1;
> +        goto exit;
> +    }
> +
> +    packet->buf = av_malloc(length);
> +    if (!packet->buf) {
> +        ret = -1;
> +        goto exit;
> +    }
> +    packet->len = length;
> +
> +    memcpy(packet->buf, data, length);
> +
> +    if (dv->queue_first) {
> +        dv->queue_last->next = packet;
> +        dv->queue_last = packet;
> +    } else {
> +        dv->queue_first = packet;
> +        dv->queue_last = packet;
> +    }
> +    dv->packets++;
> +
> +    ret = 0;
> +
> +exit:
> +#ifdef THREADS
> +    pthread_cond_signal(&dv->cond);
> +    pthread_mutex_unlock(&dv->mutex);
> +#endif
> +    return ret;
> +}
> +
> +#ifdef THREADS
> +static void *iec61883_receive_task(void *opaque)
> +{
> +    struct iec61883_data *dv = (struct iec61883_data *)opaque;
> +    int result;
> +
> +    dv->thread_loop = 1;
> +
> +    while (dv->thread_loop) {
> +        while ((result = poll(&dv->raw1394_poll, 1, 200)) < 0) {
> +            if (!(errno == EAGAIN || errno == EINTR)) {

nit+: the De-Morgan equivalent (errno != EAGAIN && errno != EINTR)
looks more readable to me, but that's just a personal opinion


> +                av_log(NULL, AV_LOG_ERROR, "Raw1394 poll error occurred.\n");

Nit: maybe 
     av_log(NULL, AV_LOG_ERROR, "Raw1394 poll error occurred: %s\n", av_err2str(AVERROR(errno)));

also I wonder if you can avoid the NULL context.

> +                return NULL;
> +            }
> +        }
> +        if (result > 0 && ((dv->raw1394_poll.revents & POLLIN)
> +                           || (dv->raw1394_poll.revents & POLLPRI))) {
> +            dv->receiving = 1;
> +            raw1394_loop_iterate(dv->handle);
> +        } else if (dv->receiving) {
> +            av_log(NULL, AV_LOG_ERROR, "No more input data available\n");
> +            pthread_mutex_lock(&dv->mutex);
> +            dv->eof = 1;
> +            pthread_cond_signal(&dv->cond);
> +            pthread_mutex_unlock(&dv->mutex);
> +            return NULL;
> +        }
> +    }
> +
> +    return NULL;
> +}
> +#endif
> +
> +static int iec61883_parse_queue_dv(struct iec61883_data *dv, AVPacket *pkt)
> +{
> +    DVPacket *packet;
> +    int size;
> +
> +    size = avpriv_dv_get_packet(dv->dv_demux, pkt);
> +    if (size > 0)
> +        return size;
> +
> +    packet = dv->queue_first;
> +    if (!packet)
> +        return -1;
> +
> +    size = avpriv_dv_produce_packet(dv->dv_demux, pkt,
> +                                    packet->buf, packet->len, -1);
> +    pkt->destruct = av_destruct_packet;
> +    dv->queue_first = packet->next;
> +    av_free(packet);
> +    dv->packets--;
> +
> +    if (size > 0)
> +        return size;
> +
> +    return -1;
> +}
> +
> +static int iec61883_parse_queue_hdv(struct iec61883_data *dv, AVPacket *pkt)
> +{
> +    DVPacket *packet;
> +    int size;
> +
> +    while (dv->queue_first) {
> +        packet = dv->queue_first;
> +        size = ff_mpegts_parse_packet(dv->mpeg_demux, pkt, packet->buf,
> +                                      packet->len);
> +        dv->queue_first = packet->next;
> +        av_free(packet->buf);
> +        av_free(packet);
> +        dv->packets--;
> +
> +        if (size > 0)
> +            return size;
> +    }
> +
> +    return -1;
> +}
> +
> +static int iec61883_read_header(AVFormatContext *context)
> +{
> +    struct iec61883_data *dv = context->priv_data;
> +    struct raw1394_portinfo pinf[16];

nit++: pinf -> portinfo?

> +    rom1394_directory rom_dir;
> +    char *endptr;
> +    int inport;

> +    int ports;

nit: nb_ports should clarify (ports/port is a bit confusing)

> +    int port = -1;
> +    int response;
> +    int i, j = 0;
> +
> +    dv->input_port = -1;
> +    dv->output_port = -1;
> +    dv->channel = -1;
> +
> +    dv->handle = raw1394_new_handle();
> +
> +    if (!dv->handle) {
> +        av_log(context, AV_LOG_ERROR, "Failed to open IEEE1394 interface.\n");
> +        return AVERROR(EIO);
> +    }
> +
> +    if ((ports = raw1394_get_port_info(dv->handle, pinf, 16)) < 0) {
> +        av_log(context, AV_LOG_ERROR, "Failed to get number of IEEE1394 ports.\n");
> +        goto fail;
> +    }
> +
> +    inport = strtol(context->filename, &endptr, 10);
> +    if (endptr != context->filename && *endptr == '\0') {
> +        av_log(context, AV_LOG_INFO, "Selecting IEEE1394 port: %d\n", inport);
> +        j = inport;
> +        ports = inport + 1;
> +    } else if (strcmp(context->filename, "auto")) {
> +        av_log(context, AV_LOG_ERROR, "Invalid input \"%s\", you should specify "
> +               "\"auto\" for auto-detection, or the port number.\n", context->filename);
> +        goto fail;
> +    }
> +
> +    /* Select first AV/C tape recorder player node */
> +
> +    for (; j < ports && port==-1; ++j) {
> +        if (raw1394_set_port(dv->handle, j)) {
> +            av_log(context, AV_LOG_ERROR, "Failed setting IEEE1394 port.\n");
> +            goto fail;
> +        }
> +        for (i=0; i<raw1394_get_nodecount(dv->handle); ++i) {
> +            if (rom1394_get_directory(dv->handle, i, &rom_dir) < 0)
> +                continue;
> +            if (((rom1394_get_node_type(&rom_dir) == ROM1394_NODE_TYPE_AVC) &&
> +                 avc1394_check_subunit_type(dv->handle, i, AVC1394_SUBUNIT_TYPE_VCR)) ||
> +                (rom_dir.unit_spec_id == MOTDCT_SPEC_ID)) {
> +                rom1394_free_directory(&rom_dir);
> +                dv->node = i;
> +                port = j;
> +                break;
> +            }
> +            rom1394_free_directory(&rom_dir);
> +        }
> +    }
> +
> +    if (port == -1) {
> +        av_log(context, AV_LOG_ERROR, "No AV/C devices found.\n");
> +        goto fail;
> +    }
> +
> +    /* Find out if device is DV or HDV */
> +
> +    if (dv->type == IEC61883_AUTO) {
> +        response = avc1394_transaction(dv->handle, dv->node,
> +                                       AVC1394_CTYPE_STATUS |
> +                                       AVC1394_SUBUNIT_TYPE_TAPE_RECORDER |
> +                                       AVC1394_SUBUNIT_ID_0 |
> +                                       AVC1394_VCR_COMMAND_OUTPUT_SIGNAL_MODE |
> +                                       0xFF, 2);
> +        response = AVC1394_GET_OPERAND0(response);
> +        dv->type = (response == 0x10 || response == 0x90 || response == 0x1A || response == 0x9A) ?
> +            IEC61883_HDV : IEC61883_DV;
> +    }
> +
> +    /* Connect to device, and do initialization */
> +
> +    dv->channel = iec61883_cmp_connect(dv->handle, dv->node, &dv->output_port,
> +                                       raw1394_get_local_id(dv->handle),
> +                                       &dv->input_port, &dv->bandwidth);
> +
> +    if (dv->channel < 0)
> +        dv->channel = 63;
> +
> +    if (!dv->max_packets)
> +        dv->max_packets = 100;
> +
> +    if (dv->type == IEC61883_HDV) {
> +        avformat_new_stream(context, NULL);
> +
> +        dv->mpeg_demux = ff_mpegts_parse_open(context);
> +        if (!dv->mpeg_demux)
> +            goto fail;
> +
> +        dv->parse_queue = iec61883_parse_queue_hdv;
> +
> +        dv->iec61883_mpeg2 = iec61883_mpeg2_recv_init(dv->handle,
> +                                                      (iec61883_mpeg2_recv_t)iec61883_callback,
> +                                                      dv);
> +
> +        dv->max_packets *= 766;

> +    } else {

please specify in a comment this is the DV case (or with an assert if
you prefer), will improve readability somewhat

> +        dv->dv_demux = avpriv_dv_init_demux(context);
> +        if (!dv->dv_demux)
> +            goto fail;
> +
> +        dv->parse_queue = iec61883_parse_queue_dv;
> +
> +        dv->iec61883_dv = iec61883_dv_fb_init(dv->handle, iec61883_callback, dv);
> +    }
> +
> +    dv->raw1394_poll.fd = raw1394_get_fd(dv->handle);
> +    dv->raw1394_poll.events = POLLIN | POLLERR | POLLHUP | POLLPRI;
> +
> +    /* Actually start receiving */
> +

> +    if (dv->type == IEC61883_HDV)
> +        iec61883_mpeg2_recv_start(dv->iec61883_mpeg2, dv->channel);
> +    else
> +        iec61883_dv_fb_start(dv->iec61883_dv, dv->channel);

I wish developers were less schizofrenic when they were designing the
API.

> +
> +#if THREADS
> +    pthread_mutex_init(&dv->mutex, NULL);
> +    pthread_cond_init(&dv->cond, NULL);
> +    pthread_create(&dv->receive_thread, NULL, iec61883_receive_task, dv);
> +#endif
> +
> +    return 0;
> +
> +fail:
> +    raw1394_destroy_handle(dv->handle);
> +    return AVERROR(EIO);
> +}
> +
> +static int iec61883_read_packet(AVFormatContext *context, AVPacket *pkt)
> +{
> +    struct iec61883_data *dv = context->priv_data;
> +    int size;
> +
> +    /**
> +     * Try to parse frames from queue
> +     */
> +
> +#ifdef THREADS
> +    pthread_mutex_lock(&dv->mutex);
> +    while ((size = dv->parse_queue(dv, pkt)) == -1)
> +        if (!dv->eof)
> +            pthread_cond_wait(&dv->cond, &dv->mutex);
> +        else
> +            break;
> +    pthread_mutex_unlock(&dv->mutex);
> +#else
> +    int result;
> +    while ((size = dv->parse_queue(dv, pkt)) == -1) {

> +        while ((result = poll(&dv->raw1394_poll, 1, 200)) < 0) {
> +            if (!(errno == EAGAIN || errno == EINTR)) {
> +                av_log(context, AV_LOG_ERROR, "Raw1394 poll error occurred.\n");
> +                return AVERROR(EIO);
> +            }
> +        }
> +        if (result > 0 && ((dv->raw1394_poll.revents & POLLIN)
> +                           || (dv->raw1394_poll.revents & POLLPRI)))
> +            raw1394_loop_iterate(dv->handle);

Maybe can be factorized with iec61883_receive_task().

> +        else {
> +            av_log(context, AV_LOG_ERROR,
> +                   "No more input data available.\n");
> +            dv->eof = 1;
> +        }
> +    }
> +#endif
> +
> +    return size;
> +}
> +
> +static int iec61883_close(AVFormatContext * context)
> +{
> +    struct iec61883_data *dv = context->priv_data;
> +
> +#if THREADS
> +    dv->thread_loop = 0;
> +    pthread_join(dv->receive_thread, NULL);
> +    pthread_cond_destroy(&dv->cond);
> +    pthread_mutex_destroy(&dv->mutex);
> +#endif
> +
> +    if (dv->type == IEC61883_HDV) {
> +        iec61883_mpeg2_recv_stop(dv->iec61883_mpeg2);
> +        iec61883_mpeg2_close(dv->iec61883_mpeg2);
> +    } else {
> +        iec61883_dv_fb_stop(dv->iec61883_dv);
> +        iec61883_dv_fb_close(dv->iec61883_dv);
> +    }
> +    while (dv->queue_first) {
> +        DVPacket *packet = dv->queue_first;
> +        dv->queue_first = packet->next;
> +        av_free(packet->buf);
> +        av_free(packet);
> +    }
> +
> +    iec61883_cmp_disconnect(dv->handle, dv->node, dv->output_port,
> +                            raw1394_get_local_id(dv->handle),
> +                            dv->input_port, dv->channel, dv->bandwidth);
> +
> +    raw1394_destroy_handle(dv->handle);
> +
> +    return 0;
> +}
> +
> +static const AVOption options[] = {

> +    { "dvtype", "Override autodetection of DV/HDV", offsetof(struct iec61883_data, type), AV_OPT_TYPE_INT, {.dbl = IEC61883_AUTO}, IEC61883_AUTO, IEC61883_HDV, AV_OPT_FLAG_DECODING_PARAM, "dvtype" },
> +    { "auto",   "Auto detect DV/HDV", 0, AV_OPT_TYPE_CONST, {.dbl = IEC61883_AUTO}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "dvtype" },
> +    { "dv",     "Force device being treated as DV device", 0, AV_OPT_TYPE_CONST, {.dbl = IEC61883_DV},   0, 0, AV_OPT_FLAG_DECODING_PARAM, "dvtype" },
> +    { "hdv" ,   "Force device being treated as HDV device", 0, AV_OPT_TYPE_CONST, {.dbl = IEC61883_HDV},  0, 0, AV_OPT_FLAG_DECODING_PARAM, "dvtype" },
> +    { "dvbuffer", "Set queue size (in packets)", offsetof(struct iec61883_data, max_packets), AV_OPT_TYPE_INT, {.dbl = 0}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
> +    { NULL },
> +};

Please no Uppercasing in options

[...]

Again, add yourself to MAINTAINERS if you wish to maintain this
device. Also feel free to ignore all the comments marked with "nit" if
they make no sense to you.

Apart from that, if there are no more comments from other developers
and you say the patch is tested enough I suppose it is safe to commit
it.
-- 
FFmpeg = Frightening Fierce Meaningful Programmable Extroverse Guru


More information about the ffmpeg-devel mailing list