]> git.sesse.net Git - vlc/blobdiff - src/input/input_ext-dec.c
* Fixed an alignment problem in UnalignedShowBits().
[vlc] / src / input / input_ext-dec.c
index d8f0d7158f6f9199745b7863b22fe03220f0ff33..e89e5218d598ec5824ebd38464e23b381d288c43 100644 (file)
@@ -3,7 +3,7 @@
  *****************************************************************************
  * Copyright (C) 1998, 1999, 2000 VideoLAN
  *
- * Authors: 
+ * Authors: Christophe Massiot <massiot@via.ecp.fr>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -34,6 +34,8 @@
 
 #include "stream_control.h"
 #include "input_ext-dec.h"
+#include "input_ext-intf.h"
+
 #include "input.h"
 
 /*****************************************************************************
@@ -43,6 +45,8 @@ void InitBitstream( bit_stream_t * p_bit_stream, decoder_fifo_t * p_fifo )
 {
     p_bit_stream->p_decoder_fifo = p_fifo;
     p_bit_stream->pf_next_data_packet = NextDataPacket;
+    p_bit_stream->pf_bitstream_callback = NULL;
+    p_bit_stream->p_callback_arg = NULL;
 
     /* Get the first data packet. */
     vlc_mutex_lock( &p_fifo->data_lock );
@@ -61,6 +65,15 @@ void InitBitstream( bit_stream_t * p_bit_stream, decoder_fifo_t * p_fifo )
     p_bit_stream->fifo.buffer = 0;
     p_bit_stream->fifo.i_available = 0;
     vlc_mutex_unlock( &p_fifo->data_lock );
+
+    if( p_bit_stream->p_byte <= p_bit_stream->p_end - sizeof(WORD_TYPE) )
+    {
+        /* Get aligned on a word boundary.
+         * NB : we _will_ get aligned, because we have at most 
+         * sizeof(WORD_TYPE) - 1 bytes to store, and at least
+         * sizeof(WORD_TYPE) - 1 empty bytes in the bit buffer. */
+        AlignWord( p_bit_stream );
+    }
 }
 
 /*****************************************************************************
@@ -68,26 +81,8 @@ void InitBitstream( bit_stream_t * p_bit_stream, decoder_fifo_t * p_fifo )
  *****************************************************************************/
 void NextDataPacket( bit_stream_t * p_bit_stream )
 {
-    WORD_TYPE           buffer_left;
-    /* FIXME : not portable in a 64bit environment */
-    int                 i_bytes_left;
     decoder_fifo_t *    p_fifo = p_bit_stream->p_decoder_fifo;
-
-    /* Buffer used at the end of a decoder thread, to give it zero
-     * values if needed. */
-    static byte_t       p_zero[64] = { 0, 0, 0, 0, 0, 0, 0,
-                                       0, 0, 0, 0, 0, 0, 0,
-                                       0, 0, 0, 0, 0, 0, 0,
-                                       0, 0, 0, 0, 0, 0, 0,
-                                       0, 0, 0, 0, 0, 0, 0,
-                                       0, 0, 0, 0, 0, 0, 0,
-                                       0, 0, 0, 0, 0, 0, 0,
-                                       0, 0, 0, 0, 0, 0, 0 };
-
-    /* Put the remaining bytes (not aligned on a word boundary) in a
-     * temporary buffer. */
-    i_bytes_left = p_bit_stream->p_end - p_bit_stream->p_byte;
-    buffer_left = *((WORD_TYPE *)p_bit_stream->p_end - 1);
+    boolean_t           b_new_pes;
 
     /* We are looking for the next data packet that contains real data,
      * and not just a PES header */
@@ -102,47 +97,31 @@ void NextDataPacket( bit_stream_t * p_bit_stream )
              * that's why we need to take the lock before. */
             vlc_mutex_lock( &p_fifo->data_lock );
 
-            /* Is the input thread dying ? */
-            if( p_fifo->b_die )
-            {
-                vlc_mutex_unlock( &p_fifo->data_lock );
-                p_bit_stream->p_byte = p_zero;
-                p_bit_stream->p_end = &p_zero[sizeof(p_zero) - 1];
-                return;
-            }
-
-            /* We should increase the start index of the decoder fifo, but
-             * if we do this now, the input thread could overwrite the
-             * pointer to the current PES packet, and we weren't able to
-             * give it back to the netlist. That's why we free the PES
-             * packet first. */
+            /* Free the previous PES packet. */
             p_fifo->pf_delete_pes( p_fifo->p_packets_mgt,
                                    DECODER_FIFO_START( *p_fifo ) );
             DECODER_FIFO_INCSTART( *p_fifo );
 
-            while( DECODER_FIFO_ISEMPTY( *p_fifo ) )
+            if( DECODER_FIFO_ISEMPTY( *p_fifo ) )
             {
+                /* Wait for the input to tell us when we receive a packet. */
                 vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
-                if( p_fifo->b_die )
-                {
-                    vlc_mutex_unlock( &p_fifo->data_lock );
-                    p_bit_stream->p_byte = p_zero;
-                    p_bit_stream->p_end = &p_zero[sizeof(p_zero) - 1];
-                    return;
-                }
             }
 
             /* The next byte could be found in the next PES packet */
             p_bit_stream->p_data = DECODER_FIFO_START( *p_fifo )->p_first;
 
-            /* We can release the fifo's data lock */
             vlc_mutex_unlock( &p_fifo->data_lock );
+
+            b_new_pes = 1;
         }
         else
         {
             /* Perhaps the next data packet of the current PES packet contains
              * real data (ie its payload's size is greater than 0). */
             p_bit_stream->p_data = p_bit_stream->p_data->p_next;
+
+            b_new_pes = 0;
         }
     } while ( p_bit_stream->p_data->p_payload_start
                == p_bit_stream->p_data->p_payload_end );
