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