1 /*
2  *  scan_pack.c
3  *
4  *  Copyright (C) Thomas Oestreich - June 2001
5  *
6  *  This file is part of transcode, a video stream processing tool
7  *
8  *  transcode is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2, or (at your option)
11  *  any later version.
12  *
13  *  transcode is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with GNU Make; see the file COPYING.  If not, write to
20  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  */
23 
24 #include "transcode.h"
25 #include "ioaux.h"
26 #include "aux_pes.h"
27 #include "seqinfo.h"
28 #include "demuxer.h"
29 #include "packets.h"
30 
31 /* ------------------------------------------------------------
32  *
33  * auxiliary routines
34  *
35  * ------------------------------------------------------------*/
36 
37 static char *picture_structure_str[4] = {
38     "Invalid Picture Structure",
39     "Top field",
40     "Bottom field",
41     "Frame Picture"
42 };
43 
_cmp_32_bits(char * buf,long x)44 static int _cmp_32_bits(char *buf, long x)
45 {
46 
47     if(0) {
48 	tc_log_msg(__FILE__, "MAGIC: 0x%02lx 0x%02lx 0x%02lx 0x%02lx", (x >> 24) & 0xff, ((x >> 16) & 0xff), ((x >>  8) & 0xff), ((x      ) & 0xff));
49 	tc_log_msg(__FILE__, " FILE: 0x%02x 0x%02x 0x%02x 0x%02x", buf[0] & 0xff, buf[1] & 0xff, buf[2] & 0xff, buf[3] & 0xff);
50     }
51 
52     if ((buf[0]& 0xff) != ((x >> 24) & 0xff))
53 	return 0;
54     if ((buf[1]& 0xff) != ((x >> 16) & 0xff))
55 	return 0;
56     if ((buf[2] & 0xff)!= ((x >>  8) & 0xff))
57 	return 0;
58     if ((buf[3]& 0xff) != ((x      ) & 0xff))
59 	return 0;
60 
61   // OK found it
62   return 1;
63 }
64 
65 
_cmp_16_bits(char * buf,long x)66 static int _cmp_16_bits(char *buf, long x)
67 {
68   if(0) {
69     tc_log_msg(__FILE__, "MAGIC: 0x%02lx 0x%02lx 0x%02lx 0x%02lx %s", (x >> 24) & 0xff, ((x >> 16) & 0xff), ((x >>  8) & 0xff), ((x      ) & 0xff), filetype(x));
70     tc_log_msg(__FILE__, " FILE: 0x%02x 0x%02x 0x%02x 0x%02x", buf[2] & 0xff, buf[3] & 0xff, buf[0] & 0xff, buf[1] & 0xff);
71   }
72 
73     if ((uint8_t)buf[0] != ((x >>  8) & 0xff))
74 	return 0;
75     if ((uint8_t)buf[1] != ((x      ) & 0xff))
76 	return 0;
77 
78   // OK found it
79   return 1;
80 }
81 
pack_scan_16(char * video,long magic)82 static int pack_scan_16(char *video, long magic)
83 {
84     int k, off = (video[VOB_PACKET_OFFSET] & 0xff) + VOB_PACKET_OFFSET + 1;
85 
86     for(k=off; k<=VOB_PACKET_SIZE-2; ++k) {
87 	if(_cmp_16_bits(video+k, magic)) return(k);
88     }// scan buffer
89     return(-1);
90 }
91 
92 
pack_scan_32(char * video,long magic)93 static int pack_scan_32(char *video, long magic)
94 {
95     int k, off = (video[VOB_PACKET_OFFSET] & 0xff) + VOB_PACKET_OFFSET + 1;
96 
97     for(k=off; k<=VOB_PACKET_SIZE-4; ++k) {
98 	if(_cmp_32_bits(video+k, magic)) return(k);
99     }// scan buffer
100     return(-1);
101 }
102 
103 #if 0  // unused
104 static unsigned long read_ts(char *_s)
105 {
106 
107   unsigned long pts;
108 
109   char *buffer=_s;
110 
111   unsigned int ptr=0;
112 
113   pts = (buffer[ptr++] >> 1) & 7;  //low 4 bits (7==1111)
114   pts <<= 15;
115   pts |= (stream_read_int16(&buffer[ptr]) >> 1);
116   ptr+=2;
117   pts <<= 15;
118   pts |= (stream_read_int16(&buffer[ptr]) >> 1);
119 
120   return pts;
121 }
122 #endif
123 
124 #define BUF_WARN_COUNT 20
125 
probe_picext(uint8_t * buffer,size_t buflen)126 static int probe_picext(uint8_t *buffer, size_t buflen)
127 {
128 
129   //  static char *picture_structure_str[4] = {
130   //  "Invalid Picture Structure",
131   //  "Top field",
132   //  "Bottom field",
133   //  "Frame Picture"
134   //};
135   if(buflen < 3) {
136 #ifdef PROBE_DEBUG
137     static int buf_small_count = 0;
138     if(buf_small_count == 0
139       || (buf_small_count % BUF_WARN_COUNT) == 0) {
140         tc_log_warn(__FILE__, "not enough buffer to probe picture extension "
141                           "(buflen=%lu) [happened at least %i times]",
142                           (unsigned long)buflen, buf_small_count);
143     }
144     buf_small_count++;
145 #endif
146     return(-1); /* failed probe */
147   }
148   return(buffer[2] & 3);
149 }
150 
probe_group(uint8_t * buffer,size_t buflen)151 static const char *probe_group(uint8_t *buffer, size_t buflen)
152 {
153     static char retbuf[32];
154     if(buflen < 5) {
155 #ifdef PROBE_DEBUG
156         static int buf_small_count = 0;
157         if(buf_small_count == 0
158           || (buf_small_count % BUF_WARN_COUNT) == 0) {
159             tc_log_warn(__FILE__, "not enough buffer to probe picture group "
160                              "(buflen=%lu) [happened at least %i times]",
161                              (unsigned long)buflen, buf_small_count);
162         }
163         buf_small_count++;
164 #endif
165 	*retbuf = 0;
166     } else {
167 	tc_snprintf(retbuf, sizeof(retbuf), "%s%s",
168 		    (buffer[4] & 0x40) ? " closed_gop" : "",
169 		    (buffer[4] & 0x20) ? " broken_link" : "");
170     }
171     return retbuf;
172 }
173 
174 int flag1=0, flag2=0, flag3=0;
175 
scan_pack_pics(char * video)176 int scan_pack_pics(char *video)
177 {
178 
179    int k, off = (video[VOB_PACKET_OFFSET] & 0xff) + VOB_PACKET_OFFSET + 1;
180 
181    int ctr=0;
182 
183 
184    if(flag1) if( (video[off] & 0xff) == 0) ++ctr;
185    if(flag2) if( (video[off] & 0xff) == 1  &&  (video[off+1] & 0xff) == 0) ++ctr;
186    if(flag3) if( (video[off] & 0xff) == 0  && (video[off+1] & 0xff) == 1  &&  (video[off+2] & 0xff) == 0) ++ctr;
187 
188 //   tc_log_msg(__FILE__, "off=%d byte=0x%x byte=0x%x ctr=%d", off , (video[off] & 0xff), (video[VOB_PACKET_SIZE-4] & 0xff), ctr);
189 
190    if(ctr && (verbose & TC_PRIVATE)) tc_log_msg(__FILE__, "split PIC code detected");
191 
192    flag1=flag2=flag3=0;
193 
194    for(k=off; k<=VOB_PACKET_SIZE-4; ++k) {
195      if(_cmp_32_bits(video+k, MPEG_PICTURE_START_CODE)) ++ctr;
196    }
197 
198    if( (video[VOB_PACKET_SIZE-1] & 0xff) == 0) flag3=1;
199    if( (video[VOB_PACKET_SIZE-2] & 0xff) == 0 && (video[VOB_PACKET_SIZE-1] & 0xff) == 0) flag2=1;
200    if( (video[VOB_PACKET_SIZE-3] & 0xff) == 0 && (video[VOB_PACKET_SIZE-2] & 0xff) == 0 && (video[VOB_PACKET_SIZE-1] & 0xff) == 1) flag1=1;
201 
202 //   tc_log_msg(__FILE__, "ctr= %d | f1=%d, f2=%d, f3=%d", ctr, flag1, flag2, flag3);
203 
204    return(ctr);
205 }
206 
scan_pack_ext(char * buf)207 int scan_pack_ext(char *buf)
208 {
209 
210   int n, ret_code=-1;
211 
212   for(n=0; n<VOB_PACKET_SIZE-4; ++n) {
213 
214       if(_cmp_32_bits(buf+n, TC_MAGIC_PICEXT) && ((uint8_t) buf[n+4]>>4)==8){
215 	  ret_code = probe_picext(buf+n+4, VOB_PACKET_SIZE-4-n);
216       }
217   } // probe extension header
218 
219   return(ret_code);
220 }
221 
222 
scan_pack_payload(char * video,size_t size,int n,int verbose)223 void scan_pack_payload(char *video, size_t size, int n, int verbose)
224 {
225 
226     int k;
227     char buf[256];
228     unsigned long i_pts, i_dts;
229 
230     int aud_tag, vid_tag;
231 
232     int len;
233 
234     double pts;
235 
236     seq_info_t si;
237 
238     // scan payload
239 
240     // time stamp:
241     ac_memcpy(buf, &video[4], 6);
242     pts = read_time_stamp(buf);
243 
244     //    tc_log_msg(__FILE__, "PTS=%ld %d %f %ld",  read_time_stamp_long(buf),read_ts(buf), read_ts(buf)/90000., parse_pts(buf, 2));
245 
246     // payload length
247     len = stream_read_int16(&video[18]);
248 
249     tc_log_msg(__FILE__, "[%06d] id=0x%x SCR=%12.8f size=%4d", n, (video[17] & 0xff), pts, len);
250 
251 
252     if((video[17] & 0xff) == P_ID_MPEG) {
253 
254 	if((k=pack_scan_32(video, TC_MAGIC_M2V))!=-1) {
255 
256 	    tc_log_msg(__FILE__, "    MPEG SEQ start code found in packet %d, offset %4d", n, k);
257 
258 
259 	    //read packet header
260 	    ac_memcpy(buf, &video[20], 16);
261 	    get_pts_dts(buf, &i_pts, &i_dts);
262 
263 	    tc_log_msg(__FILE__, "    PTS=%f DTS=%f", (double) i_pts / 90000., (double) i_dts / 90000.);
264 
265 	    stats_sequence(&video[k+4], &si);
266 
267 	}
268 
269 	if((k=pack_scan_32(video, MPEG_SEQUENCE_END_CODE))!=-1)
270 	    tc_log_msg(__FILE__, "    MPEG SEQ   end code found in packet %d, offset %4d", n, k);
271 
272 	if((k=pack_scan_32(video, MPEG_EXT_START_CODE))!=-1) {
273 
274 	    if(((uint8_t)video[k+4]>>4)==8) {
275 		    int mode = probe_picext(&video[k+4], size - (size_t)k);
276             if(mode > 0)
277                 tc_log_msg(__FILE__, "    MPEG EXT start code found in packet %d, offset %4d, %s", n, k, picture_structure_str[mode]);
278             else
279                 tc_log_msg(__FILE__, "    MPEG EXT start code found INCOMPLETE in packet %d, offset %4d", n, k);
280 	    } else
281 		    tc_log_msg(__FILE__, "    MPEG EXT start code found in packet %d, offset %4d", n, k);
282 	}
283 
284 	if((k=pack_scan_32(video, MPEG_GOP_START_CODE))!=-1) {
285 	    tc_log_msg(__FILE__, "    MPEG GOP start code found in packet %d, offset %4d, gop [%03d]%s",
286 		       n, k, gop_cnt,
287 		       probe_group((uint8_t*) &video[k+4], size - (size_t)k));
288 	    gop_pts=pts;
289 	    ++gop_cnt;
290 	    gop=1;
291 	}
292 
293 	if((k=pack_scan_32(video, MPEG_PICTURE_START_CODE))!=-1)
294 	    tc_log_msg(__FILE__, "    MPEG PIC start code found in packet %d, offset %4d", n, k);
295 
296 	if((k=pack_scan_32(video, MPEG_SYSTEM_START_CODE))!=-1)
297 	    tc_log_msg(__FILE__, "    MPEG SYS start code found in packet %d, offset %4d", n, k);
298 
299 	if((k=pack_scan_32(video, MPEG_PADDING_START_CODE))!=-1)
300 	    tc_log_msg(__FILE__, "    MPEG PAD start code found in packet %d, offset %4d", n, k);
301     }
302 
303     if((video[17] & 0xff) == P_ID_AC3) {
304 
305 	      //position of track code
306 	      uint8_t *ibuf=video+14;
307 	      uint8_t *tmp=ibuf + 9 + ibuf[8];
308 
309 	      //read packet header
310 	      ac_memcpy(buf, &video[20], 16);
311 	      get_pts_dts(buf, &i_pts, &i_dts);
312 
313 	      tc_log_msg(__FILE__, "    substream PTS=%f [0x%x]", (double) i_pts / 90000., *tmp);
314 
315 	      if((k=pack_scan_16(video, TC_MAGIC_AC3))!=-1) {
316 		if(gop) {
317 
318 		  tc_log_msg(__FILE__, "    AC3 sync frame, packet %6d, offset %3d, gop [%03d], A-V %.3f", n, k, gop_cnt-1, pts-gop_pts);
319 		  gop=0;
320 
321 	    } else
322 	      tc_log_msg(__FILE__, "    AC3 sync frame found in packet %d, offset %d", n, k);
323 	}
324 
325 	if((k=pack_scan_32(video, MPEG_PADDING_START_CODE))!=-1)
326 	    tc_log_msg(__FILE__, "    MPEG PAD start code found in packet %d, offset %4d", n, k);
327 
328     }
329 
330     if((video[17] & 0xff) >= 0xc0 && (video[17] & 0xff) <= 0xdf) {
331 
332       //read packet header
333       ac_memcpy(buf, &video[20], 16);
334       get_pts_dts(buf, &i_pts, &i_dts);
335 
336       tc_log_msg(__FILE__, "    MPEG audio PTS=%f [0x%x]", (double) i_pts / 90000., (video[17] & 0xff));
337     }
338 
339     if((video[17] & 0xff) == P_ID_PROG) {
340 
341 	aud_tag = (video[23]>>2) & 0x3f;
342 	vid_tag = video[24] & 0x1f;
343 
344 	tc_log_msg(__FILE__, "    MPEG PRG start code found in packet %d, A=%d, V=%d", n, aud_tag, vid_tag);
345 
346     }// check for sync packet
347 
348     return;
349 }
350 
scan_pack_header(char * buf,long x)351 int scan_pack_header(char *buf, long x)
352 {
353 
354     int ret = _cmp_32_bits(buf, x);
355     if(0) tc_log_msg(__FILE__, "scan_pack_header() ret=%d", ret);
356     return(ret);
357 }
358