OSDN Git Service

- Add mpeg2 "Standard Target Decoder" clock recovery to the low level mpeg stream...
[handbrake-jp/handbrake-jp-git.git] / libhb / demuxmpeg.c
1 /* $Id: demuxmpeg.c,v 1.4 2004/10/19 23:11:36 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 /* Basic MPEG demuxer, only works with DVDs (2048 bytes packets) */
10
11 int hb_demux_ps( hb_buffer_t * buf_ps, hb_list_t * list_es )
12 {
13     hb_buffer_t * buf_es;
14     int           pos = 0;
15     int64_t       scr;
16
17 #define d (buf_ps->data)
18
19     /* pack_header */
20     if( d[pos] != 0 || d[pos+1] != 0 ||
21         d[pos+2] != 0x1 || d[pos+3] != 0xBA )
22     {
23         hb_log( "hb_demux_ps: not a PS packet (%02x%02x%02x%02x)",
24                 d[pos], d[pos+1], d[pos+2], d[pos+3] );
25         return 0;
26     }
27     pos += 4;                    /* pack_start_code */
28     /* extract the system clock reference (scr) */
29     scr = ((uint64_t)(d[pos] & 0x38) << 27) |
30           ((uint64_t)(d[pos] & 0x03) << 28) |
31           ((uint64_t)(d[pos+1]) << 20) |
32           ((uint64_t)(d[pos+2] >> 3) << 15) |
33           ((uint64_t)(d[pos+2] & 3) << 13) |
34           ((uint64_t)(d[pos+3]) << 5) |
35           (d[pos+4] >> 3);
36     pos += 9;                    /* pack_header */
37     pos += 1 + ( d[pos] & 0x7 ); /* stuffing bytes */
38
39     /* system_header */
40     if( d[pos] == 0 && d[pos+1] == 0 &&
41         d[pos+2] == 0x1 && d[pos+3] == 0xBB )
42     {
43         int header_length;
44
45         pos           += 4; /* system_header_start_code */
46         header_length  = ( d[pos] << 8 ) + d[pos+1];
47         pos           += 2 + header_length;
48     }
49
50     /* pes */
51     while( pos + 6 < buf_ps->size &&
52            d[pos] == 0 && d[pos+1] == 0 && d[pos+2] == 0x1 )
53     {
54         int      id;
55         int      pes_packet_length;
56         int      pes_packet_end;
57         int      pes_header_d_length;
58         int      pes_header_end;
59         int      has_pts;
60         int64_t  pts = -1;
61
62         pos               += 3;               /* packet_start_code_prefix */
63         id           = d[pos];
64         pos               += 1;
65
66         pes_packet_length  = ( d[pos] << 8 ) + d[pos+1];
67         pos               += 2;               /* pes_packet_length */
68         pes_packet_end     = pos + pes_packet_length;
69
70         if( id != 0xE0 && id != 0xBD &&
71             ( id & 0xC0 ) != 0xC0  )
72         {
73             /* Not interesting */
74             pos = pes_packet_end;
75             continue;
76         }
77
78         has_pts             = ( ( d[pos+1] >> 6 ) & 0x2 ) ? 1 : 0;
79         pos               += 2;               /* Required headers */
80
81         pes_header_d_length  = d[pos];
82         pos                    += 1;
83         pes_header_end          = pos + pes_header_d_length;
84
85         if( has_pts )
86         {
87             pts = ( ( ( (uint64_t) d[pos] >> 1 ) & 0x7 ) << 30 ) +
88                   ( d[pos+1] << 22 ) +
89                   ( ( d[pos+2] >> 1 ) << 15 ) +
90                   ( d[pos+3] << 7 ) +
91                   ( d[pos+4] >> 1 );
92         }
93
94         pos = pes_header_end;
95
96         if( id == 0xBD )
97         {
98             id |= ( d[pos] << 8 );
99             if( ( id & 0xF0FF ) == 0x80BD ) /* A52 */
100             {
101                 pos += 4;
102             }
103             else if( ( id & 0xE0FF ) == 0x20BD || /* SPU */
104                      ( id & 0xF0FF ) == 0xA0BD )  /* LPCM */
105             {
106                 pos += 1;
107             }
108         }
109
110         /* Sanity check */
111         if( pos >= pes_packet_end )
112         {
113             pos = pes_packet_end;
114             continue;
115         }
116
117         /* Here we hit we ES payload */
118         buf_es = hb_buffer_init( pes_packet_end - pos );
119
120         buf_es->id       = id;
121         buf_es->start    = pts;
122         buf_es->stop     = scr;
123         if (id == 0xE0) {
124             // Consume a chapter break, and apply it to the ES.
125             buf_es->new_chap = buf_ps->new_chap;
126             buf_ps->new_chap = 0;
127         }
128         memcpy( buf_es->data, d + pos, pes_packet_end - pos );
129
130         hb_list_add( list_es, buf_es );
131
132         pos = pes_packet_end;
133     }
134
135 #undef d
136
137     return 1;
138 }