]> git.sesse.net Git - vlc/blob - modules/codec/libmpeg2.c
* modules/codec/libmpeg2.c: added code to handle 3:2 pulldown.
[vlc] / modules / codec / libmpeg2.c
1 /*****************************************************************************\r
2  * libmpeg2.c: mpeg2 video decoder module making use of libmpeg2.\r
3  *****************************************************************************\r
4  * Copyright (C) 1999-2001 VideoLAN\r
5  * $Id: libmpeg2.c,v 1.5 2003/03/26 22:56:39 gbazin Exp $\r
6  *\r
7  * Authors: Gildas Bazin <gbazin@netcourrier.com>\r
8  *\r
9  * This program is free software; you can redistribute it and/or modify\r
10  * it under the terms of the GNU General Public License as published by\r
11  * the Free Software Foundation; either version 2 of the License, or\r
12  * (at your option) any later version.\r
13  * \r
14  * This program is distributed in the hope that it will be useful,\r
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
17  * GNU General Public License for more details.\r
18  *\r
19  * You should have received a copy of the GNU General Public License\r
20  * along with this program; if not, write to the Free Software\r
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.\r
22  *****************************************************************************/\r
23 \r
24 /*****************************************************************************\r
25  * Preamble\r
26  *****************************************************************************/\r
27 #include <vlc/vlc.h>\r
28 #include <vlc/vout.h>\r
29 #include <vlc/input.h>\r
30 #include <vlc/decoder.h>\r
31 \r
32 #include <stdlib.h>                                      /* malloc(), free() */\r
33 #include <string.h>                                    /* memcpy(), memset() */\r
34 \r
35 #include <mpeg2dec/mpeg2.h>\r
36 \r
37 /* Aspect ratio (ISO/IEC 13818-2 section 6.3.3, table 6-3) */\r
38 #define AR_SQUARE_PICTURE       1                           /* square pixels */\r
39 #define AR_3_4_PICTURE          2                        /* 3:4 picture (TV) */\r
40 #define AR_16_9_PICTURE         3              /* 16:9 picture (wide screen) */\r
41 #define AR_221_1_PICTURE        4                  /* 2.21:1 picture (movie) */\r
42 \r
43 /*****************************************************************************\r
44  * dec_thread_t : libmpeg2 decoder thread descriptor\r
45  *****************************************************************************/\r
46 typedef struct dec_thread_t\r
47 {\r
48     /*\r
49      * libmpeg2 properties\r
50      */\r
51     mpeg2dec_t          *p_mpeg2dec;\r
52     const mpeg2_info_t  *p_info;\r
53 \r
54     /*\r
55      * Input properties\r
56      */\r
57     decoder_fifo_t   *p_fifo;                  /* stores the PES stream data */\r
58     pes_packet_t     *p_pes;                  /* current PES we are decoding */\r
59     mtime_t          i_pts;\r
60     mtime_t          i_previous_pts;\r
61     mtime_t          i_current_pts;\r
62     mtime_t          i_period_remainder;\r
63 \r
64     /*\r
65      * Output properties\r
66      */\r
67     vout_thread_t *p_vout;\r
68 \r
69 } dec_thread_t;\r
70 \r
71 /*****************************************************************************\r
72  * Local prototypes\r
73  *****************************************************************************/\r
74 static int  OpenDecoder  ( vlc_object_t * );\r
75 static int  RunDecoder   ( decoder_fifo_t * );\r
76 static void CloseDecoder ( dec_thread_t * );\r
77 \r
78 /*****************************************************************************\r
79  * Module descriptor\r
80  *****************************************************************************/\r
81 vlc_module_begin();\r
82     set_description( _("libmpeg2 decoder module") );\r
83     set_capability( "decoder", 40 );\r
84     set_callbacks( OpenDecoder, NULL );\r
85     add_shortcut( "libmpeg2" );\r
86 vlc_module_end();\r
87 \r
88 /*****************************************************************************\r
89  * OpenDecoder: probe the decoder and return score\r
90  *****************************************************************************/\r
91 static int OpenDecoder( vlc_object_t *p_this )\r
92 {\r
93     decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;\r
94 \r
95     if( p_fifo->i_fourcc != VLC_FOURCC('m','p','g','v') )\r
96     {\r
97         return VLC_EGENERIC;\r
98     }\r
99 \r
100     p_fifo->pf_run = RunDecoder;\r
101     return VLC_SUCCESS;\r
102 }\r
103 /*****************************************************************************\r
104  * RunDecoder: the libmpeg2 decoder\r
105  *****************************************************************************/\r
106 static int RunDecoder( decoder_fifo_t *p_fifo )\r
107 {\r
108     dec_thread_t    *p_dec;\r
109     data_packet_t   *p_data = NULL;\r
110     mpeg2_state_t   state;\r
111     picture_t       *p_pic;\r
112     int             i_aspect, i_chroma;\r
113 \r
114     /* Allocate the memory needed to store the thread's structure */\r
115     if( (p_dec = (dec_thread_t *)malloc (sizeof(dec_thread_t)) )\r
116         == NULL)\r
117     {\r
118         msg_Err( p_fifo, "out of memory" );\r
119         goto error;\r
120     }\r
121 \r
122     /* Initialize the thread properties */\r
123     memset( p_dec, 0, sizeof(dec_thread_t) );\r
124     p_dec->p_fifo     = p_fifo;\r
125     p_dec->p_pes      = NULL;\r
126     p_dec->p_vout     = NULL;\r
127     p_dec->p_mpeg2dec = NULL;\r
128     p_dec->p_info     = NULL;\r
129     p_dec->i_pts      = mdate() + DEFAULT_PTS_DELAY;\r
130     p_dec->i_current_pts  = 0;\r
131     p_dec->i_previous_pts = 0;\r
132     p_dec->i_period_remainder = 0;\r
133 \r
134     /* Initialize decoder */\r
135     p_dec->p_mpeg2dec = mpeg2_init();\r
136     if( p_dec->p_mpeg2dec == NULL)\r
137         goto error;\r
138 \r
139     p_dec->p_info = mpeg2_info( p_dec->p_mpeg2dec );\r
140 \r
141     /* libmpeg2 decoder thread's main loop */\r
142     while( (!p_dec->p_fifo->b_die) && (!p_dec->p_fifo->b_error) )\r
143     {\r
144         state = mpeg2_parse( p_dec->p_mpeg2dec );\r
145 \r
146         switch( state )\r
147         {\r
148         case STATE_BUFFER:\r
149             /* Feed libmpeg2 a data packet at a time */\r
150             if( p_data == NULL )\r
151             {\r
152                 /* Get the next PES */\r
153                 if( p_dec->p_pes )\r
154                     input_DeletePES( p_dec->p_fifo->p_packets_mgt,\r
155                                      p_dec->p_pes );\r
156 \r
157                 input_ExtractPES( p_dec->p_fifo, &p_dec->p_pes );\r
158                 if( !p_dec->p_pes )\r
159                 {\r
160                     p_dec->p_fifo->b_error = 1;\r
161                     break;\r
162                 }\r
163 \r
164                 if( p_dec->p_pes->i_pts )\r
165                 {\r
166                     mpeg2_pts( p_dec->p_mpeg2dec,\r
167                                (uint32_t)p_dec->p_pes->i_pts );\r
168                     p_dec->i_previous_pts = p_dec->i_current_pts;\r
169                     p_dec->i_current_pts = p_dec->p_pes->i_pts;\r
170                 }\r
171                 p_data = p_dec->p_pes->p_first;\r
172             }\r
173 \r
174             if( p_data != NULL )\r
175             {\r
176                 mpeg2_buffer( p_dec->p_mpeg2dec,\r
177                               p_data->p_payload_start,\r
178                               p_data->p_payload_end );\r
179 \r
180                 p_data = p_data->p_next;\r
181             }\r
182             break;\r
183 \r
184         case STATE_SEQUENCE:\r
185             /* Initialize video output */\r
186 \r
187             /* Check whether the input gives a particular aspect ratio */\r
188             if( p_dec->p_fifo->p_demux_data\r
189                 && ( *(int*)(p_dec->p_fifo->p_demux_data) & 0x7 ) )\r
190             {\r
191                 i_aspect = *(int*)(p_dec->p_fifo->p_demux_data);\r
192                 switch( i_aspect )\r
193                 {\r
194                 case AR_3_4_PICTURE:\r
195                     i_aspect = VOUT_ASPECT_FACTOR * 4 / 3;\r
196                     break;\r
197                 case AR_16_9_PICTURE:\r
198                     i_aspect = VOUT_ASPECT_FACTOR * 16 / 9;\r
199                     break;\r
200                 case AR_221_1_PICTURE:\r
201                     i_aspect = VOUT_ASPECT_FACTOR * 221 / 100;\r
202                     break;\r
203                 case AR_SQUARE_PICTURE:\r
204                 default:\r
205                     i_aspect = VOUT_ASPECT_FACTOR *\r
206                                    p_dec->p_info->sequence->width /\r
207                                    p_dec->p_info->sequence->height;\r
208                     break;\r
209                 }\r
210             }\r
211             else\r
212             {\r
213                 /* Use the value provided in the MPEG sequence header */\r
214                 i_aspect = ((uint64_t)p_dec->p_info->sequence->width) *\r
215                     p_dec->p_info->sequence->pixel_width * VOUT_ASPECT_FACTOR /\r
216                     p_dec->p_info->sequence->height /\r
217                     p_dec->p_info->sequence->pixel_height;\r
218             }\r
219 \r
220             i_chroma = VLC_FOURCC('Y','V','1','2');\r
221 \r
222             p_dec->p_vout = vout_Request( p_dec->p_fifo, p_dec->p_vout,\r
223                                           p_dec->p_info->sequence->width,\r
224                                           p_dec->p_info->sequence->height,\r
225                                           i_chroma, i_aspect );\r
226             break;\r
227 \r
228         case STATE_PICTURE:\r
229         {\r
230             uint8_t *buf[3];\r
231 \r
232             /* Get a new picture */\r
233             while( !(p_pic = vout_CreatePicture( p_dec->p_vout, 0, 0, 0 ) ) )\r
234             {\r
235                 if( p_dec->p_fifo->b_die || p_dec->p_fifo->b_error )\r
236                     break;\r
237 \r
238                 msleep( VOUT_OUTMEM_SLEEP );\r
239             }\r
240             if( p_pic == NULL )\r
241                 break;\r
242 \r
243             buf[0] = p_pic->p[0].p_pixels;\r
244             buf[1] = p_pic->p[1].p_pixels;\r
245             buf[2] = p_pic->p[2].p_pixels;\r
246             mpeg2_set_buf( p_dec->p_mpeg2dec, buf, p_pic );\r
247 \r
248             /* Store the date for the picture */\r
249             if( p_dec->p_info->current_picture->flags & PIC_FLAG_PTS )\r
250             {\r
251                 p_pic->date = ( p_dec->p_info->current_picture->pts ==\r
252                                 (uint32_t)p_dec->i_current_pts ) ?\r
253                               p_dec->i_current_pts : p_dec->i_previous_pts;\r
254             }\r
255         }\r
256         break;\r
257 \r
258         case STATE_END:\r
259         case STATE_SLICE:\r
260             if( p_dec->p_info->display_fbuf\r
261                 && p_dec->p_info->display_fbuf->id )\r
262             {\r
263                 p_pic = (picture_t *)p_dec->p_info->display_fbuf->id;\r
264 \r
265                 /* Date the new picture */\r
266                 if( p_dec->p_info->display_picture->flags & PIC_FLAG_PTS )\r
267                 {\r
268                     p_dec->i_pts = p_pic->date;\r
269                     p_dec->i_period_remainder = 0;\r
270                 }\r
271                 else\r
272                 {\r
273                     p_dec->i_pts += ( (p_dec->p_info->sequence->frame_period +\r
274                                        p_dec->i_period_remainder) / 27 );\r
275                     p_dec->i_period_remainder =\r
276                         p_dec->p_info->sequence->frame_period +\r
277                         p_dec->i_period_remainder -\r
278                         ( p_dec->p_info->sequence->frame_period +\r
279                           p_dec->i_period_remainder ) / 27 * 27;\r
280                 }\r
281                 vout_DatePicture( p_dec->p_vout, p_pic, p_dec->i_pts );\r
282 \r
283                 vout_DisplayPicture( p_dec->p_vout, p_pic );\r
284 \r
285                 /* Handle pulldown by adding some delay to the pts of the next\r
286                  * picture. */\r
287                 if( p_dec->p_info->display_picture->nb_fields > 2 )\r
288                 {\r
289                     int i_repeat_fields =\r
290                         p_dec->p_info->display_picture->nb_fields - 2;\r
291 \r
292                     p_dec->i_pts += ( (p_dec->p_info->sequence->frame_period +\r
293                                        p_dec->i_period_remainder)\r
294                                       / 27 / 2 * i_repeat_fields );\r
295                     p_dec->i_period_remainder =\r
296                         p_dec->p_info->sequence->frame_period +\r
297                         p_dec->i_period_remainder -\r
298                         ( p_dec->p_info->sequence->frame_period +\r
299                           p_dec->i_period_remainder ) / 27 / 2 * 27 * 2;\r
300                 }\r
301             }\r
302             break;\r
303 \r
304         default:\r
305             break;\r
306         }\r
307     }\r
308 \r
309     /* If b_error is set, the libmpeg2 decoder thread enters the error loop */\r
310     if( p_dec->p_fifo->b_error )\r
311     {\r
312         DecoderError( p_dec->p_fifo );\r
313     }\r
314 \r
315     /* End of the libmpeg2 decoder thread */\r
316     CloseDecoder( p_dec );\r
317 \r
318     return 0;\r
319 \r
320  error:\r
321     DecoderError( p_fifo );\r
322     if( p_dec )\r
323     {\r
324         if( p_dec->p_fifo )\r
325             p_dec->p_fifo->b_error = 1;\r
326 \r
327         /* End of the libmpeg2 decoder thread */\r
328         CloseDecoder( p_dec );\r
329     }\r
330 \r
331     return -1;\r
332 }\r
333 \r
334 /*****************************************************************************\r
335  * CloseDecoder: libmpeg2 decoder destruction\r
336  *****************************************************************************/\r
337 static void CloseDecoder( dec_thread_t * p_dec )\r
338 {\r
339     if( p_dec )\r
340     {\r
341         if( p_dec->p_pes )\r
342             input_DeletePES( p_dec->p_fifo->p_packets_mgt, p_dec->p_pes );\r
343 \r
344         vout_Request( p_dec->p_fifo, p_dec->p_vout, 0, 0, 0, 0 );\r
345 \r
346         if( p_dec->p_mpeg2dec ) mpeg2_close( p_dec->p_mpeg2dec );\r
347 \r
348         free( p_dec );\r
349     }\r
350 }\r