From patchwork Wed Jul 22 19:25:53 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gautam Ramakrishnan X-Patchwork-Id: 21232 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 230A544ADB0 for ; Wed, 22 Jul 2020 22:26:13 +0300 (EEST) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 0E1D668B809; Wed, 22 Jul 2020 22:26:13 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-pg1-f177.google.com (mail-pg1-f177.google.com [209.85.215.177]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id C7A9068B73A for ; Wed, 22 Jul 2020 22:26:05 +0300 (EEST) Received: by mail-pg1-f177.google.com with SMTP id s189so1808068pgc.13 for ; Wed, 22 Jul 2020 12:26:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=oBPDN0ha/B/vQQOBCb9IM88PHL+3f7W82UqoCbF2z7g=; b=SroumNgpjPa/CBgfzheXP1tkORw7kriv6SusJs7foE60ae7YWu3+AeWo/6PLJBasNa 5HyuCyGlt096gLY8P6D1oqw4xd092amF9AvRXjSHtdsPa41HdTprVt6b1020hP0AVqHs EeSmk0OkcFNt2OZ3eneZBOjhr3rCmUZ7DdIpKtsPFBfpr/4lPzvzgFEjSTdyfthmKvnh x2/Ai9BVQLQNo+c8n1XOIfTmHcUZ1AwJXeKsk9S+gLqy2I9qZa/FuegmHJYYBSWt0JHH xIJeTK5Ik9oP7R4HzeFSg14MCJrLMlYQx/tlw1Y7Sh6KAvt/krsgUVF5XVJXXxStpEdB uDUg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=oBPDN0ha/B/vQQOBCb9IM88PHL+3f7W82UqoCbF2z7g=; b=i1lJskYHSHYF7DDPxXiQsJkxq1V6h5saWZNE7n+HTEWdo094cAwayxdnpHopv58HI1 jRnpOyA2eu48C3FSGaS/p5SKsrXaTdNFjfDrmI9cS2M34dTYTv7jctDZoAhFcKn5TftF LvNSLsmHugzkp4KwhZQFLOcQgUqLNsJsCqa+phLvlWjKoIVi8jokCQq2VA5Xkgy9WWdv 0tqyMosCxc2TtDI53pQ1V5njOAKdVzHhV+DGDvboBg5Vohljziblq+2ROePmjftR+3ro 3BJxdtb/9rN2ksiIzn+J20Q3weg0fmxQsrbnvhbtJgLFvXuFbH3WIV+LcWbXrDQSIXf+ p4Xg== X-Gm-Message-State: AOAM532IMNKjc3+o6Rk7CLC4W/YjNEmroMjeqha8y65HDEym+2pW6EhM na6W17oFIMyuYa5p+fdrvcj0J8Lq5Y4= X-Google-Smtp-Source: ABdhPJzFaNCLDNtAJ+qdwD/gMZZYu6El/kOJcdeJOEZJxTWZ8FjrF/WHaab2MfxDyCRtDc8AYrVEaQ== X-Received: by 2002:a62:3814:: with SMTP id f20mr1017562pfa.278.1595445963263; Wed, 22 Jul 2020 12:26:03 -0700 (PDT) Received: from localhost.localdomain ([122.167.212.213]) by smtp.gmail.com with ESMTPSA id l134sm405963pga.50.2020.07.22.12.26.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 22 Jul 2020 12:26:02 -0700 (PDT) From: gautamramk@gmail.com To: ffmpeg-devel@ffmpeg.org Date: Thu, 23 Jul 2020 00:55:53 +0530 Message-Id: <20200722192553.9688-2-gautamramk@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200722192553.9688-1-gautamramk@gmail.com> References: <20200722192553.9688-1-gautamramk@gmail.com> Subject: [FFmpeg-devel] [RFC Patch 2/2] libavformat/rtpenc_jpeg2000 JPEG2000 RTP Muxer X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Gautam Ramakrishnan MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" From: Gautam Ramakrishnan 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",