]> git.sesse.net Git - vlc/blob - src/spu_decoder/spu_decoder.c
5f276966d231345f36c36bbe2d1395d920006d30
[vlc] / src / spu_decoder / spu_decoder.c
1 /*****************************************************************************
2  * spu_decoder.c : spu decoder thread
3  * (c)2000 VideoLAN
4  *****************************************************************************/
5
6 /* repompĂ© sur video_decoder.c
7  * FIXME: passer en terminate/destroy avec les signaux supplĂ©mentaires ?? */
8
9 /*****************************************************************************
10  * Preamble
11  *****************************************************************************/
12 //#include "vlc.h"
13
14 #include <errno.h>
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <unistd.h>
18 #include <string.h>
19 #include <sys/uio.h>
20
21 #include "config.h"
22 #include "common.h"
23 #include "mtime.h"
24 #include "vlc_thread.h"
25
26 #include "intf_msg.h"
27 #include "debug.h"                 /* XXX?? temporaire, requis par netlist.h */
28
29 #include "input.h"
30 #include "input_netlist.h"
31 #include "decoder_fifo.h"
32
33 #include "spu_decoder.h"
34
35 /*
36  * Local prototypes
37  */
38 static int      InitThread          ( spudec_thread_t *p_spudec );
39 static void     RunThread           ( spudec_thread_t *p_spudec );
40 static void     ErrorThread         ( spudec_thread_t *p_spudec );
41 static void     EndThread           ( spudec_thread_t *p_spudec );
42
43 /*****************************************************************************
44  * spudec_CreateThread: create a spu decoder thread
45  *****************************************************************************/
46 spudec_thread_t * spudec_CreateThread( input_thread_t * p_input )
47 {
48     spudec_thread_t *     p_spudec;
49
50     intf_DbgMsg("spudec debug: creating spu decoder thread\n");
51
52     /* Allocate the memory needed to store the thread's structure */
53     if ( (p_spudec = (spudec_thread_t *)malloc( sizeof(spudec_thread_t) )) == NULL )
54     {
55         intf_ErrMsg("spudec error: not enough memory for spudec_CreateThread() to create the new thread\n");
56         return( NULL );
57     }
58
59     /*
60      * Initialize the thread properties
61      */
62     p_spudec->b_die = 0;
63     p_spudec->b_error = 0;
64
65     /*
66      * Initialize the input properties
67      */
68     /* Initialize the decoder fifo's data lock and conditional variable and set
69      * its buffer as empty */
70     vlc_mutex_init( &p_spudec->fifo.data_lock );
71     vlc_cond_init( &p_spudec->fifo.data_wait );
72     p_spudec->fifo.i_start = 0;
73     p_spudec->fifo.i_end = 0;
74     /* Initialize the bit stream structure */
75     p_spudec->bit_stream.p_input = p_input;
76     p_spudec->bit_stream.p_decoder_fifo = &p_spudec->fifo;
77     p_spudec->bit_stream.fifo.buffer = 0;
78     p_spudec->bit_stream.fifo.i_available = 0;
79
80     /* Spawn the spu decoder thread */
81     if ( vlc_thread_create(&p_spudec->thread_id, "spu decoder",
82          (vlc_thread_func_t)RunThread, (void *)p_spudec) )
83     {
84         intf_ErrMsg("spudec error: can't spawn spu decoder thread\n");
85         free( p_spudec );
86         return( NULL );
87     }
88
89     intf_DbgMsg("spudec debug: spu decoder thread (%p) created\n", p_spudec);
90     return( p_spudec );
91 }
92
93 /*****************************************************************************
94  * spudec_DestroyThread: destroy a spu decoder thread
95  *****************************************************************************
96  * Destroy and terminate thread. This function will return 0 if the thread could
97  * be destroyed, and non 0 else. The last case probably means that the thread
98  * was still active, and another try may succeed.
99  *****************************************************************************/
100 void spudec_DestroyThread( spudec_thread_t *p_spudec )
101 {
102     intf_DbgMsg("spudec debug: requesting termination of spu decoder thread %p\n", p_spudec);
103
104     /* Ask thread to kill itself */
105     p_spudec->b_die = 1;
106
107     /* Warn the decoder that we're quitting */
108     vlc_mutex_lock( &p_spudec->fifo.data_lock );
109     vlc_cond_signal( &p_spudec->fifo.data_wait );
110     vlc_mutex_unlock( &p_spudec->fifo.data_lock );
111
112     /* Waiting for the decoder thread to exit */
113     /* Remove this as soon as the "status" flag is implemented */
114     vlc_thread_join( p_spudec->thread_id );
115 }
116
117 /* following functions are local */
118
119 /*****************************************************************************
120  * InitThread: initialize spu decoder thread
121  *****************************************************************************
122  * This function is called from RunThread and performs the second step of the
123  * initialization. It returns 0 on success. Note that the thread's flag are not
124  * modified inside this function.
125  *****************************************************************************/
126 static int InitThread( spudec_thread_t *p_spudec )
127 {
128     intf_DbgMsg("spudec debug: initializing spu decoder thread %p\n", p_spudec);
129
130     /* Our first job is to initialize the bit stream structure with the
131      * beginning of the input stream */
132     vlc_mutex_lock( &p_spudec->fifo.data_lock );
133     while ( DECODER_FIFO_ISEMPTY(p_spudec->fifo) )
134     {
135         if ( p_spudec->b_die )
136         {
137             vlc_mutex_unlock( &p_spudec->fifo.data_lock );
138             return( 1 );
139         }
140         vlc_cond_wait( &p_spudec->fifo.data_wait, &p_spudec->fifo.data_lock );
141     }
142
143     p_spudec->bit_stream.p_ts = DECODER_FIFO_START( p_spudec->fifo )->p_first_ts;
144     p_spudec->bit_stream.p_byte = p_spudec->bit_stream.p_ts->buffer + p_spudec->bit_stream.p_ts->i_payload_start;
145     p_spudec->bit_stream.p_end = p_spudec->bit_stream.p_ts->buffer + p_spudec->bit_stream.p_ts->i_payload_end;
146     vlc_mutex_unlock( &p_spudec->fifo.data_lock );
147
148     /* Mark thread as running and return */
149     intf_DbgMsg( "spudec debug: InitThread(%p) succeeded\n", p_spudec );
150     return( 0 );
151 }
152
153 /*****************************************************************************
154  * RunThread: spu decoder thread
155  *****************************************************************************
156  * spu decoder thread. This function does only return when the thread is
157  * terminated.
158  *****************************************************************************/
159 static void RunThread( spudec_thread_t *p_spudec )
160 {
161     intf_DbgMsg("spudec debug: running spu decoder thread (%p) (pid == %i)\n",
162         p_spudec, getpid());
163
164     /*
165      * Initialize thread and free configuration
166      */
167     p_spudec->b_error = InitThread( p_spudec );
168
169     p_spudec->b_run = 1;
170
171     /*
172      * Main loop - it is not executed if an error occured during
173      * initialization
174      */
175     vlc_mutex_lock( &p_spudec->fifo.data_lock );
176     while( (!p_spudec->b_die) && (!p_spudec->b_error) )
177     {
178         /* Trash all received PES packets */
179         while( !DECODER_FIFO_ISEMPTY(p_spudec->fifo) )
180         {
181             input_NetlistFreePES( p_spudec->bit_stream.p_input, DECODER_FIFO_START(p_spudec->fifo) );
182             DECODER_FIFO_INCSTART( p_spudec->fifo );
183         }
184         /* Waiting for the input thread to put new PES packets in the fifo */
185         vlc_cond_wait( &p_spudec->fifo.data_wait, &p_spudec->fifo.data_lock );
186     }
187     vlc_mutex_unlock( &p_spudec->fifo.data_lock );
188
189     /*
190      * Error loop
191      */
192     if( p_spudec->b_error )
193     {
194         ErrorThread( p_spudec );
195     }
196
197     p_spudec->b_run = 0;
198
199     /* End of thread */
200     EndThread( p_spudec );
201 }
202
203 /*****************************************************************************
204  * ErrorThread: RunThread() error loop
205  *****************************************************************************
206  * This function is called when an error occured during thread main's loop. The
207  * thread can still receive feed, but must be ready to terminate as soon as
208  * possible.
209  *****************************************************************************/
210 static void ErrorThread( spudec_thread_t *p_spudec )
211 {
212     /* We take the lock, because we are going to read/write the start/end
213      * indexes of the decoder fifo */
214     vlc_mutex_lock( &p_spudec->fifo.data_lock );
215
216     /* Wait until a `die' order is sent */
217     while( !p_spudec->b_die )
218     {
219         /* Trash all received PES packets */
220         while( !DECODER_FIFO_ISEMPTY(p_spudec->fifo) )
221         {
222             input_NetlistFreePES( p_spudec->bit_stream.p_input, DECODER_FIFO_START(p_spudec->fifo) );
223             DECODER_FIFO_INCSTART( p_spudec->fifo );
224         }
225
226         /* Waiting for the input thread to put new PES packets in the fifo */
227         vlc_cond_wait( &p_spudec->fifo.data_wait, &p_spudec->fifo.data_lock );
228     }
229
230     /* We can release the lock before leaving */
231     vlc_mutex_unlock( &p_spudec->fifo.data_lock );
232 }
233
234 /*****************************************************************************
235  * EndThread: thread destruction
236  *****************************************************************************
237  * This function is called when the thread ends after a sucessfull
238  * initialization.
239  *****************************************************************************/
240 static void EndThread( spudec_thread_t *p_spudec )
241 {
242     intf_DbgMsg( "spudec debug: destroying spu decoder thread %p\n", p_spudec );
243     free( p_spudec );
244     intf_DbgMsg( "spudec debug: spu decoder thread %p destroyed\n", p_spudec);
245 }