]> git.sesse.net Git - vlc/blob - modules/codec/theora.c
* modules/codec/theora.c, configure.ac.in, modules/codec/Modules.am: new
[vlc] / modules / codec / theora.c
1 /*****************************************************************************
2  * theora.c: theora decoder module making use of libtheora.
3  *****************************************************************************
4  * Copyright (C) 1999-2001 VideoLAN
5  * $Id: theora.c,v 1.1 2002/11/20 14:09:57 gbazin Exp $
6  *
7  * Authors: Gildas Bazin <gbazin@netcourrier.com>
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 <vlc/vlc.h>
28 #include <vlc/vout.h>
29 #include <vlc/input.h>
30 #include <vlc/decoder.h>
31
32 #include <stdlib.h>                                      /* malloc(), free() */
33 #include <string.h>                                    /* memcpy(), memset() */
34
35 #include <ogg/ogg.h>
36
37 #include <theora/theora.h>
38
39 /*****************************************************************************
40  * dec_thread_t : theora decoder thread descriptor
41  *****************************************************************************/
42 typedef struct dec_thread_t
43 {
44     /*
45      * Thread properties
46      */
47     vlc_thread_t        thread_id;                /* id for thread functions */
48
49     /*
50      * Theora properties
51      */
52     theora_info      ti;                        /* theora bitstream settings */
53     theora_state     td;                   /* theora bitstream user comments */
54
55     /*
56      * Input properties
57      */
58     decoder_fifo_t         *p_fifo;            /* stores the PES stream data */
59     pes_packet_t           *p_pes;            /* current PES we are decoding */
60
61     /*
62      * Output properties
63      */
64     vout_thread_t *p_vout;
65
66 } dec_thread_t;
67
68 /*****************************************************************************
69  * Local prototypes
70  *****************************************************************************/
71 static int  OpenDecoder  ( vlc_object_t * );
72 static int  RunDecoder   ( decoder_fifo_t * );
73 static void CloseDecoder ( dec_thread_t * );
74
75 static void DecodePacket ( dec_thread_t * );
76 static int  GetOggPacket ( dec_thread_t *, ogg_packet *, mtime_t * );
77
78 static void theora_CopyPicture( dec_thread_t *, picture_t *, yuv_buffer * );
79 static vout_thread_t *theora_SpawnVout( dec_thread_t *, int, int, int, int );
80 /*****************************************************************************
81  * Module descriptor
82  *****************************************************************************/
83 vlc_module_begin();
84     set_description( _("Theora decoder module") );
85     set_capability( "decoder", 100 );
86     set_callbacks( OpenDecoder, NULL );
87     add_shortcut( "theora" );
88 vlc_module_end();
89
90 /*****************************************************************************
91  * OpenDecoder: probe the decoder and return score
92  *****************************************************************************/
93 static int OpenDecoder( vlc_object_t *p_this )
94 {
95     decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
96
97     if( p_fifo->i_fourcc != VLC_FOURCC('t','h','e','o') )
98     {
99         return VLC_EGENERIC;
100     }
101
102     p_fifo->pf_run = RunDecoder;
103     return VLC_SUCCESS;
104 }
105 /*****************************************************************************
106  * RunDecoder: the theora decoder
107  *****************************************************************************/
108 static int RunDecoder( decoder_fifo_t *p_fifo )
109 {
110     dec_thread_t *p_dec;
111     ogg_packet oggpacket;
112     int i_chroma, i_aspect;
113     mtime_t i_pts;
114
115     /* Allocate the memory needed to store the thread's structure */
116     if( (p_dec = (dec_thread_t *)malloc (sizeof(dec_thread_t)) )
117             == NULL)
118     {
119         msg_Err( p_fifo, "out of memory" );
120         goto error;
121     }
122
123     /* Initialize the thread properties */
124     memset( p_dec, 0, sizeof(dec_thread_t) );
125     p_dec->p_fifo = p_fifo;
126     p_dec->p_pes  = NULL;
127
128     /* Take care of the initial Theora header */
129     if( GetOggPacket( p_dec, &oggpacket, &i_pts ) != VLC_SUCCESS )
130         goto error;
131
132     oggpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */
133     if( theora_decode_header( &p_dec->ti, &oggpacket ) < 0 )
134     {
135         msg_Err( p_dec->p_fifo, "This bitstream does not contain Theora "
136                  "video data");
137         goto error;
138     }
139
140     /* Initialize decoder */
141     theora_decode_init( &p_dec->td, &p_dec->ti );
142     msg_Dbg( p_dec->p_fifo, "%dx%d %.02f fps video",
143              p_dec->ti.width, p_dec->ti.height,
144              (double)p_dec->ti.fps_numerator/p_dec->ti.fps_denominator);
145
146     /* Initialize video output */
147     if( p_dec->ti.aspect_denominator )
148         i_aspect = VOUT_ASPECT_FACTOR * p_dec->ti.aspect_numerator /
149                     p_dec->ti.aspect_denominator;
150     else
151         i_aspect = VOUT_ASPECT_FACTOR * p_dec->ti.width / p_dec->ti.height;
152
153     i_chroma = VLC_FOURCC('Y','V','1','2');
154
155     p_dec->p_vout = theora_SpawnVout( p_dec, p_dec->ti.width, p_dec->ti.height,
156                                       i_aspect, i_chroma );
157
158     /* theora decoder thread's main loop */
159     while( (!p_dec->p_fifo->b_die) && (!p_dec->p_fifo->b_error) )
160     {
161         DecodePacket( p_dec );
162     }
163
164     /* If b_error is set, the theora decoder thread enters the error loop */
165     if( p_dec->p_fifo->b_error )
166     {
167         DecoderError( p_dec->p_fifo );
168     }
169
170     /* End of the theora decoder thread */
171     CloseDecoder( p_dec );
172
173     return 0;
174
175  error:
176     DecoderError( p_fifo );
177     if( p_dec )
178     {
179         if( p_dec->p_fifo )
180             p_dec->p_fifo->b_error = 1;
181
182         /* End of the theora decoder thread */
183         CloseDecoder( p_dec );
184     }
185
186     return -1;
187 }
188
189 /*****************************************************************************
190  * DecodePacket: decodes a Theora packet.
191  *****************************************************************************/
192 static void DecodePacket( dec_thread_t *p_dec )
193 {
194     ogg_packet oggpacket;
195     picture_t *p_pic;
196     mtime_t i_pts;
197     yuv_buffer yuv;
198
199     if( GetOggPacket( p_dec, &oggpacket, &i_pts ) != VLC_SUCCESS )
200     {
201         /* This should mean an eos */
202         return;
203     }
204
205     theora_decode_packetin( &p_dec->td, &oggpacket );
206
207     /* Decode */
208     theora_decode_YUVout( &p_dec->td, &yuv );
209
210     /* Get a new picture */
211     while( !(p_pic = vout_CreatePicture( p_dec->p_vout, 0, 0, 0 ) ) )
212     {
213         if( p_dec->p_fifo->b_die || p_dec->p_fifo->b_error )
214         {
215             return;
216         }
217         msleep( VOUT_OUTMEM_SLEEP );
218     }
219     if( !p_pic )
220         return;
221
222     theora_CopyPicture( p_dec, p_pic, &yuv );
223
224     vout_DatePicture( p_dec->p_vout, p_pic, i_pts );
225     vout_DisplayPicture( p_dec->p_vout, p_pic );
226 }
227
228 /*****************************************************************************
229  * GetOggPacket: get the following theora packet from the stream and send back
230  *               the result in an ogg packet (for easy decoding by libtheora).
231  *****************************************************************************
232  * Returns VLC_EGENERIC in case of eof.
233  *****************************************************************************/
234 static int GetOggPacket( dec_thread_t *p_dec, ogg_packet *p_oggpacket,
235                          mtime_t *p_pts )
236 {
237     if( p_dec->p_pes ) input_DeletePES( p_dec->p_fifo->p_packets_mgt,
238                                         p_dec->p_pes );
239
240     input_ExtractPES( p_dec->p_fifo, &p_dec->p_pes );
241     if( !p_dec->p_pes ) return VLC_EGENERIC;
242
243     p_oggpacket->packet = p_dec->p_pes->p_first->p_payload_start;
244     p_oggpacket->bytes = p_dec->p_pes->i_pes_size;
245     p_oggpacket->granulepos = p_dec->p_pes->i_dts;
246     p_oggpacket->b_o_s = 0;
247     p_oggpacket->e_o_s = 0;
248     p_oggpacket->packetno = 0;
249
250     *p_pts = p_dec->p_pes->i_pts;
251
252     return VLC_SUCCESS;
253 }
254
255 /*****************************************************************************
256  * CloseDecoder: theora decoder destruction
257  *****************************************************************************/
258 static void CloseDecoder( dec_thread_t * p_dec )
259 {
260
261     if( p_dec )
262     {
263         if( p_dec->p_pes )
264             input_DeletePES( p_dec->p_fifo->p_packets_mgt, p_dec->p_pes );
265
266         if( p_dec->p_vout )
267         {
268             vlc_object_detach( p_dec->p_vout );
269             vout_DestroyThread( p_dec->p_vout );
270         }
271
272         free( p_dec );
273     }
274 }
275
276 /*****************************************************************************
277  * theora_SpawnVout: creates a new video output
278  *****************************************************************************/
279 static vout_thread_t *theora_SpawnVout( dec_thread_t *p_dec,
280                                         int i_width,
281                                         int i_height,
282                                         int i_aspect,
283                                         int i_chroma )
284 {
285     vout_thread_t *p_vout;
286
287     if( !i_width || !i_height )
288         return NULL;
289
290     if( !i_chroma )
291         return NULL;
292
293     /* Spawn a video output if there is none. First we look for our children,
294      * then we look for any other vout that might be available. */
295     p_vout = vlc_object_find( p_dec->p_fifo, VLC_OBJECT_VOUT,
296                                               FIND_CHILD );
297     if( !p_vout )
298     {
299         p_vout = vlc_object_find( p_dec->p_fifo, VLC_OBJECT_VOUT,
300                                                   FIND_ANYWHERE );
301     }
302
303     if( p_vout )
304     {
305         if( p_vout->render.i_width != i_width
306             || p_vout->render.i_height != i_height
307             || p_vout->render.i_chroma != i_chroma
308             || p_vout->render.i_aspect != i_aspect )
309         {
310             /* We are not interested in this format, close this vout */
311             vlc_object_detach( p_vout );
312             vlc_object_release( p_vout );
313             vout_DestroyThread( p_vout );
314             p_vout = NULL;
315         }
316         else
317         {
318             /* This video output is cool! Hijack it. */
319             vlc_object_detach( p_vout );
320             vlc_object_attach( p_vout, p_dec->p_fifo );
321             vlc_object_release( p_vout );
322         }
323     }
324
325     if( p_vout == NULL )
326     {
327         msg_Dbg( p_dec->p_fifo, "no vout present, spawning one" );
328
329         p_vout = vout_CreateThread( p_dec->p_fifo,
330                                     i_width, i_height,
331                                     i_chroma, i_aspect );
332     }
333
334     return( p_vout );
335 }
336
337 /*****************************************************************************
338  * theora_CopyPicture: copy a picture from theora internal buffers to a
339  *                     picture_t structure.
340  *****************************************************************************/
341 static void theora_CopyPicture( dec_thread_t *p_dec, picture_t *p_pic,
342                                 yuv_buffer *yuv )
343 {
344     int i_plane, i_line, i_width, i_dst_stride, i_src_stride;
345     u8  *p_dst, *p_src;
346
347     for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
348     {
349         p_dst = p_pic->p[i_plane].p_pixels;
350         p_src = i_plane ? (i_plane - 1 ? yuv->v : yuv->u ) : yuv->y;
351         i_width = p_pic->p[i_plane].i_visible_pitch;
352         i_dst_stride = p_pic->p[i_plane].i_pitch;
353         i_src_stride = i_plane ? yuv->uv_stride : yuv->y_stride;
354
355         for( i_line = 0; i_line < p_pic->p[i_plane].i_lines; i_line++ )
356         {
357             p_dec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, i_width );
358             p_src += i_src_stride;
359             p_dst += i_dst_stride;
360         }
361     }
362 }