OSDN Git Service

Fix Previous Bad commit for Cyanders Chapter Markers
[handbrake-jp/handbrake-jp-git.git] / 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 /**********************************************************************
12  * hb_libmpeg2_t
13  **********************************************************************
14  * A convenient libmpeg wrapper, used both here and in scan.c
15  *********************************************************************/
16 struct hb_libmpeg2_s
17 {
18     mpeg2dec_t         * libmpeg2;
19     const mpeg2_info_t * info;
20     int                  width;
21     int                  height;
22     int                  rate;
23     int                  got_iframe;
24     int                  look_for_break;
25     int64_t              last_pts;
26 };
27
28 /**********************************************************************
29  * hb_libmpeg2_init
30  **********************************************************************
31  * 
32  *********************************************************************/
33 hb_libmpeg2_t * hb_libmpeg2_init()
34 {
35     hb_libmpeg2_t * m = calloc( sizeof( hb_libmpeg2_t ), 1 );
36     
37     m->libmpeg2 = mpeg2_init();
38     m->info     = mpeg2_info( m->libmpeg2 );
39     m->last_pts = -1;
40     m->look_for_break = 0;
41
42     return m;
43 }
44
45 /**********************************************************************
46  * hb_libmpeg2_decode
47  **********************************************************************
48  * 
49  *********************************************************************/
50 int hb_libmpeg2_decode( hb_libmpeg2_t * m, hb_buffer_t * buf_es,
51                         hb_list_t * list_raw )
52 {
53     mpeg2_state_t   state;
54     hb_buffer_t   * buf;
55     uint8_t       * data;
56     int             chap_break = 0;
57
58     /* Feed libmpeg2 */
59     if( buf_es->start > -1 )
60     {
61         mpeg2_tag_picture( m->libmpeg2, buf_es->start >> 32,
62                            buf_es->start & 0xFFFFFFFF );
63     }
64     mpeg2_buffer( m->libmpeg2, buf_es->data,
65                   buf_es->data + buf_es->size );
66
67     for( ;; )
68     {
69         state = mpeg2_parse( m->libmpeg2 );
70         if( state == STATE_BUFFER )
71         {
72             /* Require some more data */
73             break;
74         }
75         else if( state == STATE_SEQUENCE )
76         {
77             if( !( m->width && m->height && m->rate ) )
78             {
79                 m->width  = m->info->sequence->width;
80                 m->height = m->info->sequence->height;
81                 m->rate   = m->info->sequence->frame_period;
82                 
83                 if( m->rate == 900900 )
84                 {
85                     /* 29.97 fps. 3:2 pulldown might, or might not be
86                        used. I can't find a way to know, so we always
87                        output 23.976 */
88                     m->rate = 1126125;
89                 }
90             }
91         }
92         else if( state == STATE_GOP && m->look_for_break == 2)
93         {
94             printf("MPEG2: Group of pictures found, searching for I-Frame\n");
95             m->look_for_break = 1;
96         }
97         else if( ( state == STATE_SLICE || state == STATE_END ) &&
98                  m->info->display_fbuf )
99         {
100             if( ( m->info->display_picture->flags &
101                   PIC_MASK_CODING_TYPE ) == PIC_FLAG_CODING_TYPE_I )
102             {
103                 m->got_iframe = 1;
104                 
105                 // If we are looking for a break, insert the chapter break on an I-Frame
106                 if( m->look_for_break == 1 )
107                 {
108                     printf("MPEG2: I-Frame Found\n");
109                     m->look_for_break = 0;
110                     chap_break = 1;
111                 }
112             }
113
114             if( m->got_iframe )
115             {
116                 buf  = hb_buffer_init( m->width * m->height * 3 / 2 );
117                 data = buf->data;
118
119                 // Was a good break point found?
120                 if( chap_break )
121                 {
122                     printf("MPEG2: Chapter Break Inserted\n");
123                     chap_break = 0;
124                     buf->new_chap = 1;
125                 }
126
127                 memcpy( data, m->info->display_fbuf->buf[0],
128                         m->width * m->height );
129                 data += m->width * m->height;
130                 memcpy( data, m->info->display_fbuf->buf[1],
131                         m->width * m->height / 4 );
132                 data += m->width * m->height / 4;
133                 memcpy( data, m->info->display_fbuf->buf[2],
134                         m->width * m->height / 4 );
135
136                 if( m->info->display_picture->flags & PIC_FLAG_TAGS )
137                 {
138                     buf->start =
139                         ( (uint64_t) m->info->display_picture->tag << 32 ) |
140                         ( (uint64_t) m->info->display_picture->tag2 );
141                 }
142                 else if( m->last_pts > -1 )
143                 {
144                     /* For some reason nb_fields is sometimes 1 while it
145                        should be 2 */
146                     buf->start = m->last_pts +
147                         MAX( 2, m->info->display_picture->nb_fields ) *
148                         m->info->sequence->frame_period / 600;
149                 }
150                 else
151                 {
152                     buf->start = -1;
153                 }
154                 m->last_pts = buf->start;
155
156                 hb_list_add( list_raw, buf );
157             }
158         }
159         else if( state == STATE_INVALID )
160         {
161             mpeg2_reset( m->libmpeg2, 0 );
162         }
163     }
164     return 1;
165 }
166
167 /**********************************************************************
168  * hb_libmpeg2_info
169  **********************************************************************
170  * 
171  *********************************************************************/
172 void hb_libmpeg2_info( hb_libmpeg2_t * m, int * width, int * height,
173                         int * rate )
174 {
175     *width  = m->width;
176     *height = m->height;
177     *rate   = m->rate;
178 }
179
180 /**********************************************************************
181  * hb_libmpeg2_close
182  **********************************************************************
183  * 
184  *********************************************************************/
185 void hb_libmpeg2_close( hb_libmpeg2_t ** _m )
186 {
187     hb_libmpeg2_t * m = *_m;
188
189     mpeg2_close( m->libmpeg2 );
190
191     free( m );
192     *_m = NULL;
193 }
194
195 /**********************************************************************
196  * The decmpeg2 work object
197  **********************************************************************
198  * 
199  *********************************************************************/
200 struct hb_work_private_s
201 {
202     hb_libmpeg2_t * libmpeg2;
203     hb_list_t     * list;
204 };
205
206 /**********************************************************************
207  * hb_work_decmpeg2_init
208  **********************************************************************
209  * 
210  *********************************************************************/
211 int decmpeg2Init( hb_work_object_t * w, hb_job_t * job )
212 {
213     hb_work_private_t * pv;
214     
215     pv              = calloc( 1, sizeof( hb_work_private_t ) );
216     w->private_data = pv;
217     
218     pv->libmpeg2 = hb_libmpeg2_init();
219     pv->list     = hb_list_init();
220
221     return 0;
222 }
223
224 /**********************************************************************
225  * Work
226  **********************************************************************
227  * 
228  *********************************************************************/
229 int decmpeg2Work( hb_work_object_t * w, hb_buffer_t ** buf_in,
230                    hb_buffer_t ** buf_out )
231 {
232     hb_work_private_t * pv = w->private_data;
233     hb_buffer_t * buf, * last = NULL;
234
235     // The reader found a chapter break, consume it completely, and remove it from the
236     // stream. We need to shift it.
237     if( (*buf_in)->new_chap )
238     {
239         printf("MPEG2: Chapter Break Cell Found, searching for GOP\n");
240         pv->libmpeg2->look_for_break = 2;
241         (*buf_in)->new_chap = 0;
242     }
243
244     hb_libmpeg2_decode( pv->libmpeg2, *buf_in, pv->list );
245
246     *buf_out = NULL;
247     while( ( buf = hb_list_item( pv->list, 0 ) ) )
248     {
249         hb_list_rem( pv->list, buf );
250         if( last )
251         {
252             last->next = buf;
253             last       = buf;
254         }
255         else
256         {
257             *buf_out = buf;
258             last     = buf;
259         }
260     }
261
262     return HB_WORK_OK;
263 }
264
265 /**********************************************************************
266  * Close
267  **********************************************************************
268  * 
269  *********************************************************************/
270 void decmpeg2Close( hb_work_object_t * w )
271 {
272     hb_work_private_t * pv = w->private_data;
273     hb_list_close( &pv->list );
274     hb_libmpeg2_close( &pv->libmpeg2 );
275     free( pv );
276 }
277
278 hb_work_object_t hb_decmpeg2 =
279 {
280     WORK_DECMPEG2,
281     "MPEG-2 decoder (libmpeg2)",
282     decmpeg2Init,
283     decmpeg2Work,
284     decmpeg2Close
285 };
286