]> git.sesse.net Git - vlc/blob - src/spu_decoder/spu_decoder.c
* spu_decoder/spu_decoder.c :
[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  * ?? 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"                    /* ?? 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.i_byte = p_spudec->bit_stream.p_ts->i_payload_start;
145     vlc_mutex_unlock( &p_spudec->fifo.data_lock );
146
147     /* Mark thread as running and return */
148     intf_DbgMsg( "spudec debug: InitThread(%p) succeeded\n", p_spudec );
149     return( 0 );
150 }
151
152 /*******************************************************************************
153  * RunThread: spu decoder thread
154  *******************************************************************************
155  * spu decoder thread. This function does only return when the thread is
156  * terminated. 
157  *******************************************************************************/
158 static void RunThread( spudec_thread_t *p_spudec )
159 {
160     intf_DbgMsg("spudec debug: running spu decoder thread (%p) (pid == %i)\n",
161         p_spudec, getpid());
162
163     /*
164      * Initialize thread and free configuration
165      */
166     p_spudec->b_error = InitThread( p_spudec );
167
168     p_spudec->b_run = 1;
169
170     /*
171      * Main loop - it is not executed if an error occured during
172      * initialization
173      */
174     vlc_mutex_lock( &p_spudec->fifo.data_lock );
175     while( (!p_spudec->b_die) && (!p_spudec->b_error) )
176     {
177         /* Trash all received PES packets */
178         while( !DECODER_FIFO_ISEMPTY(p_spudec->fifo) )
179         {
180             input_NetlistFreePES( p_spudec->bit_stream.p_input, DECODER_FIFO_START(p_spudec->fifo) );
181             DECODER_FIFO_INCSTART( p_spudec->fifo );
182         }
183         /* Waiting for the input thread to put new PES packets in the fifo */
184         vlc_cond_wait( &p_spudec->fifo.data_wait, &p_spudec->fifo.data_lock );
185     }
186     vlc_mutex_unlock( &p_spudec->fifo.data_lock );
187
188     /*
189      * Error loop
190      */
191     if( p_spudec->b_error )
192     {
193         ErrorThread( p_spudec );
194     }
195
196     p_spudec->b_run = 0;
197
198     /* End of thread */
199     EndThread( p_spudec );
200 }
201
202 /*******************************************************************************
203  * ErrorThread: RunThread() error loop
204  *******************************************************************************
205  * This function is called when an error occured during thread main's loop. The
206  * thread can still receive feed, but must be ready to terminate as soon as
207  * possible.
208  *******************************************************************************/
209 static void ErrorThread( spudec_thread_t *p_spudec )
210 {
211     /* We take the lock, because we are going to read/write the start/end
212      * indexes of the decoder fifo */
213     vlc_mutex_lock( &p_spudec->fifo.data_lock );
214
215     /* Wait until a `die' order is sent */
216     while( !p_spudec->b_die )
217     {
218         /* Trash all received PES packets */
219         while( !DECODER_FIFO_ISEMPTY(p_spudec->fifo) )
220         {
221             input_NetlistFreePES( p_spudec->bit_stream.p_input, DECODER_FIFO_START(p_spudec->fifo) );
222             DECODER_FIFO_INCSTART( p_spudec->fifo );
223         }
224
225         /* Waiting for the input thread to put new PES packets in the fifo */
226         vlc_cond_wait( &p_spudec->fifo.data_wait, &p_spudec->fifo.data_lock );
227     }
228
229     /* We can release the lock before leaving */
230     vlc_mutex_unlock( &p_spudec->fifo.data_lock );
231 }
232
233 /*******************************************************************************
234  * EndThread: thread destruction
235  *******************************************************************************
236  * This function is called when the thread ends after a sucessfull 
237  * initialization.
238  *******************************************************************************/
239 static void EndThread( spudec_thread_t *p_spudec )
240 {
241     intf_DbgMsg( "spudec debug: destroying spu decoder thread %p\n", p_spudec );
242     free( p_spudec );
243     intf_DbgMsg( "spudec debug: spu decoder thread %p destroyed\n", p_spudec);
244 }