]> git.sesse.net Git - vlc/blob - modules/demux/dirac.c
mediacodec: don't loop in GetOutput
[vlc] / modules / demux / dirac.c
1 /*****************************************************************************
2  * dirac.c : Dirac Video demuxer
3  *****************************************************************************
4  * Copyright (C) 2002-2008 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: David Flynn <davidf@rd.bbc.co.uk>
8  * Based on vc1.c by: Laurent Aimar <fenrir@via.ecp.fr>
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU Lesser General Public License as published by
12  * the Free Software Foundation; either version 2.1 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this program; if not, write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_demux.h>
36 #include <vlc_codec.h>
37
38 #define DEMUX_CFG_PREFIX "dirac-"
39
40 #define DEMUX_DTSOFFSET "dts-offset"
41 #define DEMUX_DTSOFFSET_TEXT N_("Value to adjust dts by")
42 #define DEMUX_DTSOFFSET_LONGTEXT DEMUX_DTSOFFSET_TEXT
43
44 /*****************************************************************************
45  * Module descriptor
46  *****************************************************************************/
47 static int  Open ( vlc_object_t * );
48 static void Close( vlc_object_t * );
49
50 vlc_module_begin();
51     set_shortname( "Dirac");
52     set_category( CAT_INPUT );
53     set_subcategory( SUBCAT_INPUT_DEMUX );
54     set_description( N_("Dirac video demuxer" ) );
55     set_capability( "demux", 50 );
56     add_integer( DEMUX_CFG_PREFIX DEMUX_DTSOFFSET, 0,
57                  DEMUX_DTSOFFSET_TEXT, DEMUX_DTSOFFSET_LONGTEXT, false )
58     set_callbacks( Open, Close );
59     add_shortcut( "dirac" )
60 vlc_module_end();
61
62 /*****************************************************************************
63  * Local prototypes
64  *****************************************************************************/
65 struct demux_sys_t
66 {
67     mtime_t i_dts;
68     mtime_t i_dtsoffset;
69     mtime_t i_pts_offset_lowtide;
70     es_out_id_t *p_es;
71
72     enum {
73         /* demuxer states, do not reorder (++ is used) */
74         DIRAC_DEMUX_DISCONT = 0, /* signal a discontinuity to packetizer */
75         DIRAC_DEMUX_FIRST, /* provide an origin timestamp for the packetizer */
76         DIRAC_DEMUX_STEADY, /* normal operation */
77     } i_state;
78
79     decoder_t *p_packetizer;
80 };
81
82 static int Demux( demux_t * );
83 static int Control( demux_t *, int, va_list );
84
85 #define DIRAC_PACKET_SIZE 4096
86
87 /*****************************************************************************
88  * Open: initializes demux structures
89  *****************************************************************************/
90 static int Open( vlc_object_t * p_this )
91 {
92     demux_t     *p_demux = (demux_t*)p_this;
93     demux_sys_t *p_sys;
94     const uint8_t *p_peek;
95     es_format_t fmt;
96
97     if( stream_Peek( p_demux->s, &p_peek, 5 ) < 5 ) return VLC_EGENERIC;
98
99     if( p_peek[0] != 'B' || p_peek[1] != 'B' ||
100         p_peek[2] != 'C' || p_peek[3] != 'D') /* start of ParseInfo */
101     {
102         if( !p_demux->b_force ) return VLC_EGENERIC;
103
104         msg_Err( p_demux, "This doesn't look like a Dirac stream (incorrect parsecode)" );
105         msg_Warn( p_demux, "continuing anyway" );
106     }
107
108     p_demux->pf_demux = Demux;
109     p_demux->pf_control = Control;
110     p_demux->p_sys = p_sys = calloc( 1, sizeof( demux_sys_t ) );
111     if( !p_sys ) return VLC_ENOMEM;
112
113     p_sys->i_pts_offset_lowtide = INT64_MAX;
114     p_sys->i_state = DIRAC_DEMUX_FIRST;
115
116     p_sys->i_dtsoffset = var_CreateGetInteger( p_demux, DEMUX_CFG_PREFIX DEMUX_DTSOFFSET );
117
118     /* Load the packetizer */
119     es_format_Init( &fmt, VIDEO_ES, VLC_CODEC_DIRAC );
120     p_sys->p_packetizer = demux_PacketizerNew( p_demux, &fmt, "dirac" );
121     if( !p_sys->p_packetizer )
122     {
123         free( p_sys );
124         return VLC_EGENERIC;
125     }
126
127     return VLC_SUCCESS;
128 }
129
130 /*****************************************************************************
131  * Close: frees unused data
132  *****************************************************************************/
133 static void Close( vlc_object_t * p_this )
134 {
135     demux_t     *p_demux = (demux_t*)p_this;
136     demux_sys_t *p_sys = p_demux->p_sys;
137
138     demux_PacketizerDestroy( p_sys->p_packetizer );
139
140     if( p_sys->i_pts_offset_lowtide < INT64_MAX &&
141         p_sys->i_pts_offset_lowtide > 0 )
142     {
143         msg_Warn( p_demux, "For all packets seen, pts-dts (%"PRId64") could be reduced to 0",
144                   p_sys->i_pts_offset_lowtide );
145     }
146     free( p_sys );
147 }
148
149 /*****************************************************************************
150  * Demux: reads and demuxes data packets
151  *****************************************************************************
152  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
153  *****************************************************************************/
154 static int Demux( demux_t *p_demux)
155 {
156     demux_sys_t *p_sys = p_demux->p_sys;
157     block_t *p_block_in, *p_block_out;
158
159     if( p_sys->i_state == DIRAC_DEMUX_DISCONT )
160     {
161         p_sys->i_state++;
162         p_block_in = block_Alloc( 128 );
163         if( p_block_in )
164         {
165             p_block_in->i_flags = BLOCK_FLAG_DISCONTINUITY | BLOCK_FLAG_CORRUPTED;
166         }
167     }
168     else
169     {
170         p_block_in = stream_Block( p_demux->s, DIRAC_PACKET_SIZE );
171         if( !p_block_in )
172         {
173             return 0;
174         }
175         if ( p_sys->i_state == DIRAC_DEMUX_FIRST)
176         {
177             p_sys->i_state++;
178             /* by default, timestamps are invalid.
179              * Except when we need an anchor point */
180             p_block_in->i_dts = VLC_TS_0;
181         }
182     }
183
184     while( (p_block_out = p_sys->p_packetizer->pf_packetize( p_sys->p_packetizer, &p_block_in )) )
185     {
186         while( p_block_out )
187         {
188             block_t *p_next = p_block_out->p_next;
189             p_block_out->p_next = NULL;
190
191             if( p_sys->p_es == NULL )
192                 p_sys->p_es = es_out_Add( p_demux->out, &p_sys->p_packetizer->fmt_out);
193
194             p_block_out->i_dts += p_sys->i_dtsoffset;
195             p_sys->i_dts = p_block_out->i_dts;
196
197             /* track low watermark for pts_offset -- can be used to show
198              * when it is too large */
199             mtime_t i_delay = p_block_out->i_pts - p_block_out->i_dts;
200             if( p_sys->i_pts_offset_lowtide > i_delay )
201             {
202                 p_sys->i_pts_offset_lowtide = i_delay;
203             }
204
205             es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block_out->i_dts );
206             es_out_Send( p_demux->out, p_sys->p_es, p_block_out );
207
208             p_block_out = p_next;
209         }
210     }
211     return 1;
212 }
213
214 /*****************************************************************************
215  * Control:
216  *****************************************************************************/
217 static int Control( demux_t *p_demux, int i_query, va_list args )
218 {
219     demux_sys_t *p_sys  = p_demux->p_sys;
220     if( DEMUX_GET_TIME == i_query )
221     {
222         int64_t *pi64 = (int64_t*)va_arg( args, int64_t * );
223         *pi64 = p_sys->i_dts;
224         return VLC_SUCCESS;
225     }
226     else if( DEMUX_GET_FPS == i_query )
227     {
228         if( !p_sys->p_packetizer->fmt_out.video.i_frame_rate )
229         {
230             return VLC_EGENERIC;
231         }
232         double *pd = (double*)va_arg( args, double * );
233         *pd = (float) p_sys->p_packetizer->fmt_out.video.i_frame_rate
234             / p_sys->p_packetizer->fmt_out.video.i_frame_rate_base;
235         return VLC_SUCCESS;
236     }
237     else
238     {
239         if( DEMUX_SET_POSITION == i_query || DEMUX_SET_TIME == i_query )
240         {
241             p_sys->i_state = DIRAC_DEMUX_DISCONT;
242         }
243         return demux_vaControlHelper( p_demux->s, 0, -1, 0, 1, i_query, args );
244     }
245 }
246