@@ -151,7 +130,203 @@ void NextDataPacket( bit_stream_t * p_bit_stream )
     p_bit_stream->p_byte = p_bit_stream->p_data->p_payload_start;
     p_bit_stream->p_end  = p_bit_stream->p_data->p_payload_end;
 
-    /* Copy remaining bits of the previous packet */
-    *((WORD_TYPE *)p_bit_stream->p_byte - 1) = buffer_left;
-    p_bit_stream->p_byte -= i_bytes_left;
+    /* Call back the decoder. */
+    if( p_bit_stream->pf_bitstream_callback != NULL )
+    {
+        p_bit_stream->pf_bitstream_callback( p_bit_stream, b_new_pes );
+    }
+}
+
+/*****************************************************************************
+ * UnalignedShowBits : return i_bits bits from the bit stream, even when
+ * not aligned on a word boundary
+ *****************************************************************************/
+u32 UnalignedShowBits( bit_stream_t * p_bit_stream, unsigned int i_bits )
+{
+    /* We just fill in the bit buffer. */
+    while( p_bit_stream->fifo.i_available < i_bits )
+    {
+        if( p_bit_stream->p_byte < p_bit_stream->p_end )
+        {
+            p_bit_stream->fifo.buffer |= *(p_bit_stream->p_byte++)
+                                            << (8 * sizeof(WORD_TYPE) - 8
+                                            - p_bit_stream->fifo.i_available);
+            p_bit_stream->fifo.i_available += 8;
+        }
+        else
+        {
+            p_bit_stream->pf_next_data_packet( p_bit_stream );
+
+            if( (ptrdiff_t)p_bit_stream->p_byte & (sizeof(WORD_TYPE) - 1) )
+            {
+                /* We are not aligned anymore. */
+                if( ((ptrdiff_t)p_bit_stream->p_byte
+                                    & (sizeof(WORD_TYPE) - 1)) * 8
+                        < p_bit_stream->fifo.i_available )
+                {
+                    /* We are not aligned, and won't be. Copy the first word
+                     * of the packet in a temporary buffer, and we'll see
+                     * later. */
+                    int     i;
+                    p_bit_stream->i_showbits_buffer = 0;
+
+                    for( i = 0; i < sizeof(WORD_TYPE) ; i++ )
+                    {
+                        if( p_bit_stream->p_byte >= p_bit_stream->p_end )
+                        {
+                            p_bit_stream->pf_next_data_packet( p_bit_stream );
+                        }
+                        ((byte_t *)&p_bit_stream->i_showbits_buffer)[i] =
+                            * p_bit_stream->p_byte;
+                        p_bit_stream->p_byte++;
+                    }
+
+                    /* This is kind of kludgy. */
+                    p_bit_stream->p_data->p_payload_start += sizeof(WORD_TYPE);
+                    p_bit_stream->p_byte =
+                        (byte_t *)&p_bit_stream->i_showbits_buffer;
+                    p_bit_stream->p_end =
+                        (byte_t *)&p_bit_stream->i_showbits_buffer
+                            + sizeof(WORD_TYPE);
+                    p_bit_stream->showbits_data.p_next = p_bit_stream->p_data;
+                    p_bit_stream->p_data = &p_bit_stream->showbits_data;
+                }
+                else
+                {
+                    /* We are not aligned, but we can be. */
+                    AlignWord( p_bit_stream );
+                }
+            }
+
+            return( ShowBits( p_bit_stream, i_bits ) );
+        }
+    }
+    return( p_bit_stream->fifo.buffer >> (8 * sizeof(WORD_TYPE) - i_bits) );
 }
