]> git.sesse.net Git - vlc/blob - src/input/input_ext-intf.c
d820a4a68b238317308de35b75ac8d02def01f55
[vlc] / src / input / input_ext-intf.c
1 /*****************************************************************************
2  * input_ext-intf.c: services to the interface
3  *****************************************************************************
4  * Copyright (C) 1998-2001 VideoLAN
5  * $Id: input_ext-intf.c,v 1.39 2002/07/23 00:39:17 sam Exp $
6  *
7  * Authors: Christophe Massiot <massiot@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  * 
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <string.h>                                    /* memcpy(), memset() */
28 #include <sys/types.h>                                              /* off_t */
29
30 #include <vlc/vlc.h>
31
32 #include "stream_control.h"
33 #include "input_ext-dec.h"
34 #include "input_ext-intf.h"
35 #include "input_ext-plugins.h"
36
37 /*****************************************************************************
38  * input_SetStatus: change the reading status
39  *****************************************************************************/
40 void __input_SetStatus( vlc_object_t * p_this, int i_mode )
41 {
42     input_thread_t *p_input;
43
44     p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_PARENT );
45
46     if( p_input == NULL )
47     {
48         msg_Err( p_this, "no input found" );
49         return;
50     }
51
52     vlc_mutex_lock( &p_input->stream.stream_lock );
53
54     switch( i_mode )
55     {
56     case INPUT_STATUS_END:
57         p_input->stream.i_new_status = PLAYING_S;
58         p_input->b_eof = 1;
59         msg_Dbg( p_input, "end of stream" );
60         break;
61
62     case INPUT_STATUS_PLAY:
63         p_input->stream.i_new_status = PLAYING_S;
64         msg_Dbg( p_input, "playing at normal rate" );
65         break;
66
67     case INPUT_STATUS_PAUSE:
68         /* XXX: we don't need to check i_status, because input_clock.c
69          * does it for us */
70         p_input->stream.i_new_status = PAUSE_S;
71         msg_Dbg( p_input, "toggling pause" );
72         break;
73
74     case INPUT_STATUS_FASTER:
75         /* If we are already going too fast, go back to default rate */
76         if( p_input->stream.control.i_rate * 8 <= DEFAULT_RATE )
77         {
78             p_input->stream.i_new_status = PLAYING_S;
79             msg_Dbg( p_input, "playing at normal rate" );
80         }
81         else
82         {
83             p_input->stream.i_new_status = FORWARD_S;
84
85             if( p_input->stream.control.i_rate < DEFAULT_RATE
86                     && p_input->stream.control.i_status == FORWARD_S )
87             {
88                 p_input->stream.i_new_rate =
89                                     p_input->stream.control.i_rate / 2;
90             }
91             else
92             {
93                 p_input->stream.i_new_rate = DEFAULT_RATE / 2;
94             }
95             msg_Dbg( p_input, "playing at %i:1 fast forward",
96                      DEFAULT_RATE / p_input->stream.i_new_rate );
97         }
98         break;
99
100     case INPUT_STATUS_SLOWER:
101         /* If we are already going too slow, go back to default rate */
102         if( p_input->stream.control.i_rate >= 8 * DEFAULT_RATE )
103         {
104             p_input->stream.i_new_status = PLAYING_S;
105             msg_Dbg( p_input, "playing at normal rate" );
106         }
107         else
108         {
109             p_input->stream.i_new_status = FORWARD_S;
110
111             if( p_input->stream.control.i_rate > DEFAULT_RATE
112                     && p_input->stream.control.i_status == FORWARD_S )
113             {
114                 p_input->stream.i_new_rate =
115                                     p_input->stream.control.i_rate * 2;
116             }
117             else
118             {
119                 p_input->stream.i_new_rate = DEFAULT_RATE * 2;
120             }
121             msg_Dbg( p_input, "playing at 1:%i slow motion",
122                       p_input->stream.i_new_rate / DEFAULT_RATE );
123         }
124         break;
125
126     default:
127         break;
128     }
129
130     vlc_cond_signal( &p_input->stream.stream_wait );
131     vlc_mutex_unlock( &p_input->stream.stream_lock );
132
133     vlc_object_release( p_input );
134 }
135
136 /*****************************************************************************
137  * input_Seek: changes the stream postion
138  *****************************************************************************/
139 void __input_Seek( vlc_object_t * p_this, off_t i_position, int i_whence )
140 {
141     input_thread_t *p_input;
142
143     char psz_time1[OFFSETTOTIME_MAX_SIZE];
144     char psz_time2[OFFSETTOTIME_MAX_SIZE];
145
146     p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_PARENT );
147
148     if( p_input == NULL )
149     {
150         msg_Err( p_this, "no input found" );
151         return;
152     }
153
154     vlc_mutex_lock( &p_input->stream.stream_lock );
155
156 #define A p_input->stream.p_selected_area
157     switch( i_whence & 0x30 )
158     {
159         case INPUT_SEEK_SECONDS:
160             i_position *= (off_t)50 * p_input->stream.i_mux_rate;
161             break;
162
163         case INPUT_SEEK_PERCENT:
164             i_position = A->i_size * i_position / (off_t)100;
165             break;
166
167         case INPUT_SEEK_BYTES:
168         default:
169             break;
170     }
171
172     switch( i_whence & 0x03 )
173     {
174         case INPUT_SEEK_CUR:
175             A->i_seek = A->i_tell + i_position;
176             break;
177
178         case INPUT_SEEK_END:
179             A->i_seek = A->i_size + i_position;
180             break;
181
182         case INPUT_SEEK_SET:
183         default:
184             A->i_seek = i_position;
185             break;
186     }
187
188     if( A->i_seek < 0 )
189     {
190         A->i_seek = 0;
191     }
192     else if( A->i_seek > A->i_size )
193     {
194         A->i_seek = A->i_size;
195     }
196
197     msg_Dbg( p_input, "seeking position %lld/%lld (%s/%s)",
198              A->i_seek, A->i_size,
199              input_OffsetToTime( p_input, psz_time1, i_position ),
200              input_OffsetToTime( p_input, psz_time2, A->i_size ) );
201 #undef A
202
203     vlc_cond_signal( &p_input->stream.stream_wait );
204     vlc_mutex_unlock( &p_input->stream.stream_lock );
205
206     vlc_object_release( p_input );
207 }
208
209 /*****************************************************************************
210  * input_Tell: requests the stream postion
211  *****************************************************************************/
212 void __input_Tell( vlc_object_t * p_this, stream_position_t * p_position )
213 {
214     input_thread_t *p_input;
215
216     p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_PARENT );
217
218     if( p_input == NULL )
219     {
220         p_position->i_tell = 0;
221         p_position->i_size = 0;
222         p_position->i_mux_rate = 0;
223         msg_Err( p_this, "no input found" );
224         return;
225     }
226
227     vlc_mutex_lock( &p_input->stream.stream_lock );
228
229 #define A p_input->stream.p_selected_area
230     p_position->i_tell = A->i_tell;
231     p_position->i_size = A->i_size;
232     p_position->i_mux_rate = p_input->stream.i_mux_rate;
233 #undef A
234
235     vlc_mutex_unlock( &p_input->stream.stream_lock );
236     vlc_object_release( p_input );
237 }
238
239 /*****************************************************************************
240  * input_OffsetToTime : converts an off_t value to a time indicator, using
241  *                      mux_rate
242  *****************************************************************************
243  * BEWARE : this function assumes that you already own the lock on
244  * p_input->stream.stream_lock
245  *****************************************************************************/
246 char * input_OffsetToTime( input_thread_t * p_input, char * psz_buffer,
247                            off_t i_offset )
248 {
249     mtime_t         i_seconds;
250
251     if( p_input->stream.i_mux_rate )
252     {
253         i_seconds = i_offset / 50 / p_input->stream.i_mux_rate;
254         snprintf( psz_buffer, OFFSETTOTIME_MAX_SIZE, "%d:%02d:%02d",
255                  (int) (i_seconds / (60 * 60)),
256                  (int) (i_seconds / 60 % 60),
257                  (int) (i_seconds % 60) );
258         return( psz_buffer );
259     }
260     else
261     {
262         /* Divide by zero is not my friend. */
263         sprintf( psz_buffer, "-:--:--" );
264         return( psz_buffer );
265     }
266 }
267
268 /*****************************************************************************
269  * input_DumpStream: dumps the contents of a stream descriptor
270  *****************************************************************************
271  * BEWARE : this function assumes that you already own the lock on
272  * p_input->stream.stream_lock
273  *****************************************************************************/
274 void input_DumpStream( input_thread_t * p_input )
275 {
276     int         i, j;
277     char        psz_time1[OFFSETTOTIME_MAX_SIZE];
278     char        psz_time2[OFFSETTOTIME_MAX_SIZE];
279
280 #define S   p_input->stream
281     msg_Dbg( p_input, "dumping stream ID 0x%x [OK:%d/D:%d]", S.i_stream_id,
282              S.c_packets_read, S.c_packets_trashed );
283     if( S.b_seekable )
284         msg_Dbg( p_input, "seekable stream, position: %lld/%lld (%s/%s)",
285                  S.p_selected_area->i_tell, S.p_selected_area->i_size,
286                  input_OffsetToTime( p_input, psz_time1,
287                                      S.p_selected_area->i_tell ),
288                  input_OffsetToTime( p_input, psz_time2,
289                                      S.p_selected_area->i_size ) );
290     else
291         msg_Dbg( p_input, "pace %scontrolled", S.b_pace_control ? "" : "un-" );
292 #undef S
293     for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
294     {
295 #define P   p_input->stream.pp_programs[i]
296         msg_Dbg( p_input, "dumping program 0x%x, version %d (%s)",
297                  P->i_number, P->i_version,
298                  P->b_is_ok ? "complete" : "partial" );
299 #undef P
300         for( j = 0; j < p_input->stream.pp_programs[i]->i_es_number; j++ )
301         {
302 #define ES  p_input->stream.pp_programs[i]->pp_es[j]
303             msg_Dbg( p_input,
304                      "ES 0x%x, stream 0x%x, fourcc `%4.4s', %s [OK:%d/ERR:%d]",
305                      ES->i_id, ES->i_stream_id, (char*)&ES->i_fourcc,
306                      ES->p_decoder_fifo != NULL ? "selected" : "not selected",
307                      ES->c_packets, ES->c_invalid_packets );
308 #undef ES
309         }
310     }
311 }
312
313 /*****************************************************************************
314  * input_ToggleES: answers to a user request with calls to (Un)SelectES
315  *****************************************************************************
316  * Useful since the interface plugins know p_es.
317  * It only works for audio & spu ( to be sure nothing nasty is being done ).
318  * b_select is a boolean to know if we have to select or unselect ES
319  *****************************************************************************/
320 int input_ToggleES( input_thread_t * p_input, es_descriptor_t * p_es,
321                     vlc_bool_t b_select )
322 {
323     vlc_mutex_lock( &p_input->stream.stream_lock );
324
325     if( p_es != NULL )
326     {
327         if( b_select )
328         {
329             p_input->stream.p_newly_selected_es = p_es;
330         }
331         else
332         {
333             p_input->stream.p_removed_es = p_es;
334         }
335     }
336
337     vlc_mutex_unlock( &p_input->stream.stream_lock );
338
339     return 0;
340 }
341
342 /****************************************************************************
343  * input_ChangeArea: interface request an area change
344  ****************************************************************************/
345 int input_ChangeArea( input_thread_t * p_input, input_area_t * p_area )
346 {
347     vlc_mutex_lock( &p_input->stream.stream_lock );
348
349     p_input->stream.p_new_area = p_area;
350
351     vlc_mutex_unlock( &p_input->stream.stream_lock );
352
353     return 0;
354 }
355
356 /****************************************************************************
357  * input_ChangeProgram: interface request a program change
358  ****************************************************************************/
359 int input_ChangeProgram( input_thread_t * p_input, u16 i_program_number )
360 {
361     pgrm_descriptor_t *       p_program;
362     
363     vlc_mutex_lock( &p_input->stream.stream_lock );
364
365     p_program = input_FindProgram( p_input, i_program_number );
366
367     if ( p_program == NULL )
368     {
369         msg_Err( p_input, "could not find selected program" );
370         return -1;
371     }
372
373     p_input->stream.p_new_program = p_program;
374     
375     vlc_mutex_unlock( &p_input->stream.stream_lock );
376
377     return 0;
378 }
379
380 /****************************************************************************
381  * input_ToggleGrayscale: change to grayscale or color output
382  ****************************************************************************/
383 int input_ToggleGrayscale( input_thread_t * p_input )
384 {
385     /* No need to warn the input thread since only the decoders and outputs
386      * worry about it. */
387     vlc_mutex_lock( &p_input->stream.control.control_lock );
388     p_input->stream.control.b_grayscale =
389                     !p_input->stream.control.b_grayscale;
390
391     msg_Dbg( p_input, "changing to %s output",
392              p_input->stream.control.b_grayscale ? "grayscale" : "color" );
393
394     vlc_mutex_unlock( &p_input->stream.control.control_lock );
395
396     return 0;
397 }
398
399 /****************************************************************************
400  * input_ToggleMute: activate/deactivate mute mode
401  ****************************************************************************/
402 int input_ToggleMute( input_thread_t * p_input )
403 {
404     /* We need to feed the decoders with 0, and only input can do that, so
405      * pass the message to the input thread. */
406     vlc_mutex_lock( &p_input->stream.stream_lock );
407     p_input->stream.b_new_mute = !p_input->stream.control.b_mute;
408
409     msg_Dbg( p_input, "%s mute mode",
410              p_input->stream.control.b_mute ? "activating" : "deactivating" );
411
412     vlc_mutex_unlock( &p_input->stream.stream_lock );
413
414     return 0;
415 }
416
417 /****************************************************************************
418  * input_SetSMP: change the number of video decoder threads
419  ****************************************************************************/
420 int input_SetSMP( input_thread_t * p_input, int i_smp )
421 {
422     /* No need to warn the input thread since only the decoders
423      * worry about it. */
424     vlc_mutex_lock( &p_input->stream.control.control_lock );
425     p_input->stream.control.i_smp = i_smp;
426     vlc_mutex_unlock( &p_input->stream.control.control_lock );
427
428     return 0;
429 }
430