diff --git a/ChangeLog b/ChangeLog index 25c7b72480..a82b06e84c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +2007-04-12 Thomas Vander Stichele + + * gst/rtp/Makefile.am: + * gst/rtp/fnv1hash.c (MASK_24, FNV1_HASH_32_INIT, FNV1_HASH_32_PRIME, + fnv1_hash_32_new, fnv1_hash_32_update, fnv1_hash_32_to_24): + * gst/rtp/fnv1hash.h (__GST_FNV1_HASH_H__): + Add a simple hashing implementation that we can use to generate + a 24-bit ident value based on the codebooks for vorbis and theora. + * gst/rtp/gstrtptheorapay.c (gst_rtp_theora_pay_finish_headers, + gst_rtp_theora_pay_handle_buffer): + * gst/rtp/gstrtpvorbisdepay.c + (gst_rtp_vorbis_depay_parse_configuration, + gst_rtp_vorbis_depay_switch_codebook, gst_rtp_vorbis_depay_process): + * gst/rtp/gstrtpvorbispay.c (gst_rtp_vorbis_pay_reset_packet, + gst_rtp_vorbis_pay_init_packet, gst_rtp_vorbis_pay_flush_packet, + gst_rtp_vorbis_pay_finish_headers, gst_rtp_vorbis_pay_handle_buffer): + Use the hashing function, ensuring that the same codebooks result + in the same ident and thus the same SDP description. + Various log fixes/changes. + 2007-04-12 Wim Taymans Patch by: jerry tan diff --git a/gst/rtp/Makefile.am b/gst/rtp/Makefile.am index 6f4acefe1f..3a2be68930 100644 --- a/gst/rtp/Makefile.am +++ b/gst/rtp/Makefile.am @@ -1,6 +1,7 @@ plugin_LTLIBRARIES = libgstrtp.la libgstrtp_la_SOURCES = \ + fnv1hash.c \ gstrtp.c \ gstrtpdepay.c \ gstrtpac3depay.c \ @@ -54,6 +55,7 @@ libgstrtp_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \ libgstrtp_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) noinst_HEADERS = \ + fnv1hash.h \ gstrtpL16depay.h \ gstrtpL16pay.h \ gstrtpac3depay.h \ diff --git a/gst/rtp/fnv1hash.c b/gst/rtp/fnv1hash.c new file mode 100644 index 0000000000..84fac9ad15 --- /dev/null +++ b/gst/rtp/fnv1hash.c @@ -0,0 +1,61 @@ +/* GStreamer + * Copyright (C) 2007 Thomas Vander Stichele + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +/* This file implements FNV-1 hashing used in the Ogg payload encoders + * to generate the 24-bit ident value based on the header pages. + * See http://isthe.com/chongo/tech/comp/fnv/ + */ + +#define MASK_24 (((guint32) 1 << 24) -1) + +#define FNV1_HASH_32_INIT ((guint32) 0x811C9DC5L) +//2166136261L) +#define FNV1_HASH_32_PRIME 16777619 + +guint32 +fnv1_hash_32_new (void) +{ + return FNV1_HASH_32_INIT; +} + +guint32 +fnv1_hash_32_update (guint32 hash, const guchar * data, guint length) +{ + guint i; + const guchar *p = data; + + for (i = 0; i < length; ++i, ++p) { + hash *= FNV1_HASH_32_PRIME; + hash ^= *p; + } + + return hash; +} + +guint32 +fnv1_hash_32_to_24 (guint32 hash) +{ + return (hash >> 24) ^ (hash & MASK_24); +} diff --git a/gst/rtp/fnv1hash.h b/gst/rtp/fnv1hash.h new file mode 100644 index 0000000000..ea3c6b6b35 --- /dev/null +++ b/gst/rtp/fnv1hash.h @@ -0,0 +1,36 @@ +/* GStreamer + * Copyright (C) 2007 Thomas Vander Stichele + * + * 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. + */ + +#ifndef __GST_FNV1_HASH_H__ +#define __GST_FNV1_HASH_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +guint32 fnv1_hash_32_new (); +guint32 fnv1_hash_32_update (guint32 hash, const guchar *data, guint length); +guint32 fnv1_hash_32_to_24 (guint32 hash); + +G_END_DECLS + +#endif /* __GST_FNV1_HASH_H__ */ + diff --git a/gst/rtp/gstrtptheorapay.c b/gst/rtp/gstrtptheorapay.c index db8a5872fe..418b9f0c21 100644 --- a/gst/rtp/gstrtptheorapay.c +++ b/gst/rtp/gstrtptheorapay.c @@ -25,6 +25,7 @@ #include +#include "fnv1hash.h" #include "gstrtptheorapay.h" #define THEORA_ID_LEN 42 @@ -230,8 +231,11 @@ gst_rtp_theora_pay_finish_headers (GstBaseRTPPayload * basepayload) goto no_headers; /* we need exactly 2 header packets */ - if (g_list_length (rtptheorapay->headers) != 2) + if (g_list_length (rtptheorapay->headers) != 2) { + GST_DEBUG_OBJECT (rtptheorapay, "We need 2 headers but have %d", + g_list_length (rtptheorapay->headers)); goto no_headers; + } /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Number of packed headers | @@ -266,9 +270,13 @@ gst_rtp_theora_pay_finish_headers (GstBaseRTPPayload * basepayload) /* count the size of the headers first */ length = 0; + ident = fnv1_hash_32_new (); for (walk = rtptheorapay->headers; walk; walk = g_list_next (walk)) { GstBuffer *buf = GST_BUFFER_CAST (walk->data); + ident = + fnv1_hash_32_update (ident, GST_BUFFER_DATA (buf), + GST_BUFFER_SIZE (buf)); length += GST_BUFFER_SIZE (buf); } @@ -283,8 +291,8 @@ gst_rtp_theora_pay_finish_headers (GstBaseRTPPayload * basepayload) data[2] = 0; data[3] = 1; - /* we generate a random ident for this configuration */ - ident = rtptheorapay->payload_ident = g_random_int (); + ident = fnv1_hash_32_to_24 (ident); + rtptheorapay->payload_ident = ident; /* take lower 3 bytes */ data[4] = (ident >> 16) & 0xff; @@ -427,7 +435,8 @@ gst_rtp_theora_pay_handle_buffer (GstBaseRTPPayload * basepayload, if (data[0] & 0x80) { /* header */ if (data[0] == 0x80) { - /* identification, we need to parse this in order to get the clock rate. */ + /* identification, we need to parse this in order to get the clock rate. + */ if (G_UNLIKELY (!gst_rtp_theora_pay_parse_id (basepayload, data, size))) goto parse_id_failed; TDT = 1; @@ -451,7 +460,7 @@ gst_rtp_theora_pay_handle_buffer (GstBaseRTPPayload * basepayload, ret = GST_FLOW_OK; goto done; } else if (TDT != 0) { - GST_DEBUG_OBJECT (rtptheorapay, "collecting header"); + GST_DEBUG_OBJECT (rtptheorapay, "collecting header, buffer %p", buffer); /* append header to the list of headers */ rtptheorapay->headers = g_list_append (rtptheorapay->headers, buffer); ret = GST_FLOW_OK; diff --git a/gst/rtp/gstrtpvorbisdepay.c b/gst/rtp/gstrtpvorbisdepay.c index eab6210079..d71c72ac0b 100644 --- a/gst/rtp/gstrtpvorbisdepay.c +++ b/gst/rtp/gstrtpvorbisdepay.c @@ -227,7 +227,7 @@ gst_rtp_vorbis_depay_parse_configuration (GstRtpVorbisDepay * rtpvorbisdepay, size -= 5; data += 5; - GST_DEBUG_OBJECT (rtpvorbisdepay, "header %d, ident %08x, length %u", i, + GST_DEBUG_OBJECT (rtpvorbisdepay, "header %d, ident 0x%08x, length %u", i, ident, length); if (size < length + VORBIS_ID_LEN) @@ -363,6 +363,7 @@ gst_rtp_vorbis_depay_switch_codebook (GstRtpVorbisDepay * rtpvorbisdepay, GList *walk; gboolean res = FALSE; + GST_DEBUG_OBJECT (rtpvorbisdepay, "Looking up code book ident 0x%08x", ident); for (walk = rtpvorbisdepay->configs; walk; walk = g_list_next (walk)) { GstRtpVorbisConfig *conf = (GstRtpVorbisConfig *) walk->data; @@ -436,6 +437,7 @@ gst_rtp_vorbis_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) if (G_UNLIKELY (VDT == 3)) goto ignore_reserved; + GST_DEBUG_OBJECT (depayload, "header: 0x%08x", header); ident = (header >> 8) & 0xffffff; F = (header & 0xc0) >> 6; packets = (header & 0xf); @@ -447,9 +449,11 @@ gst_rtp_vorbis_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) if (!rtpvorbisdepay->config) { /* we don't have an active codebook, find the codebook and * activate it */ + GST_DEBUG_OBJECT (rtpvorbisdepay, "No active codebook, switching"); do_switch = TRUE; } else if (rtpvorbisdepay->config->ident != ident) { /* codebook changed */ + GST_DEBUG_OBJECT (rtpvorbisdepay, "codebook changed, switching"); do_switch = TRUE; } if (do_switch) { diff --git a/gst/rtp/gstrtpvorbispay.c b/gst/rtp/gstrtpvorbispay.c index 0482e0c50b..35478a27c1 100644 --- a/gst/rtp/gstrtpvorbispay.c +++ b/gst/rtp/gstrtpvorbispay.c @@ -25,6 +25,7 @@ #include +#include "fnv1hash.h" #include "gstrtpvorbispay.h" GST_DEBUG_CATEGORY_STATIC (rtpvorbispay_debug); @@ -133,7 +134,7 @@ gst_rtp_vorbis_pay_reset_packet (GstRtpVorbisPay * rtpvorbispay, guint8 VDT) { guint payload_len; - GST_DEBUG_OBJECT (rtpvorbispay, "reset packet"); + GST_LOG_OBJECT (rtpvorbispay, "reset packet"); rtpvorbispay->payload_pos = 4; payload_len = gst_rtp_buffer_get_payload_len (rtpvorbispay->packet); @@ -148,7 +149,7 @@ static void gst_rtp_vorbis_pay_init_packet (GstRtpVorbisPay * rtpvorbispay, guint8 VDT, GstClockTime timestamp) { - GST_DEBUG_OBJECT (rtpvorbispay, "starting new packet, VDT: %d", VDT); + GST_LOG_OBJECT (rtpvorbispay, "starting new packet, VDT: %d", VDT); if (rtpvorbispay->packet) gst_buffer_unref (rtpvorbispay->packet); @@ -172,7 +173,7 @@ gst_rtp_vorbis_pay_flush_packet (GstRtpVorbisPay * rtpvorbispay) if (!rtpvorbispay->packet || rtpvorbispay->payload_pos <= 4) return GST_FLOW_OK; - GST_DEBUG_OBJECT (rtpvorbispay, "flushing packet"); + GST_LOG_OBJECT (rtpvorbispay, "flushing packet"); /* fix header */ payload = gst_rtp_buffer_get_payload (rtpvorbispay->packet); @@ -261,9 +262,13 @@ gst_rtp_vorbis_pay_finish_headers (GstBaseRTPPayload * basepayload) /* count the size of the headers first */ length = 0; + ident = fnv1_hash_32_new (); for (walk = rtpvorbispay->headers; walk; walk = g_list_next (walk)) { GstBuffer *buf = GST_BUFFER_CAST (walk->data); + ident = + fnv1_hash_32_update (ident, GST_BUFFER_DATA (buf), + GST_BUFFER_SIZE (buf)); length += GST_BUFFER_SIZE (buf); } @@ -278,8 +283,9 @@ gst_rtp_vorbis_pay_finish_headers (GstBaseRTPPayload * basepayload) data[2] = 0; data[3] = 1; - /* we generate a random ident for this configuration */ - ident = rtpvorbispay->payload_ident = g_random_int (); + ident = fnv1_hash_32_to_24 (ident); + rtpvorbispay->payload_ident = ident; + GST_DEBUG_OBJECT (rtpvorbispay, "ident 0x%08x", ident); /* take lower 3 bytes */ data[4] = (ident >> 16) & 0xff; @@ -416,7 +422,7 @@ gst_rtp_vorbis_pay_handle_buffer (GstBaseRTPPayload * basepayload, duration = GST_BUFFER_DURATION (buffer); timestamp = GST_BUFFER_TIMESTAMP (buffer); - GST_DEBUG_OBJECT (rtpvorbispay, "size %u, duration %" GST_TIME_FORMAT, + GST_LOG_OBJECT (rtpvorbispay, "size %u, duration %" GST_TIME_FORMAT, size, GST_TIME_ARGS (duration)); if (G_UNLIKELY (size < 1 || size > 0xffff)) @@ -496,7 +502,7 @@ gst_rtp_vorbis_pay_handle_buffer (GstBaseRTPPayload * basepayload, while (size) { plen = MIN (rtpvorbispay->payload_left - 2, size); - GST_DEBUG_OBJECT (rtpvorbispay, "append %u bytes", plen); + GST_LOG_OBJECT (rtpvorbispay, "append %u bytes", plen); /* data is copied in the payload with a 2 byte length header */ ppos[0] = (plen >> 8) & 0xff;