+
+/*****************************************************************************
+ * UnalignedGetBits : returns i_bits bits from the bit stream and removes
+ * them from the buffer, even when the bit stream is not aligned on a word
+ * boundary
+ *****************************************************************************/
+u32 UnalignedGetBits( bit_stream_t * p_bit_stream, unsigned int i_bits )
+{
+    u32         i_result;
+
+    i_result = p_bit_stream->fifo.buffer
+                    >> (8 * sizeof(WORD_TYPE) - i_bits);
+    i_bits = -p_bit_stream->fifo.i_available;
+
+    /* Gather missing bytes. */
+    while( i_bits >= 8 )
+    {
+        if( p_bit_stream->p_byte < p_bit_stream->p_end )
+        {
+            i_result |= *(p_bit_stream->p_byte++) << (i_bits - 8);
+            i_bits -= 8;
+        }
+        else
+        {
+            p_bit_stream->pf_next_data_packet( p_bit_stream );
+            i_result |= *(p_bit_stream->p_byte++) << (i_bits - 8);
+            i_bits -= 8;
+        }
+    }
+
+    /* Gather missing bits. */
+    if( i_bits > 0 )
+    {
+        unsigned int    i_tmp = 8 - i_bits;
+
+        if( p_bit_stream->p_byte < p_bit_stream->p_end )
+        {
+            i_result |= *p_bit_stream->p_byte >> i_tmp;
+            p_bit_stream->fifo.buffer = *(p_bit_stream->p_byte++)
+                 << ( sizeof(WORD_TYPE) * 8 - i_tmp );
+            p_bit_stream->fifo.i_available = i_tmp;
+        }
+        else
+        {
+            p_bit_stream->pf_next_data_packet( p_bit_stream );
+            i_result |= *p_bit_stream->p_byte >> i_tmp;
+            p_bit_stream->fifo.buffer = *(p_bit_stream->p_byte++)
+                 << ( sizeof(WORD_TYPE) * 8 - i_tmp );
+            p_bit_stream->fifo.i_available = i_tmp;
+        }
+    }
+    else
+    {
+        p_bit_stream->fifo.i_available = 0;
+        p_bit_stream->fifo.buffer = 0;
+    }
+
+    if( p_bit_stream->p_byte <= p_bit_stream->p_end - sizeof(WORD_TYPE) )
+    {
+        /* Get aligned on a word boundary. Otherwise it is safer
+         * to do it the next time.
+         * NB : we _will_ get aligned, because we have at most 
+         * sizeof(WORD_TYPE) - 1 bytes to store, and at least
+         * sizeof(WORD_TYPE) - 1 empty bytes in the bit buffer. */
+        AlignWord( p_bit_stream );
+    }
+
+    return( i_result );
+}
+
+/*****************************************************************************
+ * UnalignedRemoveBits : removes i_bits (== -i_available) from the bit
+ * buffer, even when the bit stream is not aligned on a word boundary
+ *****************************************************************************/
+void UnalignedRemoveBits( bit_stream_t * p_bit_stream )
+{
+    /* First remove all unnecessary bytes. */
+    while( p_bit_stream->fifo.i_available <= -8 )
+    {
+        if( p_bit_stream->p_byte < p_bit_stream->p_end )
+        {
+            p_bit_stream->p_byte++;
+            p_bit_stream->fifo.i_available += 8;
+        }
+        else
+        {
+            p_bit_stream->pf_next_data_packet( p_bit_stream );
+            p_bit_stream->p_byte++;
+            p_bit_stream->fifo.i_available += 8;
+        }
+    }
+
+    /* Remove unnecessary bits. */
+    if( p_bit_stream->fifo.i_available < 0 )
+    {
+        if( p_bit_stream->p_byte < p_bit_stream->p_end )
+        {
+            p_bit_stream->fifo.buffer = *(p_bit_stream->p_byte++)
+                 << ( sizeof(WORD_TYPE) * 8 - 8
+                         - p_bit_stream->fifo.i_available );
+            p_bit_stream->fifo.i_available += 8;
+        }
+        else
+        {
+            p_bit_stream->pf_next_data_packet( p_bit_stream );
+            p_bit_stream->fifo.buffer = *(p_bit_stream->p_byte++)
+                 << ( sizeof(WORD_TYPE) * 8 - 8
+                         - p_bit_stream->fifo.i_available );
+            p_bit_stream->fifo.i_available += 8;
+        }
+    }
+    else
+    {
+        p_bit_stream->fifo.buffer = 0;
+    }
+
+    if( p_bit_stream->p_byte <= p_bit_stream->p_end - sizeof(WORD_TYPE) )
+    {
+        /* Get aligned on a word boundary. Otherwise it is safer
+         * to do it the next time.
+         * NB : we _will_ get aligned, because we have at most 
+         * sizeof(WORD_TYPE) - 1 bytes to store, and at least
+         * sizeof(WORD_TYPE) - 1 empty bytes in the bit buffer. */
+        AlignWord( p_bit_stream );
+    }
+}
+