* Boston, MA 02110-1301, USA.
*/
+
+ /**
+ * SECTION:element-rtpj2kdepay
+ * @title: rtpj2kdepay
+ *
+ * Depayload an RTP-payloaded JPEG 2000 image into RTP packets according to RFC 5371
+ * and RFC 5372.
+ * For detailed information see: https://datatracker.ietf.org/doc/rfc5371/
+ * and https://datatracker.ietf.org/doc/rfc5372/
+ */
+
+
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/video/video.h>
#include <string.h>
+#include "gstrtpj2kcommon.h"
#include "gstrtpj2kdepay.h"
+#include "gstrtputils.h"
GST_DEBUG_CATEGORY_STATIC (rtpj2kdepay_debug);
#define GST_CAT_DEFAULT (rtpj2kdepay_debug)
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("image/x-jpc")
+ GST_STATIC_CAPS ("image/x-jpc, "
+ "colorspace = (string) { sRGB, sYUV, GRAY }")
);
static GstStaticPadTemplate gst_rtp_j2k_depay_sink_template =
-GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("application/x-rtp, "
- "media = (string) \"video\", "
- "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
- "clock-rate = (int) 90000, " "encoding-name = (string) \"JPEG2000\"")
+ "media = (string) \"video\", " "clock-rate = (int) 90000, "
+ GST_RTP_J2K_SAMPLING_LIST ","
+ "encoding-name = (string) \"JPEG2000\";"
+ "application/x-rtp, "
+ "media = (string) \"video\", " "clock-rate = (int) 90000, "
+ "colorspace = (string) { sRGB, sYUV, GRAY }, "
+ "encoding-name = (string) \"JPEG2000\";")
);
-typedef enum
-{
- J2K_MARKER = 0xFF,
- J2K_MARKER_SOC = 0x4F,
- J2K_MARKER_SOT = 0x90,
- J2K_MARKER_SOP = 0x91,
- J2K_MARKER_SOD = 0x93,
- J2K_MARKER_EOC = 0xD9
-} RtpJ2KMarker;
-
enum
{
PROP_0,
static gboolean gst_rtp_j2k_depay_setcaps (GstRTPBaseDepayload * depayload,
GstCaps * caps);
static GstBuffer *gst_rtp_j2k_depay_process (GstRTPBaseDepayload * depayload,
- GstBuffer * buf);
+ GstRTPBuffer * rtp);
static void
gst_rtp_j2k_depay_class_init (GstRtpJ2KDepayClass * klass)
gobject_class->set_property = gst_rtp_j2k_depay_set_property;
gobject_class->get_property = gst_rtp_j2k_depay_get_property;
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&gst_rtp_j2k_depay_src_template));
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&gst_rtp_j2k_depay_sink_template));
+ gst_element_class_add_static_pad_template (gstelement_class,
+ &gst_rtp_j2k_depay_src_template);
+ gst_element_class_add_static_pad_template (gstelement_class,
+ &gst_rtp_j2k_depay_sink_template);
gst_element_class_set_static_metadata (gstelement_class,
"RTP JPEG 2000 depayloader", "Codec/Depayloader/Network/RTP",
gstelement_class->change_state = gst_rtp_j2k_depay_change_state;
gstrtpbasedepayload_class->set_caps = gst_rtp_j2k_depay_setcaps;
- gstrtpbasedepayload_class->process = gst_rtp_j2k_depay_process;
+ gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_j2k_depay_process;
GST_DEBUG_CATEGORY_INIT (rtpj2kdepay_debug, "rtpj2kdepay", 0,
"J2K Video RTP Depayloader");
static gboolean
gst_rtp_j2k_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
{
- GstStructure *structure;
+ GstStructure *structure = NULL;
gint clock_rate;
- GstCaps *outcaps;
- gboolean res;
+ GstCaps *outcaps = NULL;
+ gboolean res = FALSE;
+ const gchar *colorspace = NULL;
+ const gchar *sampling = NULL;
structure = gst_caps_get_structure (caps, 0);
clock_rate = 90000;
depayload->clock_rate = clock_rate;
- outcaps =
- gst_caps_new_simple ("image/x-jpc", "framerate", GST_TYPE_FRACTION, 0, 1,
- "fields", G_TYPE_INT, 1, "colorspace", G_TYPE_STRING, "sYUV", NULL);
+ sampling = gst_structure_get_string (structure, "sampling");
+ if (sampling) {
+ if (!strcmp (sampling, GST_RTP_J2K_RGB) ||
+ !strcmp (sampling, GST_RTP_J2K_RGBA) ||
+ !strcmp (sampling, GST_RTP_J2K_BGR) ||
+ !strcmp (sampling, GST_RTP_J2K_BGRA))
+ colorspace = "sRGB";
+ else if (!strcmp (sampling, GST_RTP_J2K_GRAYSCALE))
+ colorspace = "GRAY";
+ else
+ colorspace = "sYUV";
+ } else {
+ GST_ELEMENT_WARNING (depayload, STREAM, DEMUX, NULL,
+ ("Non-compliant stream: sampling field missing. Frames my appear incorrect"));
+ colorspace = gst_structure_get_string (structure, "colorspace");
+ if (!strcmp (colorspace, "GRAY")) {
+ sampling = GST_RTP_J2K_GRAYSCALE;
+ }
+ }
+
+ outcaps = gst_caps_new_simple ("image/x-jpc",
+ "framerate", GST_TYPE_FRACTION, 0, 1,
+ "fields", G_TYPE_INT, 1, "colorspace", G_TYPE_STRING, colorspace, NULL);
+
+ if (sampling)
+ gst_caps_set_simple (outcaps, "sampling", G_TYPE_STRING, sampling, NULL);
+
res = gst_pad_set_caps (depayload->srcpad, outcaps);
+
gst_caps_unref (outcaps);
return res;
if (map.size < 12)
goto invalid_tile;
- if (map.data[0] == 0xff && map.data[1] == J2K_MARKER_SOT) {
+ if (map.data[0] == GST_J2K_MARKER && map.data[1] == GST_J2K_MARKER_SOT) {
guint Psot, nPsot;
- if (end[0] == 0xff && end[1] == J2K_MARKER_EOC)
+ if (end[0] == GST_J2K_MARKER && end[1] == GST_J2K_MARKER_EOC)
nPsot = avail - 2;
else
nPsot = avail;
goto done;
if (avail > 2) {
- GList *list, *walk;
- GstBufferList *buflist;
+ GstBuffer *outbuf;
/* take the last bytes of the JPEG 2000 data to see if there is an EOC
* marker */
gst_adapter_copy (rtpj2kdepay->f_adapter, end, avail - 2, 2);
- if (end[0] != 0xff && end[1] != 0xd9) {
- GstBuffer *outbuf;
-
- end[0] = 0xff;
- end[1] = 0xd9;
+ if (end[0] != GST_J2K_MARKER && end[1] != GST_J2K_MARKER_EOC) {
+ end[0] = GST_J2K_MARKER;
+ end[1] = GST_J2K_MARKER_EOC;
GST_DEBUG_OBJECT (rtpj2kdepay, "no EOC marker, adding one");
avail += 2;
}
- GST_DEBUG_OBJECT (rtpj2kdepay, "pushing buffer list of %u bytes", avail);
- list = gst_adapter_take_list (rtpj2kdepay->f_adapter, avail);
-
- buflist = gst_buffer_list_new ();
-
- for (walk = list; walk; walk = g_list_next (walk))
- gst_buffer_list_add (buflist, GST_BUFFER_CAST (walk->data));
-
- g_list_free (list);
-
- ret = gst_rtp_base_depayload_push_list (depayload, buflist);
+ GST_DEBUG_OBJECT (rtpj2kdepay, "pushing buffer of %u bytes", avail);
+ outbuf = gst_adapter_take_buffer (rtpj2kdepay->f_adapter, avail);
+ gst_rtp_drop_non_video_meta (depayload, outbuf);
+ ret = gst_rtp_base_depayload_push (depayload, outbuf);
} else {
GST_WARNING_OBJECT (rtpj2kdepay, "empty packet");
gst_adapter_clear (rtpj2kdepay->f_adapter);
}
static GstBuffer *
-gst_rtp_j2k_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+gst_rtp_j2k_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
{
GstRtpJ2KDepay *rtpj2kdepay;
guint8 *payload;
guint MHF, mh_id, frag_offset, tile, payload_len, j2klen;
gint gap;
guint32 rtptime;
- GstRTPBuffer rtp = { NULL };
rtpj2kdepay = GST_RTP_J2K_DEPAY (depayload);
- gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
-
- payload = gst_rtp_buffer_get_payload (&rtp);
- payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+ payload = gst_rtp_buffer_get_payload (rtp);
+ payload_len = gst_rtp_buffer_get_payload_len (rtp);
/* we need at least a header */
- if (payload_len < 8)
+ if (payload_len < GST_RTP_J2K_HEADER_SIZE)
goto empty_packet;
- rtptime = gst_rtp_buffer_get_timestamp (&rtp);
+ rtptime = gst_rtp_buffer_get_timestamp (rtp);
/* new timestamp marks new frame */
if (rtpj2kdepay->last_rtptime != rtptime) {
tile = (payload[2] << 8) | payload[3];
frag_offset = (payload[5] << 16) | (payload[6] << 8) | payload[7];
- j2klen = payload_len - 8;
+ j2klen = payload_len - GST_RTP_J2K_HEADER_SIZE;
GST_DEBUG_OBJECT (rtpj2kdepay, "MHF %u, tile %u, frag %u, expected %u", MHF,
tile, frag_offset, rtpj2kdepay->next_frag);
}
/* check for sync code */
- if (j2klen > 2 && payload[8] == 0xff) {
- guint marker = payload[9];
+ if (j2klen > 2 && payload[GST_RTP_J2K_HEADER_SIZE] == GST_J2K_MARKER) {
+ guint marker = payload[GST_RTP_J2K_HEADER_SIZE + 1];
/* packets must start with SOC, SOT or SOP */
switch (marker) {
- case J2K_MARKER_SOC:
+ case GST_J2K_MARKER_SOC:
GST_DEBUG_OBJECT (rtpj2kdepay, "found SOC packet");
/* flush the previous frame, should have happened when the timestamp
* changed above. */
gst_rtp_j2k_depay_flush_frame (depayload);
rtpj2kdepay->have_sync = TRUE;
break;
- case J2K_MARKER_SOT:
+ case GST_J2K_MARKER_SOT:
/* flush the previous tile */
gst_rtp_j2k_depay_flush_tile (depayload);
GST_DEBUG_OBJECT (rtpj2kdepay, "found SOT packet");
/* we sync on the tile now */
rtpj2kdepay->last_tile = tile;
break;
- case J2K_MARKER_SOP:
+ case GST_J2K_MARKER_SOP:
GST_DEBUG_OBJECT (rtpj2kdepay, "found SOP packet");
/* flush the previous PU */
gst_rtp_j2k_depay_flush_pu (depayload);
}
/* and push in pu adapter */
GST_DEBUG_OBJECT (rtpj2kdepay, "push pu of size %u in adapter", j2klen);
- pu_frag = gst_rtp_buffer_get_payload_subbuffer (&rtp, 8, -1);
+ pu_frag = gst_rtp_buffer_get_payload_subbuffer (rtp, 8, -1);
gst_adapter_push (rtpj2kdepay->pu_adapter, pu_frag);
if (MHF & 2) {
}
/* marker bit finishes the frame */
- if (gst_rtp_buffer_get_marker (&rtp)) {
+ if (gst_rtp_buffer_get_marker (rtp)) {
GST_DEBUG_OBJECT (rtpj2kdepay, "marker set, last buffer");
/* then flush frame */
gst_rtp_j2k_depay_flush_frame (depayload);
}
- gst_rtp_buffer_unmap (&rtp);
return NULL;
{
GST_ELEMENT_WARNING (rtpj2kdepay, STREAM, DECODE,
("Empty Payload."), (NULL));
- gst_rtp_buffer_unmap (&rtp);
return NULL;
}
wrong_mh_id:
("Invalid mh_id %u, expected %u", mh_id, rtpj2kdepay->last_mh_id),
(NULL));
gst_rtp_j2k_depay_clear_pu (rtpj2kdepay);
- gst_rtp_buffer_unmap (&rtp);
return NULL;
}
}