changeset 14798:0bd50330e688

framerate autodetection for H264 in raw/ts streams
author nicodvb
date Thu, 24 Feb 2005 20:02:41 +0000
parents 05eab20de476
children 090be6ae25ac
files libmpdemux/mpeg_hdr.c libmpdemux/mpeg_hdr.h libmpdemux/video.c
diffstat 3 files changed, 173 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/libmpdemux/mpeg_hdr.c	Thu Feb 24 17:46:19 2005 +0000
+++ b/libmpdemux/mpeg_hdr.c	Thu Feb 24 20:02:41 2005 +0000
@@ -210,3 +210,151 @@
   n++;
   n = read_timeinc(picture, buffer, n);
 }
+
+#define min(a, b) ((a) <= (b) ? (a) : (b))
+
+static unsigned int read_golomb(unsigned char *buffer, unsigned int *init)
+{
+  unsigned int x, v = 0, v2 = 0, m, len = 0, n = *init;
+  
+  while(getbits(buffer, n++, 1) == 0)
+    len++;
+  
+  x = len + n;
+  while(n < x)
+  {
+    m = min(x - n, 8);
+    v |= getbits(buffer, n, m);
+    n += m;
+    if(x - n > 8)
+      v <<= 8;
+  }
+  
+  v2 = 1;
+  for(n = 0; n < len; n++)
+    v2 <<= 1;
+  v2 = (v2 - 1) + v;
+  
+  //fprintf(stderr, "READ_GOLOMB(%u), V=2^%u + %u-1 = %u\n", *init, len, v, v2);
+  *init = x;
+  return v2;
+}
+
+
+static int h264_parse_vui(mp_mpeg_header_t * picture, unsigned char * buf, unsigned int n)
+{
+  unsigned int overscan, vsp_color, chroma, timing, fixed_fps;
+  
+  if(getbits(buf, n++, 1))
+  {
+    picture->aspect_ratio_information = getbits(buf, n, 8);
+    n += 8;
+    if(picture->aspect_ratio_information == 255)
+    {
+      picture->display_picture_width = (getbits(buf, n, 8) << 8) | getbits(buf, n + 8, 8);
+      n += 16;
+      
+      picture->display_picture_height = (getbits(buf, n, 8) << 8) | getbits(buf, n + 8, 8);
+      n += 16;
+    }
+  }
+  
+  if(overscan=getbits(buf, n++, 1))
+    n++;
+  if(vsp_color=getbits(buf, n++, 1))
+  {
+    n += 4;
+    if(getbits(buf, n++, 1))
+      n += 24;
+  }
+  if(chroma=getbits(buf, n++, 1))
+  {
+    read_golomb(buf, &n);
+    read_golomb(buf, &n);
+  }
+  if(timing=getbits(buf, n++, 1))
+  {
+    picture->timeinc_unit = (getbits(buf, n, 8) << 24) | (getbits(buf, n+8, 8) << 16) | (getbits(buf, n+16, 8) << 8) | getbits(buf, n+24, 8);
+    n += 32;
+    
+    picture->timeinc_resolution = (getbits(buf, n, 8) << 24) | (getbits(buf, n+8, 8) << 16) | (getbits(buf, n+16, 8) << 8) | getbits(buf, n+24, 8);
+    n += 32;
+    
+    fixed_fps = getbits(buf, n, 1);
+    
+    if(picture->timeinc_unit > 0 && picture->timeinc_resolution > 0)
+      picture->fps = (picture->timeinc_resolution * 10000) / picture->timeinc_unit;
+  }
+  
+  //fprintf(stderr, "H264_PARSE_VUI, OVESCAN=%u, VSP_COLOR=%u, CHROMA=%u, TIMING=%u, DISPW=%u, DISPH=%u, TIMERES=%u, TIMEINC=%u, FIXED_FPS=%u\n", overscan, vsp_color, chroma, timing, picture->display_picture_width, picture->display_picture_height,
+  //	picture->timeinc_resolution, picture->timeinc_unit, picture->timeinc_unit, fixed_fps);
+  
+  return n;
+}
+
+int h264_parse_sps(mp_mpeg_header_t * picture, unsigned char * buf, int len)
+{
+  unsigned int n = 0, m = 0, v, i, j;
+  unsigned char *dest;
+
+  dest = (unsigned char*) malloc(len);
+  if(! dest)
+    return 0;
+  j = i = 0;
+  while(i <= len-3)
+  {
+    if(buf[i] == 0 && buf[i+1] == 0 && buf[i+2] == 3)
+    {
+      dest[j] = dest[j+1] = 0;
+      j += 2;
+      i += 3;
+    }
+    else
+    {
+      dest[j] = buf[i];
+      j++;
+      i++;
+    }
+  }
+  dest[j] = buf[len-2];
+  dest[j+1] = buf[len-1];
+  j += 2;
+  len = j+1;
+  buf = dest;
+  
+  picture->fps = picture->timeinc_unit = picture->timeinc_resolution = 0;
+  n = 24;
+  read_golomb(buf, &n);
+  read_golomb(buf, &n);
+  v = read_golomb(buf, &n);
+  if(v == 0)
+    read_golomb(buf, &n);
+  else if(v == 1)
+  {
+    getbits(buf, n++, 1);
+    read_golomb(buf, &n);
+    read_golomb(buf, &n);
+    v = read_golomb(buf, &n);
+    for(i = 0; i < v; i++)
+      read_golomb(buf, &n);
+  }
+  read_golomb(buf, &n);
+  getbits(buf, n++, 1);
+  read_golomb(buf, &n);
+  read_golomb(buf, &n);
+  if(!getbits(buf, n++, 1))
+    getbits(buf, n++, 1);
+  getbits(buf, n++, 1);
+  if(getbits(buf, n++, 1))
+  {
+    read_golomb(buf, &n);
+    read_golomb(buf, &n);
+    read_golomb(buf, &n);
+    read_golomb(buf, &n);
+  }
+  if(getbits(buf, n++, 1))
+    n = h264_parse_vui(picture, buf, n);
+
+  free(dest);
+  return n;
+}
--- a/libmpdemux/mpeg_hdr.h	Thu Feb 24 17:46:19 2005 +0000
+++ b/libmpdemux/mpeg_hdr.h	Thu Feb 24 20:02:41 2005 +0000
@@ -24,3 +24,4 @@
 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);
