From: <wt...@ke...> - 2008-11-14 11:42:56
|
CVS Root: /cvs/gstreamer Module: gst-plugins-good Changes by: wtay Date: Fri Nov 14 2008 11:42:10 UTC Log message: Patch by: Bjorn Ostby <bjornos at axis dot com> * gst/rtp/Makefile.am: * gst/rtp/gstrtp.c: (plugin_init): * gst/rtp/gstrtpjpegpay.c: (gst_rtp_jpeg_pay_base_init), (gst_rtp_jpeg_pay_class_init), (gst_rtp_jpeg_pay_init), (gst_rtp_jpeg_pay_setcaps), (gst_rtp_jpeg_pay_header_size), (gst_rtp_jpeg_pay_read_quant_table), (gst_rtp_jpeg_pay_scan_marker), (gst_rtp_jpeg_pay_handle_buffer), (gst_rtp_jpeg_pay_set_property), (gst_rtp_jpeg_pay_get_property), (gst_rtp_jpeg_pay_plugin_init): * gst/rtp/gstrtpjpegpay.h: Add JPEG payloader. Fixes #560756. Modified files: . : ChangeLog gst/rtp : Makefile.am gstrtp.c Added files: gst/rtp : gstrtpjpegpay.c gstrtpjpegpay.h Links: http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-plugins-good/ChangeLog.diff?r1=1.3815&r2=1.3816 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-plugins-good/gst/rtp/Makefile.am.diff?r1=1.53&r2=1.54 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-plugins-good/gst/rtp/gstrtp.c.diff?r1=1.46&r2=1.47 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-plugins-good/gst/rtp/gstrtpjpegpay.c?rev=1.1&content-type=text/vnd.viewcvs-markup http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-plugins-good/gst/rtp/gstrtpjpegpay.h?rev=1.1&content-type=text/vnd.viewcvs-markup ====Begin Diffs==== Index: ChangeLog =================================================================== RCS file: /cvs/gstreamer/gst-plugins-good/ChangeLog,v retrieving revision 1.3815 retrieving revision 1.3816 diff -u -d -r1.3815 -r1.3816 --- ChangeLog 13 Nov 2008 17:45:57 -0000 1.3815 +++ ChangeLog 14 Nov 2008 11:41:53 -0000 1.3816 @@ -1,3 +1,19 @@ +2008-11-14 Wim Taymans <wim...@co...> + + Patch by: Bjorn Ostby <bjornos at axis dot com> + * gst/rtp/Makefile.am: + * gst/rtp/gstrtp.c: (plugin_init): + * gst/rtp/gstrtpjpegpay.c: (gst_rtp_jpeg_pay_base_init), + (gst_rtp_jpeg_pay_class_init), (gst_rtp_jpeg_pay_init), + (gst_rtp_jpeg_pay_setcaps), (gst_rtp_jpeg_pay_header_size), + (gst_rtp_jpeg_pay_read_quant_table), + (gst_rtp_jpeg_pay_scan_marker), (gst_rtp_jpeg_pay_handle_buffer), + (gst_rtp_jpeg_pay_set_property), (gst_rtp_jpeg_pay_get_property), + (gst_rtp_jpeg_pay_plugin_init): + * gst/rtp/gstrtpjpegpay.h: + Add JPEG payloader. Fixes #560756. 2008-11-13 Wim Taymans <wim...@co...> Patch by: Fabricio Godoy <skarllot at gmail dot com> Index: Makefile.am RCS file: /cvs/gstreamer/gst-plugins-good/gst/rtp/Makefile.am,v retrieving revision 1.53 retrieving revision 1.54 diff -u -d -r1.53 -r1.54 --- Makefile.am 4 Nov 2008 12:28:29 -0000 1.53 +++ Makefile.am 14 Nov 2008 11:41:55 -0000 1.54 @@ -32,6 +32,7 @@ gstrtph263pay.c \ gstrtph264depay.c \ gstrtph264pay.c \ + gstrtpjpegpay.c \ gstrtpL16depay.c \ gstrtpL16pay.c \ gstasteriskh263.c \ @@ -101,6 +102,7 @@ gstrtph263pay.h \ gstrtph264depay.h \ gstrtph264pay.h \ + gstrtpjpegpay.h \ gstrtpmp1sdepay.h \ gstrtpmp2tdepay.h \ gstrtpmp2tpay.h \ Index: gstrtp.c RCS file: /cvs/gstreamer/gst-plugins-good/gst/rtp/gstrtp.c,v retrieving revision 1.46 retrieving revision 1.47 diff -u -d -r1.46 -r1.47 --- gstrtp.c 26 Sep 2008 13:55:48 -0000 1.46 +++ gstrtp.c 14 Nov 2008 11:41:55 -0000 1.47 @@ -49,6 +49,7 @@ #include "gstrtph263pay.h" #include "gstrtph264depay.h" #include "gstrtph264pay.h" +#include "gstrtpjpegpay.h" #include "gstrtpL16depay.h" #include "gstrtpL16pay.h" #include "gstasteriskh263.h" @@ -158,6 +159,9 @@ if (!gst_rtp_h264_pay_plugin_init (plugin)) return FALSE; + if (!gst_rtp_jpeg_pay_plugin_init (plugin)) + return FALSE; if (!gst_rtp_L16_pay_plugin_init (plugin)) --- NEW FILE: gstrtpjpegpay.c --- /* GStreamer * Copyright (C) 2008 Axis Communications <dev...@ax...> * @author Bjorn Ostby <bjo...@ax...> * @author Peter Kjellerstedt <pet...@ax...> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * This library 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 * Library General Public License for more details. * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /** * SECTION:rtpjpegpay * @short_description: RTP payloader for JPEG pictures * Payload encode JPEG pictures into RTP packets according to RFC 2435. * For detailed information see: http://www.rfc-editor.org/rfc/rfc2435.txt * The payloader takes a JPEG picture, scans the header for quantization * tables (if needed) and constructs the RTP packet header followed by * the actual JPEG entropy scan. * The payloader assumes that correct width and height is found in the caps. #ifdef HAVE_CONFIG_H # include "config.h" #endif #include <string.h> #include <gst/rtp/gstrtpbuffer.h> #include "gstrtpjpegpay.h" /* elementfactory information */ static const GstElementDetails gst_rtp_jpeg_pay_details = GST_ELEMENT_DETAILS ("RTP packet payloader", "Codec/Payloader/Network", "Payload-encodes JPEG pictures into a RTP packet", "Axis Communications <dev...@ax...>"); static GstStaticPadTemplate gst_rtp_jpeg_pay_sink_template = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ("image/jpeg, " " height = (int) [0, 2040], " " width = (int) [0, 2040]; " "video/x-jpeg, " " height = (int) [0, 2040], " " width = (int) [0, 2040]") ); static GstStaticPadTemplate gst_rtp_jpeg_pay_src_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_STATIC_CAPS ("application/x-rtp, " " media = (string) \"video\", " " payload = (int) 26 , " " clock-rate = (int) 90000, " " encoding-name = (string) \"JPEG\"") GST_DEBUG_CATEGORY_STATIC (rtpjpegpay_debug); #define GST_CAT_DEFAULT (rtpjpegpay_debug) * QUANT_PREFIX_LEN: * Prefix length in the header before the quantization tables: * Two size bytes and one byte for precision #define QUANT_PREFIX_LEN 3 * DEFAULT_JPEG_QUALITY: #define DEFAULT_JPEG_QUALITY 0 * DEFAULT_JPEG_TYPE: #define DEFAULT_JPEG_TYPE 0 typedef enum _RtpJpegMarker RtpJpegMarker; * RtpJpegMarker: * @JPEG_MARKER: Prefix for JPEG marker * @JPEG_MARKER_SOI: Start of Image marker * @JPEG_MARKER_JFIF: JFIF marker * @JPEG_MARKER_CMT: Comment marker * @JPEG_MARKER_DQT: Define Quantization Table marker * @JPEG_MARKER_SOF: Start of Frame marker * @JPEG_MARKER_DHT: Define Huffman Table marker * @JPEG_MARKER_SOS: Start of Scan marker * @JPEG_MARKER_EOI: End of Image marker * Identifers for markers in JPEG header enum _RtpJpegMarker { JPEG_MARKER = 0xFF, JPEG_MARKER_SOI = 0xD8, JPEG_MARKER_JFIF = 0xE0, JPEG_MARKER_CMT = 0xFE, JPEG_MARKER_DQT = 0xDB, JPEG_MARKER_SOF = 0xC0, JPEG_MARKER_DHT = 0xC4, JPEG_MARKER_SOS = 0xDA, JPEG_MARKER_EOI = 0xD9, }; enum PROP_0, PROP_JPEG_QUALITY, PROP_JPEG_TYPE Q_TABLE_0 = 0, Q_TABLE_1, Q_TABLE_MAX /* only support for two tables at the moment */ typedef struct _RtpJpegHeader RtpJpegHeader; typedef struct _RtpQuantHeader RtpQuantHeader; * RtpJpegHeader: * @type_spec: type specific * @offset: fragment offset * @type: type field * @q: quantization table for this frame * @width: width of image in 8-pixel multiples * @height: height of image in 8-pixel multiples * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Type-specific | Fragment Offset | * | Type | Q | Width | Height | struct _RtpJpegHeader #if (G_BYTE_ORDER == G_LITTLE_ENDIAN) guint type_spec:8; guint offset:24; #else guint8 type; guint8 q; guint8 width; guint8 height; * RtpQuantHeader * @mbz: must be zero * @precision: specify size of quantization tables * @length: length of quantization data * | MBZ | Precision | Length | * | Quantization Table Data | * | ... | struct _RtpQuantHeader guint8 mbz; guint8 precision; guint16 length; /* FIXME: restart marker header currently unsupported */ static void gst_rtp_jpeg_pay_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_rtp_jpeg_pay_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); static gboolean gst_rtp_jpeg_pay_setcaps (GstBaseRTPPayload * basepayload, GstCaps * caps); static GstFlowReturn gst_rtp_jpeg_pay_handle_buffer (GstBaseRTPPayload * pad, GstBuffer * buffer); GST_BOILERPLATE (GstRtpJPEGPay, gst_rtp_jpeg_pay, GstBaseRTPPayload, GST_TYPE_BASE_RTP_PAYLOAD); static void gst_rtp_jpeg_pay_base_init (gpointer klass) GstElementClass *element_class = GST_ELEMENT_CLASS (klass); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&gst_rtp_jpeg_pay_src_template)); gst_static_pad_template_get (&gst_rtp_jpeg_pay_sink_template)); gst_element_class_set_details (element_class, &gst_rtp_jpeg_pay_details); } gst_rtp_jpeg_pay_class_init (GstRtpJPEGPayClass * klass) GObjectClass *gobject_class; GstBaseRTPPayloadClass *gstbasertppayload_class; gobject_class = (GObjectClass *) klass; gstbasertppayload_class = (GstBaseRTPPayloadClass *) klass; gobject_class->set_property = gst_rtp_jpeg_pay_set_property; gobject_class->get_property = gst_rtp_jpeg_pay_get_property; gstbasertppayload_class->set_caps = gst_rtp_jpeg_pay_setcaps; gstbasertppayload_class->handle_buffer = gst_rtp_jpeg_pay_handle_buffer; g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_JPEG_QUALITY, g_param_spec_int ("quality", "Quality", "Quality factor on JPEG data", 0, 255, DEFAULT_JPEG_QUALITY, G_PARAM_READWRITE)); g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_JPEG_TYPE, g_param_spec_int ("type", "Type", "JPEG Type", 0, 255, DEFAULT_JPEG_TYPE, G_PARAM_READWRITE)); GST_DEBUG_CATEGORY_INIT (rtpjpegpay_debug, "rtpjpegpay", 0, "Motion JPEG RTP Payloader"); gst_rtp_jpeg_pay_init (GstRtpJPEGPay * rtpjpegpay, GstRtpJPEGPayClass * klass) rtpjpegpay->quality = DEFAULT_JPEG_QUALITY; rtpjpegpay->type = DEFAULT_JPEG_TYPE; static gboolean gst_rtp_jpeg_pay_setcaps (GstBaseRTPPayload * basepayload, GstCaps * caps) GstStructure *caps_structure = gst_caps_get_structure (caps, 0); GstRtpJPEGPay *rtpjpegpay; rtpjpegpay = GST_RTP_JPEG_PAY (basepayload); if (!gst_structure_get_int (caps_structure, "height", &rtpjpegpay->height)) { goto caps_fail; } if (!gst_structure_get_int (caps_structure, "width", &rtpjpegpay->width)) { rtpjpegpay->height /= 8; rtpjpegpay->width /= 8; gst_basertppayload_set_options (basepayload, "video", TRUE, "JPEG", 90000); gst_basertppayload_set_outcaps (basepayload, NULL); return TRUE; caps_fail: GST_ERROR_OBJECT (rtpjpegpay, "Failed to get width/height from caps"); return FALSE; static guint gst_rtp_jpeg_pay_header_size (const guint8 * data, guint offset) return data[offset] << 8 | data[offset + 1]; gst_rtp_jpeg_pay_read_quant_table (const guint8 * data, guint offset, const guint8 ** quantizer_table, RtpQuantHeader * qtable, guint8 index) gint quant_size = gst_rtp_jpeg_pay_header_size (data, offset); qtable->precision |= (data[offset + 2] & 0x10) ? (1 << index) : 0x00; /* ommit length and precision prefix from table */ quantizer_table[index] = &data[offset + QUANT_PREFIX_LEN]; quant_size -= QUANT_PREFIX_LEN; qtable->length += quant_size; return quant_size; static RtpJpegMarker gst_rtp_jpeg_pay_scan_marker (const guint8 * data, guint size, guint * offset) while ((data[(*offset)++] != JPEG_MARKER) && ((*offset) < size)); if (G_UNLIKELY ((*offset) >= size)) { return JPEG_MARKER_EOI; } else { return data[(*offset)++]; static GstFlowReturn gst_rtp_jpeg_pay_handle_buffer (GstBaseRTPPayload * basepayload, GstBuffer * buffer) GstClockTime timestamp; GstFlowReturn ret = GST_FLOW_ERROR; RtpJpegHeader jpeg_header; RtpQuantHeader quant_header; const guint8 *jpeg_quantizer_table[Q_TABLE_MAX] = { NULL }; guint8 *data; guint8 quant_table_index = 0; guint size; guint mtu; guint bytes_left; guint quant_data_size = sizeof (quant_header); guint jpeg_header_size = 0; guint offset = 0; gboolean frame_done = FALSE; gboolean sos_found = FALSE; mtu = GST_BASE_RTP_PAYLOAD_MTU (rtpjpegpay); jpeg_header.type_spec = 0; jpeg_header.offset = 0; jpeg_header.type = rtpjpegpay->type; jpeg_header.q = rtpjpegpay->quality; jpeg_header.width = rtpjpegpay->width; jpeg_header.height = rtpjpegpay->height; size = GST_BUFFER_SIZE (buffer); data = GST_BUFFER_DATA (buffer); timestamp = GST_BUFFER_TIMESTAMP (buffer); /* parse the jpeg header for 'start of scan' and read quant tables if needed */ while (!sos_found && (offset < size)) { switch (gst_rtp_jpeg_pay_scan_marker (data, size, &offset)) { case JPEG_MARKER_JFIF: case JPEG_MARKER_CMT: case JPEG_MARKER_SOF: case JPEG_MARKER_DHT: offset += gst_rtp_jpeg_pay_header_size (data, offset); break; case JPEG_MARKER_DQT:{ if ((jpeg_header.q >= 128) && (quant_table_index < Q_TABLE_MAX)) { if (!quant_table_index) { quant_header.length = 0; quant_header.precision = 0; quant_header.mbz = 0; } quant_data_size += gst_rtp_jpeg_pay_read_quant_table (data, offset, jpeg_quantizer_table, &quant_header, quant_table_index); quant_table_index++; } } case JPEG_MARKER_SOS: sos_found = TRUE; jpeg_header_size = offset + gst_rtp_jpeg_pay_header_size (data, offset); case JPEG_MARKER_EOI: GST_WARNING ("EOI reached before SOS!"); case JPEG_MARKER_SOI: default: } size -= jpeg_header_size; data += jpeg_header_size; offset = 0; bytes_left = sizeof (jpeg_header) + quant_data_size + size; while (!frame_done) { GstBuffer *outbuf; guint8 *payload; guint payload_size = (bytes_left < mtu ? bytes_left : mtu); outbuf = gst_rtp_buffer_new_allocate (payload_size, 0, 0); GST_BUFFER_TIMESTAMP (outbuf) = timestamp; if (payload_size == bytes_left) { frame_done = TRUE; gst_rtp_buffer_set_marker (outbuf, 1); payload = gst_rtp_buffer_get_payload (outbuf); memcpy (payload, &jpeg_header, sizeof (jpeg_header)); payload += sizeof (jpeg_header); payload_size -= sizeof (jpeg_header); /* only send quant table with first packet */ if (G_UNLIKELY (quant_data_size > 0)) { guint8 index; const guint8 table_size = quant_header.length / quant_table_index; quant_header.length = g_htons (quant_header.length); memcpy (payload, &quant_header, sizeof (quant_header)); payload += sizeof (quant_header); for (index = 0; index < quant_table_index; index++) { memcpy (payload, jpeg_quantizer_table[index], table_size); payload += table_size; payload_size -= quant_data_size; bytes_left -= quant_data_size; quant_data_size = 0; memcpy (payload, &data[offset], payload_size); ret = gst_basertppayload_push (basepayload, outbuf); if (ret != GST_FLOW_OK) break; bytes_left -= payload_size; offset += payload_size; jpeg_header.offset = ((offset & 0x0000FF) << 16) | ((offset & 0xFF0000) >> 16) | (offset & 0x00FF00); jpeg_header.offset = offset; gst_buffer_unref (buffer); return ret; gst_rtp_jpeg_pay_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) rtpjpegpay = GST_RTP_JPEG_PAY (object); switch (prop_id) { case PROP_JPEG_QUALITY: rtpjpegpay->quality = g_value_get_int (value); GST_DEBUG_OBJECT (object, "quality = %d", rtpjpegpay->quality); case PROP_JPEG_TYPE: rtpjpegpay->type = g_value_get_int (value); GST_DEBUG_OBJECT (object, "type = %d", rtpjpegpay->type); default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); gst_rtp_jpeg_pay_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) g_value_set_int (value, rtpjpegpay->quality); g_value_set_int (value, rtpjpegpay->type); gboolean gst_rtp_jpeg_pay_plugin_init (GstPlugin * plugin) return gst_element_register (plugin, "rtpjpegpay", GST_RANK_NONE, GST_TYPE_RTP_JPEG_PAY); --- NEW FILE: gstrtpjpegpay.h --- #ifndef __GST_RTP_JPEG_PAY_H__ #define __GST_RTP_JPEG_PAY_H__ #include <gst/gst.h> #include <gst/rtp/gstbasertppayload.h> G_BEGIN_DECLS #define GST_TYPE_RTP_JPEG_PAY \ (gst_rtp_jpeg_pay_get_type()) #define GST_RTP_JPEG_PAY(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_JPEG_PAY,GstRtpJPEGPay)) #define GST_RTP_JPEG_PAY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_JPEG_PAY,GstRtpJPEGPayClass)) #define GST_IS_RTP_JPEG_PAY(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_JPEG_PAY)) #define GST_IS_RTP_JPEG_PAY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_JPEG_PAY)) typedef struct _GstRtpJPEGPay GstRtpJPEGPay; typedef struct _GstRtpJPEGPayClass GstRtpJPEGPayClass; struct _GstRtpJPEGPay GstBaseRTPPayload payload; gint height; guint8 quality; gint width; struct _GstRtpJPEGPayClass GstBaseRTPPayloadClass parent_class; gboolean gst_rtp_jpeg_pay_plugin_init (GstPlugin * plugin); G_END_DECLS #endif /* __GST_RTP_JPEG_PAY_H__ */ |