diff mbox series

[FFmpeg-devel,RFC] libavformat/rtpdec_jpeg2000: RTP Demuxing for JPEG2000

Message ID 20200721163849.2887-1-gautamramk@gmail.com
State Superseded
Headers show
Series [FFmpeg-devel,RFC] libavformat/rtpdec_jpeg2000: RTP Demuxing for JPEG2000 | expand

Checks

Context Check Description
andriy/default pending
andriy/make success Make finished
andriy/make_fate success Make fate finished

Commit Message

Gautam Ramakrishnan July 21, 2020, 4:38 p.m. UTC
From: Gautam Ramakrishnan <gautamramk@gmail.com>

This patch adds support to receive JPEG2000 RTP streams.
---
 libavformat/Makefile          |   1 +
 libavformat/rtpdec.c          |   1 +
 libavformat/rtpdec_formats.h  |   1 +
 libavformat/rtpdec_jpeg2000.c | 116 ++++++++++++++++++++++++++++++++++
 4 files changed, 119 insertions(+)
 create mode 100644 libavformat/rtpdec_jpeg2000.c

Comments

Gautam Ramakrishnan July 21, 2020, 4:46 p.m. UTC | #1
On Tue, Jul 21, 2020 at 10:08 PM <gautamramk@gmail.com> wrote:
>
> From: Gautam Ramakrishnan <gautamramk@gmail.com>
>
> This patch adds support to receive JPEG2000 RTP streams.
> ---
>  libavformat/Makefile          |   1 +
>  libavformat/rtpdec.c          |   1 +
>  libavformat/rtpdec_formats.h  |   1 +
>  libavformat/rtpdec_jpeg2000.c | 116 ++++++++++++++++++++++++++++++++++
>  4 files changed, 119 insertions(+)
>  create mode 100644 libavformat/rtpdec_jpeg2000.c
>
> diff --git a/libavformat/Makefile b/libavformat/Makefile
> index 62d8cbb54e..4495047e3a 100644
> --- a/libavformat/Makefile
> +++ b/libavformat/Makefile
> @@ -46,6 +46,7 @@ OBJS-$(CONFIG_RTPDEC)                    += rdt.o                       \
>                                              rtpdec_hevc.o               \
>                                              rtpdec_ilbc.o               \
>                                              rtpdec_jpeg.o               \
> +                                            rtpdec_jpeg2000.o           \
>                                              rtpdec_latm.o               \
>                                              rtpdec_mpa_robust.o         \
>                                              rtpdec_mpeg12.o             \
> diff --git a/libavformat/rtpdec.c b/libavformat/rtpdec.c
> index 3d5b200099..b47dfdfebc 100644
> --- a/libavformat/rtpdec.c
> +++ b/libavformat/rtpdec.c
> @@ -118,6 +118,7 @@ static const RTPDynamicProtocolHandler *rtp_dynamic_protocol_handler_list[] = {
>      &ff_vorbis_dynamic_handler,
>      &ff_vp8_dynamic_handler,
>      &ff_vp9_dynamic_handler,
> +    &ff_jpeg2000_dynamic_handler,
>      &gsm_dynamic_handler,
>      &l24_dynamic_handler,
>      &opus_dynamic_handler,
> diff --git a/libavformat/rtpdec_formats.h b/libavformat/rtpdec_formats.h
> index dad2b8ac1b..78ea4fb384 100644
> --- a/libavformat/rtpdec_formats.h
> +++ b/libavformat/rtpdec_formats.h
> @@ -89,5 +89,6 @@ extern const RTPDynamicProtocolHandler ff_vc2hq_dynamic_handler;
>  extern const RTPDynamicProtocolHandler ff_vorbis_dynamic_handler;
>  extern const RTPDynamicProtocolHandler ff_vp8_dynamic_handler;
>  extern const RTPDynamicProtocolHandler ff_vp9_dynamic_handler;
> +extern const RTPDynamicProtocolHandler ff_jpeg2000_dynamic_handler;
>
>  #endif /* AVFORMAT_RTPDEC_FORMATS_H */
> diff --git a/libavformat/rtpdec_jpeg2000.c b/libavformat/rtpdec_jpeg2000.c
> new file mode 100644
> index 0000000000..b5337a9cdb
> --- /dev/null
> +++ b/libavformat/rtpdec_jpeg2000.c
> @@ -0,0 +1,116 @@
> +/*
> + * Code for the RTP depacketization of JPEG2000.
> + * Copyright (c) 2020 Gautam Ramakrishnan
> + *
> + * 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
> + */
> +
> +/**
> + * @file
> + * @brief JPEG2000 / RTP Code
> + * @author Gautam Ramakrishnan
> + */
> +
> +#include "rtpdec_formats.h"
> +#include "avio_internal.h"
> +#include "internal.h"
> +#include "libavutil/attributes.h"
> +#include "libavutil/avstring.h"
> +#include "libavcodec/get_bits.h"
> +
> +#define PAYLOAD_HDR_SIZ 8
> +
> +/**
> + * RTP/JPEG specific private data.
> + */
> +struct PayloadContext {
> +    AVIOContext *frame;         // current frame buffer
> +    uint32_t    timestamp;      // current frame timestamp
> +};
> +
> +static void jpeg2000_close_context(PayloadContext *data)
> +{
> +    ffio_free_dyn_buf(&data->frame);
> +}
> +
> +static int jpeg2000_parse_packet(AVFormatContext *ctx, PayloadContext *data,
> +                                AVStream *st, AVPacket *pkt, uint32_t *timestamp,
> +                                const uint8_t *buf, int len, uint16_t seq,
> +                                int flags)
> +{
> +    int ret;
> +    int off;
> +
> +    if (len < 8) {
> +        av_log(ctx, AV_LOG_ERROR, "Too short RTP/JPEG packet.\n");
> +        return AVERROR_INVALIDDATA;
> +    }
> +    off = (uint64_t)AV_RB64(buf) & 0xFFFFFF;
> +    buf += 8;
> +    len -= 8;
> +    if (!off) {
> +        /* Skip the current frame in case of the end packet
> +         * has been lost somewhere. */
> +        ffio_free_dyn_buf(&data->frame);
> +
> +        if ((ret = avio_open_dyn_buf(&data->frame)) < 0)
> +            return ret;
> +        data->timestamp = *timestamp;
> +    }
> +    if (!data->frame) {
> +        av_log(ctx, AV_LOG_ERROR,
> +               "Received packet without a start chunk; dropping frame.\n");
> +        return AVERROR(EAGAIN);
> +    }
> +
> +    if (data->timestamp != *timestamp) {
> +        /* Skip the current frame if timestamp is incorrect.
> +         * A start packet has been lost somewhere. */
> +        ffio_free_dyn_buf(&data->frame);
> +        av_log(ctx, AV_LOG_ERROR, "RTP timestamps don't match.\n");
> +        return AVERROR_INVALIDDATA;
> +    }
> +
> +    if (off != avio_tell(data->frame)) {
> +        av_log(ctx, AV_LOG_ERROR,
> +               "Missing packets; dropping frame.\n");
> +        return AVERROR(EAGAIN);
> +    }
> +    /* Copy data to frame buffer. */
> +    avio_write(data->frame, buf, len);
> +
> +    if (flags & RTP_FLAG_MARKER) {
> +        /* Prepare the JPEG2000 packet. */
> +        if ((ret = ff_rtp_finalize_packet(pkt, &data->frame, st->index)) < 0) {
> +            av_log(ctx, AV_LOG_ERROR,
> +                   "Error occurred when getting frame buffer.\n");
> +            return ret;
> +        }
> +
> +        return 0;
> +    }
> +    return AVERROR(EAGAIN);
> +}
> +
> +const RTPDynamicProtocolHandler ff_jpeg2000_dynamic_handler = {
> +    .enc_name           = "jpeg2000",
> +    .codec_type         = AVMEDIA_TYPE_VIDEO,
> +    .codec_id           = AV_CODEC_ID_JPEG2000,
> +    .priv_data_size     = sizeof(PayloadContext),
> +    .parse_packet       = jpeg2000_parse_packet,
> +    .close              = jpeg2000_close_context,
> +};
> --
> 2.17.1
>

This was tested using a GStreamer RTSP server.
An mj2 file was encoded using gst_launch and hosted
using the GStreamer RTSP server.

Additionally I would really appreciate some advice on how
to test the encoder.
From my understanding, in most cases RTSP servers perform
the encoding operations and stream to clients. This would require
me to set up ffmpeg. Is there a good way to do this?
Paul B Mahol July 21, 2020, 5:10 p.m. UTC | #2
How and when this was tested?

On 7/21/20, gautamramk@gmail.com <gautamramk@gmail.com> wrote:
> From: Gautam Ramakrishnan <gautamramk@gmail.com>
>
> This patch adds support to receive JPEG2000 RTP streams.
> ---
>  libavformat/Makefile          |   1 +
>  libavformat/rtpdec.c          |   1 +
>  libavformat/rtpdec_formats.h  |   1 +
>  libavformat/rtpdec_jpeg2000.c | 116 ++++++++++++++++++++++++++++++++++
>  4 files changed, 119 insertions(+)
>  create mode 100644 libavformat/rtpdec_jpeg2000.c
>
> diff --git a/libavformat/Makefile b/libavformat/Makefile
> index 62d8cbb54e..4495047e3a 100644
> --- a/libavformat/Makefile
> +++ b/libavformat/Makefile
> @@ -46,6 +46,7 @@ OBJS-$(CONFIG_RTPDEC)                    += rdt.o
>              \
>                                              rtpdec_hevc.o               \
>                                              rtpdec_ilbc.o               \
>                                              rtpdec_jpeg.o               \
> +                                            rtpdec_jpeg2000.o           \
>                                              rtpdec_latm.o               \
>                                              rtpdec_mpa_robust.o         \
>                                              rtpdec_mpeg12.o             \
> diff --git a/libavformat/rtpdec.c b/libavformat/rtpdec.c
> index 3d5b200099..b47dfdfebc 100644
> --- a/libavformat/rtpdec.c
> +++ b/libavformat/rtpdec.c
> @@ -118,6 +118,7 @@ static const RTPDynamicProtocolHandler
> *rtp_dynamic_protocol_handler_list[] = {
>      &ff_vorbis_dynamic_handler,
>      &ff_vp8_dynamic_handler,
>      &ff_vp9_dynamic_handler,
> +    &ff_jpeg2000_dynamic_handler,
>      &gsm_dynamic_handler,
>      &l24_dynamic_handler,
>      &opus_dynamic_handler,
> diff --git a/libavformat/rtpdec_formats.h b/libavformat/rtpdec_formats.h
> index dad2b8ac1b..78ea4fb384 100644
> --- a/libavformat/rtpdec_formats.h
> +++ b/libavformat/rtpdec_formats.h
> @@ -89,5 +89,6 @@ extern const RTPDynamicProtocolHandler
> ff_vc2hq_dynamic_handler;
>  extern const RTPDynamicProtocolHandler ff_vorbis_dynamic_handler;
>  extern const RTPDynamicProtocolHandler ff_vp8_dynamic_handler;
>  extern const RTPDynamicProtocolHandler ff_vp9_dynamic_handler;
> +extern const RTPDynamicProtocolHandler ff_jpeg2000_dynamic_handler;
>
>  #endif /* AVFORMAT_RTPDEC_FORMATS_H */
> diff --git a/libavformat/rtpdec_jpeg2000.c b/libavformat/rtpdec_jpeg2000.c
> new file mode 100644
> index 0000000000..b5337a9cdb
> --- /dev/null
> +++ b/libavformat/rtpdec_jpeg2000.c
> @@ -0,0 +1,116 @@
> +/*
> + * Code for the RTP depacketization of JPEG2000.
> + * Copyright (c) 2020 Gautam Ramakrishnan
> + *
> + * 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
> + */
> +
> +/**
> + * @file
> + * @brief JPEG2000 / RTP Code
> + * @author Gautam Ramakrishnan
> + */
> +
> +#include "rtpdec_formats.h"
> +#include "avio_internal.h"
> +#include "internal.h"
> +#include "libavutil/attributes.h"
> +#include "libavutil/avstring.h"
> +#include "libavcodec/get_bits.h"
> +
> +#define PAYLOAD_HDR_SIZ 8
> +
> +/**
> + * RTP/JPEG specific private data.
> + */
> +struct PayloadContext {
> +    AVIOContext *frame;         // current frame buffer
> +    uint32_t    timestamp;      // current frame timestamp
> +};
> +
> +static void jpeg2000_close_context(PayloadContext *data)
> +{
> +    ffio_free_dyn_buf(&data->frame);
> +}
> +
> +static int jpeg2000_parse_packet(AVFormatContext *ctx, PayloadContext
> *data,
> +                                AVStream *st, AVPacket *pkt, uint32_t
> *timestamp,
> +                                const uint8_t *buf, int len, uint16_t seq,
> +                                int flags)
> +{
> +    int ret;
> +    int off;
> +
> +    if (len < 8) {
> +        av_log(ctx, AV_LOG_ERROR, "Too short RTP/JPEG packet.\n");
> +        return AVERROR_INVALIDDATA;
> +    }
> +    off = (uint64_t)AV_RB64(buf) & 0xFFFFFF;
> +    buf += 8;
> +    len -= 8;
> +    if (!off) {
> +        /* Skip the current frame in case of the end packet
> +         * has been lost somewhere. */
> +        ffio_free_dyn_buf(&data->frame);
> +
> +        if ((ret = avio_open_dyn_buf(&data->frame)) < 0)
> +            return ret;
> +        data->timestamp = *timestamp;
> +    }
> +    if (!data->frame) {
> +        av_log(ctx, AV_LOG_ERROR,
> +               "Received packet without a start chunk; dropping frame.\n");
> +        return AVERROR(EAGAIN);
> +    }
> +
> +    if (data->timestamp != *timestamp) {
> +        /* Skip the current frame if timestamp is incorrect.
> +         * A start packet has been lost somewhere. */
> +        ffio_free_dyn_buf(&data->frame);
> +        av_log(ctx, AV_LOG_ERROR, "RTP timestamps don't match.\n");
> +        return AVERROR_INVALIDDATA;
> +    }
> +
> +    if (off != avio_tell(data->frame)) {
> +        av_log(ctx, AV_LOG_ERROR,
> +               "Missing packets; dropping frame.\n");
> +        return AVERROR(EAGAIN);
> +    }
> +    /* Copy data to frame buffer. */
> +    avio_write(data->frame, buf, len);
> +
> +    if (flags & RTP_FLAG_MARKER) {
> +        /* Prepare the JPEG2000 packet. */
> +        if ((ret = ff_rtp_finalize_packet(pkt, &data->frame, st->index)) <
> 0) {
> +            av_log(ctx, AV_LOG_ERROR,
> +                   "Error occurred when getting frame buffer.\n");
> +            return ret;
> +        }
> +
> +        return 0;
> +    }
> +    return AVERROR(EAGAIN);
> +}
> +
> +const RTPDynamicProtocolHandler ff_jpeg2000_dynamic_handler = {
> +    .enc_name           = "jpeg2000",
> +    .codec_type         = AVMEDIA_TYPE_VIDEO,
> +    .codec_id           = AV_CODEC_ID_JPEG2000,
> +    .priv_data_size     = sizeof(PayloadContext),
> +    .parse_packet       = jpeg2000_parse_packet,
> +    .close              = jpeg2000_close_context,
> +};
> --
> 2.17.1
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
diff mbox series

Patch

diff --git a/libavformat/Makefile b/libavformat/Makefile
index 62d8cbb54e..4495047e3a 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -46,6 +46,7 @@  OBJS-$(CONFIG_RTPDEC)                    += rdt.o                       \
                                             rtpdec_hevc.o               \
                                             rtpdec_ilbc.o               \
                                             rtpdec_jpeg.o               \
+                                            rtpdec_jpeg2000.o           \
                                             rtpdec_latm.o               \
                                             rtpdec_mpa_robust.o         \
                                             rtpdec_mpeg12.o             \
diff --git a/libavformat/rtpdec.c b/libavformat/rtpdec.c
index 3d5b200099..b47dfdfebc 100644
--- a/libavformat/rtpdec.c
+++ b/libavformat/rtpdec.c
@@ -118,6 +118,7 @@  static const RTPDynamicProtocolHandler *rtp_dynamic_protocol_handler_list[] = {
     &ff_vorbis_dynamic_handler,
     &ff_vp8_dynamic_handler,
     &ff_vp9_dynamic_handler,
+    &ff_jpeg2000_dynamic_handler,
     &gsm_dynamic_handler,
     &l24_dynamic_handler,
     &opus_dynamic_handler,
diff --git a/libavformat/rtpdec_formats.h b/libavformat/rtpdec_formats.h
index dad2b8ac1b..78ea4fb384 100644
--- a/libavformat/rtpdec_formats.h
+++ b/libavformat/rtpdec_formats.h
@@ -89,5 +89,6 @@  extern const RTPDynamicProtocolHandler ff_vc2hq_dynamic_handler;
 extern const RTPDynamicProtocolHandler ff_vorbis_dynamic_handler;
 extern const RTPDynamicProtocolHandler ff_vp8_dynamic_handler;
 extern const RTPDynamicProtocolHandler ff_vp9_dynamic_handler;
+extern const RTPDynamicProtocolHandler ff_jpeg2000_dynamic_handler;
 
 #endif /* AVFORMAT_RTPDEC_FORMATS_H */
diff --git a/libavformat/rtpdec_jpeg2000.c b/libavformat/rtpdec_jpeg2000.c
new file mode 100644
index 0000000000..b5337a9cdb
--- /dev/null
+++ b/libavformat/rtpdec_jpeg2000.c
@@ -0,0 +1,116 @@ 
+/*
+ * Code for the RTP depacketization of JPEG2000.
+ * Copyright (c) 2020 Gautam Ramakrishnan
+ *
+ * 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
+ */
+
+/**
+ * @file
+ * @brief JPEG2000 / RTP Code
+ * @author Gautam Ramakrishnan
+ */
+
+#include "rtpdec_formats.h"
+#include "avio_internal.h"
+#include "internal.h"
+#include "libavutil/attributes.h"
+#include "libavutil/avstring.h"
+#include "libavcodec/get_bits.h"
+
+#define PAYLOAD_HDR_SIZ 8
+
+/**
+ * RTP/JPEG specific private data.
+ */
+struct PayloadContext {
+    AVIOContext *frame;         // current frame buffer
+    uint32_t    timestamp;      // current frame timestamp
+};
+
+static void jpeg2000_close_context(PayloadContext *data)
+{
+    ffio_free_dyn_buf(&data->frame);
+}
+
+static int jpeg2000_parse_packet(AVFormatContext *ctx, PayloadContext *data,
+                                AVStream *st, AVPacket *pkt, uint32_t *timestamp,
+                                const uint8_t *buf, int len, uint16_t seq,
+                                int flags)
+{
+    int ret;
+    int off;
+
+    if (len < 8) {
+        av_log(ctx, AV_LOG_ERROR, "Too short RTP/JPEG packet.\n");
+        return AVERROR_INVALIDDATA;
+    }
+    off = (uint64_t)AV_RB64(buf) & 0xFFFFFF;
+    buf += 8;
+    len -= 8;
+    if (!off) {
+        /* Skip the current frame in case of the end packet
+         * has been lost somewhere. */
+        ffio_free_dyn_buf(&data->frame);
+
+        if ((ret = avio_open_dyn_buf(&data->frame)) < 0)
+            return ret;
+        data->timestamp = *timestamp;
+    }
+    if (!data->frame) {
+        av_log(ctx, AV_LOG_ERROR,
+               "Received packet without a start chunk; dropping frame.\n");
+        return AVERROR(EAGAIN);
+    }
+
+    if (data->timestamp != *timestamp) {
+        /* Skip the current frame if timestamp is incorrect.
+         * A start packet has been lost somewhere. */
+        ffio_free_dyn_buf(&data->frame);
+        av_log(ctx, AV_LOG_ERROR, "RTP timestamps don't match.\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    if (off != avio_tell(data->frame)) {
+        av_log(ctx, AV_LOG_ERROR,
+               "Missing packets; dropping frame.\n");
+        return AVERROR(EAGAIN);
+    }
+    /* Copy data to frame buffer. */
+    avio_write(data->frame, buf, len);
+
+    if (flags & RTP_FLAG_MARKER) {
+        /* Prepare the JPEG2000 packet. */
+        if ((ret = ff_rtp_finalize_packet(pkt, &data->frame, st->index)) < 0) {
+            av_log(ctx, AV_LOG_ERROR,
+                   "Error occurred when getting frame buffer.\n");
+            return ret;
+        }
+
+        return 0;
+    }
+    return AVERROR(EAGAIN);
+}
+
+const RTPDynamicProtocolHandler ff_jpeg2000_dynamic_handler = {
+    .enc_name           = "jpeg2000",
+    .codec_type         = AVMEDIA_TYPE_VIDEO,
+    .codec_id           = AV_CODEC_ID_JPEG2000,
+    .priv_data_size     = sizeof(PayloadContext),
+    .parse_packet       = jpeg2000_parse_packet,
+    .close              = jpeg2000_close_context,
+};