+int h264_parse_sps(mp_mpeg_header_t * picture, unsigned char * buf, int len);
--- a/libmpdemux/video.c	Thu Feb 24 17:46:19 2005 +0000
+++ b/libmpdemux/video.c	Thu Feb 24 20:02:41 2005 +0000
@@ -206,6 +206,7 @@
    break;
  }
  case VIDEO_H264: {
+   int pos = 0;
    videobuf_len=0; videobuf_code_len=0;
    mp_msg(MSGT_DECVIDEO,MSGL_V,"Searching for sequence parameter set... ");fflush(stdout);
    while(1){
@@ -222,6 +223,12 @@
      mp_msg(MSGT_DECVIDEO,MSGL_ERR,MSGTR_ShMemAllocFail);
      return 0;
    }
+   pos = videobuf_len+4;
+   if(!read_video_packet(d_video)){ 
+     mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Can't read sequence parameter set\n");
+     return 0;
+   }
+   h264_parse_sps(&picture, &(videobuffer[pos]), videobuf_len - pos);
    mp_msg(MSGT_DECVIDEO,MSGL_V,"Searching for picture parameter set... ");fflush(stdout);
    while(1){
       int i=sync_video_packet(d_video);
@@ -243,6 +250,11 @@
    }
    mp_msg(MSGT_DECVIDEO,MSGL_V,"OK!\n");
    sh_video->format=0x10000005;
+   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);
+   }
    break;
  }
  case VIDEO_MPEG12: {
@@ -495,7 +507,19 @@
       //
         while(videobuf_len<VIDEOBUFFER_SIZE-MAX_VIDEO_PACKET_SIZE){
           int i=sync_video_packet(d_video);
+          int pos = videobuf_len+4;
+          if(!i) return -1;
           if(!read_video_packet(d_video)) return -1; // EOF
+          if((i&~0x60) == 0x107 && i != 0x107) {
+            h264_parse_sps(&picture, &(videobuffer[pos]), videobuf_len - pos);
+            if(picture.fps > 0) {
+              sh_video->fps=picture.fps*0.0001f;
+              sh_video->frametime=10000.0f/(float)picture.fps;
+            }
+            i=sync_video_packet(d_video);
+            if(!i) return -1;
+            if(!read_video_packet(d_video)) return -1; // EOF
+          }
           if((i&~0x60) == 0x101 || (i&~0x60) == 0x102 || (i&~0x60) == 0x105) break;
         }
 	*start=videobuffer; in_size=videobuf_len;