changeset 14477:92553e3c8f01

automatic fps calculation for mpeg4 in raw stream/mpeg-ts
author nicodvb
date Wed, 12 Jan 2005 20:43:53 +0000
parents 1225f60d4c0d
children d04cbfe4ea8d
files libmpdemux/mpeg_hdr.c libmpdemux/mpeg_hdr.h libmpdemux/video.c
diffstat 3 files changed, 166 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/libmpdemux/mpeg_hdr.c	Wed Jan 12 15:17:15 2005 +0000
+++ b/libmpdemux/mpeg_hdr.c	Wed Jan 12 20:43:53 2005 +0000
@@ -27,7 +27,7 @@
     int width, height;
 
     if ((buffer[6] & 0x20) != 0x20){
-	printf("missing marker bit!\n");
+	fprintf(stderr, "missing marker bit!\n");
 	return 1;	/* missing marker_bit */
     }
 
@@ -101,3 +101,112 @@
     return 0;
 }
 
+
+//MPEG4 HEADERS
+static unsigned char getbits(unsigned char *buffer, unsigned int from, unsigned char len)
+{
+    unsigned int n;
+    unsigned char m, u, l, y;
+    
+    n = from / 8;
+    m = from % 8;
+    u = 8 - m;
+    l = (len > u ? len - u : 0);
+    
+    y = (buffer[n] << m);
+    if(8 > len)
+    	y  >>= (8-len);
+    if(l)
+    	y |= (buffer[n+1] >> (8-l));
+	
+    //fprintf(stderr, "GETBITS(%d -> %d): bytes=0x%x 0x%x, n=%d, m=%d, l=%d, u=%d, Y=%d\n", 
+    //	from, (int) len, (int) buffer[n],(int) buffer[n+1], n, (int) m, (int) l, (int) u, (int) y);
+    return  y;
+}
+
+static int read_timeinc(mp_mpeg_header_t * picture, unsigned char * buffer, int n)
+{
+    if(picture->timeinc_bits > 8) {
+      picture->timeinc_unit = getbits(buffer, n, picture->timeinc_bits - 8) << 8;
+      n += picture->timeinc_bits - 8;
+      picture->timeinc_unit |= getbits(buffer, n, 8);
+      n += 8;
+    } else {
+      picture->timeinc_unit = getbits(buffer, n, picture->timeinc_bits);
+      n += picture->timeinc_bits;
+    }
+    //fprintf(stderr, "TIMEINC2: %d, bits: %d\n", picture->timeinc_unit, picture->timeinc_bits);
+    return n;
+}
+
+int mp4_header_process_vol(mp_mpeg_header_t * picture, unsigned char * buffer)
+{
+    unsigned int n, aspect=0, aspectw=0, aspecth=0,  x=1, v;
+    
+    //begins with 0x0000012x
+    picture->fps = 0;
+    picture->timeinc_bits = picture->timeinc_resolution = picture->timeinc_unit = 0;
+    n = 9;
+    if(getbits(buffer, n, 1))
+      n += 7;
+    n++;
+    aspect=getbits(buffer, n, 4);
+    n += 4;
+    if(aspect == 0x0f) {
+      aspectw = getbits(buffer, n, 8);
+      n += 8;
+      aspecth = getbits(buffer, n, 8);
+      n += 8;
+    }
+    
+    if(getbits(buffer, n, 1)) {
+      n += 4;
+      if(getbits(buffer, n, 1))
+        n += 79;
+      n++;
+    } else n++;
+    
+    n+=3;
+    
+    picture->timeinc_resolution = getbits(buffer, n, 8) << 8;
+    n += 8;
+    picture->timeinc_resolution |= getbits(buffer, n, 8);
+    n += 8;
+    
+    picture->timeinc_bits = 0;
+    v = picture->timeinc_resolution - 1;
+    while(v && (x<16)) {
+      v>>=1;
+      picture->timeinc_bits++;
+    }
+    picture->timeinc_bits = (picture->timeinc_bits > 1 ? picture->timeinc_bits : 1);
+    
+    n++; //marker bit
+    
+    if(getbits(buffer, n, 1)) {	//fixed_vop_timeinc
+      n++;
+      n = read_timeinc(picture, buffer, n);
+      
+      if(picture->timeinc_unit)
+        picture->fps = (picture->timeinc_resolution * 10000) / picture->timeinc_unit;
+    }
+    
+    //fprintf(stderr, "ASPECT: %d, PARW=%d, PARH=%d, TIMEINCRESOLUTION: %d, FIXED_TIMEINC: %d (number of bits: %d), FPS: %u\n", 
+    //	aspect, aspectw, aspecth, picture->timeinc_resolution, picture->timeinc_unit, picture->timeinc_bits, picture->fps);
+    
+    return 0;
+}
+
+int mp4_header_process_vop(mp_mpeg_header_t * picture, unsigned char * buffer)
+{
+  int n;
+  n = 0;
+  picture->picture_type = getbits(buffer, n, 2);
+  n += 2;
+  while(getbits(buffer, n, 1))
+    n++;
+  n++;
+  getbits(buffer, n, 1);
+  n++;
+  n = read_timeinc(picture, buffer, n);
+}
--- a/libmpdemux/mpeg_hdr.h	Wed Jan 12 15:17:15 2005 +0000
+++ b/libmpdemux/mpeg_hdr.h	Wed Jan 12 20:43:53 2005 +0000
@@ -15,7 +15,12 @@
     int progressive_frame;
     int top_field_first;
     int display_time; // secs*100
