[FFmpeg-devel] [RFC Patch 2/2] libavformat/rtpenc_jpeg2000 JPEG2000 RTP Muxer
gautamramk at gmail.com
gautamramk at gmail.com
Wed Jul 22 22:25:53 EEST 2020
From: Gautam Ramakrishnan <gautamramk at gmail.com>
This patch adds support to mux JPEG2000 streams over
RTP.
---
libavformat/Makefile | 1 +
libavformat/rtpenc.c | 4 ++
libavformat/rtpenc.h | 1 +
libavformat/rtpenc_jpeg2000.c | 121 ++++++++++++++++++++++++++++++++++
libavformat/sdp.c | 32 +++++++++
5 files changed, 159 insertions(+)
create mode 100644 libavformat/rtpenc_jpeg2000.c
diff --git a/libavformat/Makefile b/libavformat/Makefile
index 4495047e3a..f2d260fada 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -459,6 +459,7 @@ OBJS-$(CONFIG_RTP_MUXER) += rtp.o \
rtpenc_h263_rfc2190.o \
rtpenc_h264_hevc.o \
rtpenc_jpeg.o \
+ rtpenc_jpeg2000.o \
rtpenc_mpv.o \
rtpenc.o \
rtpenc_vc2hq.o \
diff --git a/libavformat/rtpenc.c b/libavformat/rtpenc.c
index 9ef7e9094d..1af9e3f455 100644
--- a/libavformat/rtpenc.c
+++ b/libavformat/rtpenc.c
@@ -84,6 +84,7 @@ static int is_supported(enum AVCodecID id)
case AV_CODEC_ID_MJPEG:
case AV_CODEC_ID_SPEEX:
case AV_CODEC_ID_OPUS:
+ case AV_CODEC_ID_JPEG2000:
return 1;
default:
return 0;
@@ -619,6 +620,9 @@ static int rtp_write_packet(AVFormatContext *s1, AVPacket *pkt)
case AV_CODEC_ID_MJPEG:
ff_rtp_send_jpeg(s1, pkt->data, size);
break;
+ case AV_CODEC_ID_JPEG2000:
+ ff_rtp_send_jpeg2000(s1, pkt->data, size);
+ break;
case AV_CODEC_ID_OPUS:
if (size > s->max_payload_size) {
av_log(s1, AV_LOG_ERROR,
diff --git a/libavformat/rtpenc.h b/libavformat/rtpenc.h
index 62dc9ab10a..0db339f2ee 100644
--- a/libavformat/rtpenc.h
+++ b/libavformat/rtpenc.h
@@ -95,6 +95,7 @@ void ff_rtp_send_vc2hq(AVFormatContext *s1, const uint8_t *buf, int size, int in
void ff_rtp_send_vp8(AVFormatContext *s1, const uint8_t *buff, int size);
void ff_rtp_send_vp9(AVFormatContext *s1, const uint8_t *buff, int size);
void ff_rtp_send_jpeg(AVFormatContext *s1, const uint8_t *buff, int size);
+void ff_rtp_send_jpeg2000(AVFormatContext *s1, const uint8_t *buff, int size);
const uint8_t *ff_h263_find_resync_marker_reverse(const uint8_t *av_restrict start,
const uint8_t *av_restrict end);
diff --git a/libavformat/rtpenc_jpeg2000.c b/libavformat/rtpenc_jpeg2000.c
new file mode 100644
index 0000000000..699bc2e1b9
--- /dev/null
+++ b/libavformat/rtpenc_jpeg2000.c
@@ -0,0 +1,121 @@
+/*
+ * RTP JPEG2000 video Packetizer, RFC 5371
+ * 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
+ */
+
+#include "libavcodec/bytestream.h"
+#include "libavutil/intreadwrite.h"
+#include "rtpenc.h"
+
+#define PAYLOAD_HDR_SIZ 8
+
+static void send_packet(AVFormatContext *s1, const uint8_t *buf, int start, int end,
+ int header, int tileno, int cstream_start, int last)
+{
+ RTPMuxContext *s = s1->priv_data;
+ int unit_len = end - start;
+ int send_left = end - start;
+ while (send_left > 0) {
+ int len = FFMIN(send_left, s->max_payload_size - PAYLOAD_HDR_SIZ);
+ uint8_t flags = 0;
+ if (unit_len <= s->max_payload_size - PAYLOAD_HDR_SIZ)
+ flags |= 3 << 3;
+ else if (header && (send_left - len))
+ flags |= 1 << 3;
+ else if (header && !(send_left - len))
+ flags |= 2 << 3;
+ if (header)
+ flags |= 1;
+ bytestream_put_byte(&s->buf_ptr, flags);
+ bytestream_put_byte(&s->buf_ptr, 255);
+ bytestream_put_be16(&s->buf_ptr, tileno);
+ bytestream_put_byte(&s->buf_ptr, 0);
+ bytestream_put_be24(&s->buf_ptr, start - cstream_start);
+ memcpy(s->buf_ptr, buf + start, len);
+ ff_rtp_send_data(s1, s->buf, len + PAYLOAD_HDR_SIZ, last && send_left <= len);
+ send_left -= len;
+ s->buf_ptr = s->buf;
+ start += len;
+ }
+}
+
+void ff_rtp_send_jpeg2000(AVFormatContext *s1, const uint8_t *buf, int size)
+{
+ RTPMuxContext *s = s1->priv_data;
+ int i = 0;
+ int packet_start = -1;
+ int packet_end = -1;
+ int cstream_start = -1;
+ int tileno = 0;
+ int sod_found = 0;
+ int end_found = 0;
+
+ s->buf_ptr = s->buf;
+ s->timestamp = s->cur_timestamp;
+
+ while (AV_RB16(&buf[i]) != 0xFF4F && i < size)
+ i++;
+ if (i == size) {
+ av_log(s1, AV_LOG_ERROR, "Codestream Not found.\n");
+ return;
+ }
+ packet_start = i;
+ cstream_start = i;
+ while (AV_RB16(&buf[i]) != 0xFF90 && i < size)
+ i++;
+ if (i == size) {
+ av_log(s1, AV_LOG_ERROR, "Cannot find end of main header.\n");
+ return;
+ }
+ packet_end = i;
+ send_packet(s1, buf, packet_start, packet_end, 1, 0, cstream_start, 0);
+ while (i < size) {
+ if (AV_RB16(&buf[i]) == 0xFF90) {
+ packet_start = i;
+ i += 4;
+ tileno = AV_RB16(&buf[i]);
+ i += 6;
+ while (AV_RB16(&buf[i]) != 0xFF93 && i < size)
+ i++;
+ if (AV_RB16(&buf[i]) == 0xFF93)
+ i += 2;
+ else {
+ av_log(s1, AV_LOG_ERROR, "Cannot find end of TP header.\n");
+ return;
+ }
+ packet_end = i;
+ sod_found = 1;
+ send_packet(s1, buf, packet_start, packet_end, 0, tileno, cstream_start, 0);
+ } else if (sod_found) {
+ packet_start = i;
+ sod_found = 0;
+ while (AV_RB16(&buf[i]) != 0xFF90 && AV_RB16(&buf[i]) != 0xFFD9 && i < size) {
+ i++;
+ }
+ if (AV_RB16(&buf[i]) == 0xFFD9) {
+ packet_end = i+2;
+ end_found = 1;
+ } else
+ packet_end = i;
+ send_packet(s1, buf, packet_start, packet_end, 0, tileno, cstream_start, end_found);
+ }
+ if (AV_RB16(&buf[i]) == 0xFFD9)
+ break;
+ }
+}
diff --git a/libavformat/sdp.c b/libavformat/sdp.c
index 2ce1a62262..c8ca119d2d 100644
--- a/libavformat/sdp.c
+++ b/libavformat/sdp.c
@@ -673,6 +673,38 @@ static char *sdp_write_media_attributes(char *buff, int size, AVStream *st, int
av_strlcatf(buff, size, "a=rtpmap:%d JPEG/90000\r\n",
payload_type);
break;
+ case AV_CODEC_ID_JPEG2000: {
+ const char *pix_fmt;
+ switch (p->format) {
+ case AV_PIX_FMT_YUV420P:
+ pix_fmt = "YCbCr-4:2:0";
+ break;
+ case AV_PIX_FMT_YUV422P:
+ pix_fmt = "YCbCr-4:2:2";
+ break;
+ case AV_PIX_FMT_YUV444P:
+ pix_fmt = "YCbCr-4:4:4";
+ break;
+ case AV_PIX_FMT_RGB24:
+ pix_fmt = "RGB";
+ break;
+ case AV_PIX_FMT_RGB32:
+ pix_fmt = "RGBA";
+ break;
+ case AV_PIX_FMT_BGR24:
+ pix_fmt = "BGR";
+ break;
+ case AV_PIX_FMT_BGR32:
+ pix_fmt = "BGRA";
+ case AV_PIX_FMT_GRAY8:
+ pix_fmt = "GRAYSCALE";
+ }
+ if (payload_type >= RTP_PT_PRIVATE)
+ av_strlcatf(buff, size, "a=rtpmap:%d JPEG2000/90000\r\n"
+ "a=fmtp:%d sampling=%s\r\n",
+ payload_type, payload_type, pix_fmt);
+ break;
+ }
case AV_CODEC_ID_ADPCM_G722:
if (payload_type >= RTP_PT_PRIVATE)
av_strlcatf(buff, size, "a=rtpmap:%d G722/%d/%d\r\n",
--
2.17.1
More information about the ffmpeg-devel
mailing list