]> granicus.if.org Git - handbrake/blob - libhb/decmpeg2.c
Prevents a bus error at scan time with DVDs that have a weird cell structure. Much...
[handbrake] / libhb / decmpeg2.c
1 /* $Id: decmpeg2.c,v 1.12 2005/03/03 16:30:42 titer Exp $
2
3    This file is part of the HandBrake source code.
4    Homepage: <http://handbrake.m0k.org/>.
5    It may be used under the terms of the GNU General Public License. */
6
7 #include "hb.h"
8
9 #include "mpeg2dec/mpeg2.h"
10
11 /* Cadence tracking */
12 #ifndef PIC_FLAG_REPEAT_FIRST_FIELD
13 #define PIC_FLAG_REPEAT_FIRST_FIELD 256
14 #endif
15 #define TOP_FIRST PIC_FLAG_TOP_FIELD_FIRST
16 #define PROGRESSIVE PIC_FLAG_PROGRESSIVE_FRAME
17 #define COMPOSITE PIC_FLAG_COMPOSITE_DISPLAY
18 #define SKIP PIC_FLAG_SKIP
19 #define TAGS PIC_FLAG_TAGS
20 #define REPEAT_FIRST PIC_FLAG_REPEAT_FIRST_FIELD
21 #define COMPOSITE_MASK PIC_MASK_COMPOSITE_DISPLAY
22 #define TB 8
23 #define BT 16
24 #define BT_PROG 32
25 #define BTB_PROG 64
26 #define TB_PROG 128
27 #define TBT_PROG 256
28 int cadence[6];
29 int flag = 0;
30
31 /**********************************************************************
32  * hb_libmpeg2_t
33  **********************************************************************
34  * A convenient libmpeg wrapper, used both here and in scan.c
35  *********************************************************************/
36 struct hb_libmpeg2_s
37 {
38     mpeg2dec_t         * libmpeg2;
39     const mpeg2_info_t * info;
40     int                  width;
41     int                  height;
42     int                  rate;
43     int                  aspect_ratio;
44     int                  got_iframe;
45     int                  look_for_break;
46     int64_t              last_pts;
47 };
48
49 /**********************************************************************
50  * hb_libmpeg2_init
51  **********************************************************************
52  * 
53  *********************************************************************/
54 hb_libmpeg2_t * hb_libmpeg2_init()
55 {
56     hb_libmpeg2_t * m = calloc( sizeof( hb_libmpeg2_t ), 1 );
57     
58     m->libmpeg2 = mpeg2_init();
59     m->info     = mpeg2_info( m->libmpeg2 );
60     m->last_pts = -1;
61     m->look_for_break = 0;
62
63     return m;
64 }
65
66 /**********************************************************************
67  * hb_libmpeg2_decode
68  **********************************************************************
69  * 
70  *********************************************************************/
71 int hb_libmpeg2_decode( hb_libmpeg2_t * m, hb_buffer_t * buf_es,
72                         hb_list_t * list_raw )
73 {
74     mpeg2_state_t   state;
75     hb_buffer_t   * buf;
76     uint8_t       * data;
77     int             chap_break = 0;
78
79     /* Feed libmpeg2 */
80     if( buf_es->start > -1 )
81     {
82         mpeg2_tag_picture( m->libmpeg2, buf_es->start >> 32,
83                            buf_es->start & 0xFFFFFFFF );
84     }
85     mpeg2_buffer( m->libmpeg2, buf_es->data,
86                   buf_es->data + buf_es->size );
87
88     for( ;; )
89     {
90         state = mpeg2_parse( m->libmpeg2 );
91         if( state == STATE_BUFFER )
92         {
93             /* Require some more data */
94             break;
95         }
96         else if( state == STATE_SEQUENCE )
97         {
98             if( !( m->width && m->height && m->rate ) )
99             {
100                 m->width  = m->info->sequence->width;
101                 m->height = m->info->sequence->height;
102                 m->rate   = m->info->sequence->frame_period;
103             }
104             if ( m->aspect_ratio <= 0 )
105             {
106               // We can parse out the aspect ratio from the Sequence Start Header data in buf_es->data
107               
108               // Make sure we have the correct data in the buffer
109               if ((buf_es->data[0] == 0x00) && (buf_es->data[1] == 0x00) && (buf_es->data[2] == 0x01) && (buf_es->data[3] == 0xb3))
110               {
111                 unsigned char ar_fr = buf_es->data[7];    // Top 4 bits == aspect ratio flag  - bottom 4 bits == rate flags
112                 switch ((ar_fr & 0xf0) >> 4)
113                 {
114                   case 2:
115                     m->aspect_ratio = HB_ASPECT_BASE * 4 / 3;   // 4:3
116                     break;
117                   case 3:
118                     m->aspect_ratio = HB_ASPECT_BASE * 16 / 9;  // 16:9
119                     break;
120                   default:
121                     hb_log("hb_libmpeg2_decode - STATE_SEQUENCE unexpected aspect ratio/frame rate 0x%x\n", ar_fr);
122                     break;
123                 }
124               } 
125             }
126         }
127         else if( state == STATE_GOP && m->look_for_break == 2)
128         {
129             printf("MPEG2: Group of pictures found, searching for I-Frame\n");
130             m->look_for_break = 1;
131         }
132         else if( ( state == STATE_SLICE || state == STATE_END ) &&
133                  m->info->display_fbuf )
134         {
135             if( ( m->info->display_picture->flags &
136                   PIC_MASK_CODING_TYPE ) == PIC_FLAG_CODING_TYPE_I )
137             {
138                 m->got_iframe = 1;
139                 
140                 // If we are looking for a break, insert the chapter break on an I-Frame
141                 if( m->look_for_break == 1 )
142                 {
143                     printf("MPEG2: I-Frame Found\n");
144                     m->look_for_break = 0;
145                     chap_break = 1;
146                 }
147             }
148
149             if( m->got_iframe )
150             {
151                 buf  = hb_buffer_init( m->width * m->height * 3 / 2 );
152                 data = buf->data;
153
154                 // Was a good break point found?
155                 if( chap_break )
156                 {
157                     printf("MPEG2: Chapter Break Inserted\n");
158                     chap_break = 0;
159                     buf->new_chap = 1;
160                 }
161
162                 memcpy( data, m->info->display_fbuf->buf[0],
163                         m->width * m->height );
164                 data += m->width * m->height;
165                 memcpy( data, m->info->display_fbuf->buf[1],
166                         m->width * m->height / 4 );
167                 data += m->width * m->height / 4;
168                 memcpy( data, m->info->display_fbuf->buf[2],
169                         m->width * m->height / 4 );
170
171                 if( m->info->display_picture->flags & PIC_FLAG_TAGS )
172                 {
173                     buf->start =
174                         ( (uint64_t) m->info->display_picture->tag << 32 ) |
175                         ( (uint64_t) m->info->display_picture->tag2 );
176                     /*
177                       * Add back in again to track PTS of MPEG2 frames
178                       * hb_log("MPEG2: Normal buf->start = %lld", buf->start);
179                     */
180                 }
181                 else if( m->last_pts > -1 )
182                 {
183                     /* For some reason nb_fields is sometimes 1 while it
184                        should be 2 */
185                     buf->start = m->last_pts +
186                         MAX( 2, m->info->display_picture->nb_fields ) *
187                         m->info->sequence->frame_period / 600;
188                 }
189                 else
190                 {
191                     buf->start = -1;
192                 }
193                 m->last_pts = buf->start;
194
195                 flag = m->info->display_picture->flags;
196                
197 /*  Uncomment this block to see frame-by-frame picture flags, as the video encodes.
198                hb_log("***** MPEG 2 Picture Info for PTS %lld *****", buf->start);
199                 if( flag & TOP_FIRST )
200                     hb_log("MPEG2 Flag: Top field first");
201                 if( flag & PROGRESSIVE )
202                     hb_log("MPEG2 Flag: Progressive");
203                 if( flag & COMPOSITE )
204                     hb_log("MPEG2 Flag: Composite");
205                 if( flag & SKIP )
206                     hb_log("MPEG2 Flag: Skip!");
207                 if( flag & TAGS )
208                     hb_log("MPEG2 Flag: TAGS");
209                 if(flag & REPEAT_FIRST )
210                     hb_log("MPEG2 Flag: Repeat first field");
211                 if( flag & COMPOSITE_MASK )
212                     hb_log("MPEG2 Flag: Composite mask");
213                 hb_log("fields: %d", m->info->display_picture->nb_fields);
214 */             
215                 /*  Rotate the cadence tracking. */
216                 cadence[5] = cadence[4];
217                 cadence[4] = cadence[3];
218                 cadence[3] = cadence[2];
219                 cadence[2] = cadence[1];
220                 cadence[1] = cadence[0];
221                
222                 if ( !(flag & PROGRESSIVE) && !(flag & TOP_FIRST) )
223                 {
224                     /* Not progressive, not top first...
225                        That means it's probably bottom
226                        first, 2 fields displayed.
227                     */
228                     //hb_log("MPEG2 Flag: Bottom field first, 2 fields displayed.");
229                     cadence[0] = BT;
230                 }
231                 else if ( !(flag & PROGRESSIVE) && (flag & TOP_FIRST) )
232                 {
233                     /* Not progressive, top is first,
234                        Two fields displayed.
235                     */
236                     //hb_log("MPEG2 Flag: Top field first, 2 fields displayed.");
237                     cadence[0] = TB;
238                 }
239                 else if ( (flag & PROGRESSIVE) && !(flag & TOP_FIRST) && !( flag & REPEAT_FIRST )  )
240                 {
241                     /* Progressive, but noting else.
242                        That means Bottom first,
243                        2 fields displayed.
244                     */
245                     //hb_log("MPEG2 Flag: Progressive. Bottom field first, 2 fields displayed.");
246                     cadence[0] = BT_PROG;
247                 }
248                 else if ( (flag & PROGRESSIVE) && !(flag & TOP_FIRST) && ( flag & REPEAT_FIRST )  )
249                 {
250                     /* Progressive, and repeat. .
251                        That means Bottom first,
252                        3 fields displayed.
253                     */
254                     //hb_log("MPEG2 Flag: Progressive repeat. Bottom field first, 3 fields displayed.");
255                     cadence[0] = BTB_PROG;
256                 }
257                 else if ( (flag & PROGRESSIVE) && (flag & TOP_FIRST) && !( flag & REPEAT_FIRST )  )
258                 {
259                     /* Progressive, top first.
260                        That means top first,
261                        2 fields displayed.
262                     */
263                     //hb_log("MPEG2 Flag: Progressive. Top field first, 2 fields displayed.");
264                     cadence[0] = TB_PROG;
265                 }
266                 else if ( (flag & PROGRESSIVE) && (flag & TOP_FIRST) && ( flag & REPEAT_FIRST )  )
267                 {
268                     /* Progressive, top, repeat.
269                        That means top first,
270                        3 fields displayed.
271                     */
272                     //hb_log("MPEG2 Flag: Progressive repeat. Top field first, 3 fields displayed.");
273                     cadence[0] = TBT_PROG;
274                 }
275                                                
276                 if ( (cadence[2] <= TB) && (cadence[1] <= TB) && (cadence[0] > TB) && (cadence[0]) && (cadence[1]) )
277                     hb_log("PTS %lld: Interlaced -> Progressive", buf->start);
278                 if ( (cadence[2] > TB) && (cadence[1] <= TB) && (cadence[0] <= TB) && (cadence[0]) && (cadence[1]) )
279                     hb_log("PTS %lld: Progressive -> Interlaced", buf->start);
280
281                 /* Store picture flags for later use by filters */
282                 buf->flags = m->info->display_picture->flags;
283                 
284                 hb_list_add( list_raw, buf );
285             }
286         }
287         else if( state == STATE_INVALID )
288         {
289             mpeg2_reset( m->libmpeg2, 0 );
290         }
291     }
292     return 1;
293 }
294
295 /**********************************************************************
296  * hb_libmpeg2_info
297  **********************************************************************
298  * 
299  *********************************************************************/
300 void hb_libmpeg2_info( hb_libmpeg2_t * m, int * width, int * height,
301                         int * rate, int *aspect_ratio )
302 {
303     *width  = m->width;
304     *height = m->height;
305     if (m->info->display_fbuf)
306     {
307         if( (m->info->display_picture->flags & PROGRESSIVE) && (m->height == 480) )
308         {
309             /* The frame is progressive and it's NTSC DVD height, so change its FPS to 23.976.
310                This might not be correct for the title. It's really just for scan.c's benefit.
311                Scan.c will reset the fps to 29.97, until a simple majority of the preview
312                frames report at 23.976.
313             */
314             //hb_log("Detecting NTSC Progressive Frame");
315             m->rate = 1126125;
316         }
317     }
318     *rate   = m->rate;
319     *aspect_ratio = m->aspect_ratio;
320 }
321
322 /**********************************************************************
323  * hb_libmpeg2_close
324  **********************************************************************
325  * 
326  *********************************************************************/
327 void hb_libmpeg2_close( hb_libmpeg2_t ** _m )
328 {
329     hb_libmpeg2_t * m = *_m;
330
331     mpeg2_close( m->libmpeg2 );
332
333     free( m );
334     *_m = NULL;
335 }
336
337 /**********************************************************************
338  * The decmpeg2 work object
339  **********************************************************************
340  * 
341  *********************************************************************/
342 struct hb_work_private_s
343 {
344     hb_libmpeg2_t * libmpeg2;
345     hb_list_t     * list;
346 };
347
348 /**********************************************************************
349  * hb_work_decmpeg2_init
350  **********************************************************************
351  * 
352  *********************************************************************/
353 int decmpeg2Init( hb_work_object_t * w, hb_job_t * job )
354 {
355     hb_work_private_t * pv;
356     
357     pv              = calloc( 1, sizeof( hb_work_private_t ) );
358     w->private_data = pv;
359     
360     pv->libmpeg2 = hb_libmpeg2_init();
361     pv->list     = hb_list_init();
362
363     return 0;
364 }
365
366 /**********************************************************************
367  * Work
368  **********************************************************************
369  * 
370  *********************************************************************/
371 int decmpeg2Work( hb_work_object_t * w, hb_buffer_t ** buf_in,
372                    hb_buffer_t ** buf_out )
373 {
374     hb_work_private_t * pv = w->private_data;
375     hb_buffer_t * buf, * last = NULL;
376
377     // The reader found a chapter break, consume it completely, and remove it from the
378     // stream. We need to shift it.
379     if( (*buf_in)->new_chap )
380     {
381         printf("MPEG2: Chapter Break Cell Found, searching for GOP\n");
382         pv->libmpeg2->look_for_break = 2;
383         (*buf_in)->new_chap = 0;
384     }
385
386     hb_libmpeg2_decode( pv->libmpeg2, *buf_in, pv->list );
387
388     *buf_out = NULL;
389     while( ( buf = hb_list_item( pv->list, 0 ) ) )
390     {
391         hb_list_rem( pv->list, buf );
392         if( last )
393         {
394             last->next = buf;
395             last       = buf;
396         }
397         else
398         {
399             *buf_out = buf;
400             last     = buf;
401         }
402     }
403
404     return HB_WORK_OK;
405 }
406
407 /**********************************************************************
408  * Close
409  **********************************************************************
410  * 
411  *********************************************************************/
412 void decmpeg2Close( hb_work_object_t * w )
413 {
414     hb_work_private_t * pv = w->private_data;
415     hb_list_close( &pv->list );
416     hb_libmpeg2_close( &pv->libmpeg2 );
417     free( pv );
418 }
419
420 hb_work_object_t hb_decmpeg2 =
421 {
422     WORK_DECMPEG2,
423     "MPEG-2 decoder (libmpeg2)",
424     decmpeg2Init,
425     decmpeg2Work,
426     decmpeg2Close
427 };
428