diff --git a/include/speex/speex_bits.h b/include/speex/speex_bits.h
index 234ec53..df3975b 100644
--- a/include/speex/speex_bits.h
+++ b/include/speex/speex_bits.h
@@ -166,6 +166,15 @@ int speex_bits_remaining(SpeexBits *bits);
  */
 void speex_bits_insert_terminator(SpeexBits *bits);
 
+/** Returns number of full Speex frames in the stream and advance the position
+ * of the "bit cursor" to the end of the stream.
+ *  
+ * @param bits Bit-stream to operate on
+ * @return Number of full Speex frames in the stream. Returns -2 if stream is
+ * severely corrupted.
+ */
+int speex_bits_get_num_frames(SpeexBits *bits);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/libspeex/bits.c b/libspeex/bits.c
index 95adbfd..1326416 100644
--- a/libspeex/bits.c
+++ b/libspeex/bits.c
@@ -39,12 +39,17 @@
 #include "../include/speex/speex_bits.h"
 #include "arch.h"
 #include "os_support.h"
+#include "modes.h"
+#include "nb_celp.h"
 
 /* Maximum size of the bit-stream (for fixed-size allocation) */
 #ifndef MAX_CHARS_PER_FRAME
 #define MAX_CHARS_PER_FRAME (2000/BYTES_PER_CHAR)
 #endif
 
+static const int inband_skip_table[16] =
+   {1, 1, 4, 4, 4, 4, 4, 4, 8, 8, 16, 16, 32, 32, 64, 64 };
+
 EXPORT void speex_bits_init(SpeexBits *bits)
 {
    bits->chars = (char*)speex_alloc(MAX_CHARS_PER_FRAME);
@@ -370,3 +375,111 @@ EXPORT void speex_bits_insert_terminator(SpeexBits *bits)
    while (bits->bitPtr)
       speex_bits_pack(bits, 1, 1);
 }
+
+static int speex_bits_skip_wb_layers(SpeexBits *bits)
+{
+   unsigned int submode;
+   unsigned int advance;
+
+   /* skip up to two wideband frames */
+   if (  (speex_bits_remaining(bits) >= 4)
+      && speex_bits_unpack_unsigned(bits, 1))
+   {
+      submode = speex_bits_unpack_unsigned(bits, 3);
+      advance = wb_skip_table[submode];
+      if (advance < 0)
+      {
+         speex_notify("Invalid mode encountered. The stream is corrupted.");
+         return -2;
+      } 
+/*      printf("\tWB layer skipped: %d bits\n", advance); */
+      advance -= (SB_SUBMODE_BITS+1);
+      speex_bits_advance(bits, advance);
+
+      if ( (speex_bits_remaining(bits) >= 4)
+         && speex_bits_unpack_unsigned(bits, 1))
+      {
+         submode = speex_bits_unpack_unsigned(bits, 3);
+         advance = wb_skip_table[submode];
+         if (advance < 0)
+         {
+            speex_notify("Invalid mode encountered. The stream is corrupted.");
+            return -2;
+         } 
+/*         printf("\tWB layer skipped: %d bits\n", advance); */
+         advance -= (SB_SUBMODE_BITS+1);
+         speex_bits_advance(bits, advance);
+
+         if ( (speex_bits_remaining(bits) >= 4)
+            && speex_bits_unpack_unsigned(bits, 1))
+         {
+            /* too many in a row */
+            speex_notify("More than two wideband layers found. The stream is corrupted.");
+            return -2;
+         }
+      }
+
+   }
+   return 0;
+}
+
+EXPORT int speex_bits_get_num_frames(SpeexBits *bits)
+{
+   int frame_count = 0;
+   unsigned int submode;
+
+/*   printf("speex_get_samples(%d)\n", speex_bits_nbytes(bits)); */
+   while (speex_bits_remaining(bits) >= 5) {
+      /* skip wideband frames */
+      if (speex_bits_skip_wb_layers(bits) < 0)
+      {
+/*         printf("\tERROR reading wideband frames\n"); */
+         break;
+      }
+
+      if (speex_bits_remaining(bits) < 4)
+      {
+/*         printf("\tEND of stream\n"); */
+         break;
+      }
+
+      /* get control bits */
+      submode = speex_bits_unpack_unsigned(bits, 4);
+/*      printf("\tCONTROL: %d at %d\n", submode, bits->charPtr*8+bits->bitPtr); */
+
+      if (submode == 15){
+/*         printf("\tTERMINATOR\n"); */
+         break;
+      } else if (submode == 14) {
+         /* in-band signal; next 4 bits contain signal id */
+         submode = speex_bits_unpack_unsigned(bits, 4);
+/*         printf("\tIN-BAND %d bits\n", SpeexInBandSz[submode]); */
+         speex_bits_advance(bits, inband_skip_table[submode]);
+      } else if (submode == 13) {
+         /* user in-band; next 5 bits contain msg len */
+         submode = speex_bits_unpack_unsigned(bits, 5);
+/*         printf("\tUSER-BAND %d bytes\n", submode); */
+         speex_bits_advance(bits, submode * 8);
+      } else if (submode > 8) {
+/*         printf("\tUNKNOWN sub-mode %d\n", submode); */
+         break;
+      } else {
+         /* NB frame; skip number bits for submode (less the 5 control bits) */
+         unsigned int advance = submode;
+         speex_mode_query(&speex_nb_mode, SPEEX_SUBMODE_BITS_PER_FRAME, &advance);
+         if (advance < 0)
+         {
+/*            printf("Invalid mode encountered. The stream is corrupted."); */
+            return -2;
+         } 
+/*         printf("\tSUBMODE %d: %d bits\n", submode, advance); */
+         advance -= (NB_SUBMODE_BITS+1);
+         speex_bits_advance(bits, advance);
+
+         frame_count += 1;
+      }
+   }
+
+/*   printf("\tFRAMES: %d\n", frame_count); */
+   return frame_count;
+}