+    //the following are for mpeg4
+    int timeinc_resolution, timeinc_bits, timeinc_unit;
+    int picture_type;
 } mp_mpeg_header_t;
 
 int mp_header_process_sequence_header (mp_mpeg_header_t * picture, unsigned char * buffer);
 int mp_header_process_extension (mp_mpeg_header_t * picture, unsigned char * buffer);
+int mp4_header_process_vol(mp_mpeg_header_t * picture, unsigned char * buffer);
+int mp4_header_process_vop(mp_mpeg_header_t * picture, unsigned char * buffer);
--- a/libmpdemux/video.c	Wed Jan 12 15:17:15 2005 +0000
+++ b/libmpdemux/video.c	Wed Jan 12 20:43:53 2005 +0000
@@ -116,6 +116,7 @@
   break;
  }
  case VIDEO_MPEG4: {
+   int pos = 0, vop_cnt=0, units[3];
    videobuf_len=0; videobuf_code_len=0;
    mp_msg(MSGT_DECVIDEO,MSGL_V,"Searching for Video Object Start code... ");fflush(stdout);
    while(1){
@@ -142,7 +143,14 @@
 	return 0;
       }
    }
-   mp_msg(MSGT_DECVIDEO,MSGL_V,"OK!\nSearching for Video Object Plane Start code... ");fflush(stdout);
+   pos = videobuf_len+4;
+   if(!read_video_packet(d_video)){ 
+     mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Can't read Video Object Layer Header\n");
+     return 0;
+   }
+   mp4_header_process_vol(&picture, &(videobuffer[pos]));
+   mp_msg(MSGT_DECVIDEO,MSGL_V,"OK! FPS SEEMS TO BE %.3f\nSearching for Video Object Plane Start code... ", sh_video->fps);fflush(stdout);
+ mp4_init: 
    while(1){
       int i=sync_video_packet(d_video);
       if(i==0x1B6) break; // found it!
@@ -151,6 +159,48 @@
 	return 0;
       }
    }
+   pos = videobuf_len+4;
+   if(!read_video_packet(d_video)){ 
+     mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Can't read Video Object Plane Header\n");
+     return 0;
+   }
+   mp4_header_process_vop(&picture, &(videobuffer[pos]));
+   units[vop_cnt] = picture.timeinc_unit;
+   vop_cnt++;
+   //mp_msg(MSGT_DECVIDEO,MSGL_V, "TYPE: %d, unit: %d\n", picture.picture_type, picture.timeinc_unit);
+   if(!picture.fps) {
+     int i, mn, md, mx, diff;
+     if(vop_cnt < 3)
+          goto mp4_init;
+
+     i=0;
+     mn = mx = units[0];  
+     for(i=0; i<3; i++) {
+       if(units[i] < mn)
+         mn = units[i];
+       if(units[i] > mx)
+         mx = units[i];
+     }
+     md = mn;
+     for(i=0; i<3; i++) {
+       if((units[i] > mn) && (units[i] < mx))
+         md = units[i];
+     }
+     mp_msg(MSGT_DECVIDEO,MSGL_V, "MIN: %d, mid: %d, max: %d\n", mn, md, mx);
+     if(mx - md > md - mn)
+       diff = md - mn;
+     else
+       diff = mx - md;
+     if(diff > 0){
+       picture.fps = (picture.timeinc_resolution * 10000) / diff;
+       mp_msg(MSGT_DECVIDEO,MSGL_V, "FPS seems to be: %d/10000, resolution: %d, delta_units: %d\n", picture.fps, picture.timeinc_resolution, diff);
+     }
+   }
+   if(picture.fps) {
+    sh_video->fps=picture.fps*0.0001f;
+    sh_video->frametime=10000.0f/(float)picture.fps;
+    mp_msg(MSGT_DECVIDEO,MSGL_INFO, "FPS seems to be: %d/10000\n", picture.fps);
+   }
    mp_msg(MSGT_DECVIDEO,MSGL_V,"OK!\n");
    sh_video->format=0x10000004;
    break;