[MPlayer-dev-eng] [PATCH] unified timing patch for H264

James Zhang muliang.zhang at cs2c.com.cn
Fri Aug 20 04:11:19 CEST 2010


On 2010-08-19 20:00, Pásztor Szilárd wrote:
> Reimar Döffinger:
> > I don't have any samples at hand, but 0 is returned in got_picture also
> > if a 0-sized packet is passed, and 0-sized packets are used for timing
> > in AVI (I however do not know if those 0-sized packets are ever passed
> > up all the way to the decoder or not, but at least there would be a
> sudden
> > break of meaning of 0-sized packets between demuxer and decoder layer
> > that needs to be documented).
> 
> Uhh, you are right again - unfortunately. The generic decoder wrapper of
> libavcodec (in libavformat/utils.c) overwrites this value in got_picture to
> 0,
> so it is the default behavior of lavc to return 0 - which does not help us
> recognize the 0 from a first field.
> 
> > Given that libavcodec is broken in this case, not really.
> 
> Yes it is clearly a bug, as vital information gets lost. However, in
> libavcodec/h264.c, if we return -1 instead of 0 (at "Wait for second
> field"),
> which may not be a pretty way of signalling this special case, it works.
> 
> There are other problems by the way. With nocorrect-pts, when timestamps
> are
> not reordered, frame times are calculated from fps and pts values are
> ignored when displaying the image. But not when calculating a-v sync! This
> leads to a-v sync constantly jumping around because of the mixed up pts
> values, so the a-v sync correction algorithm makes picture jerky again. :(
> 
> I've started looking into the fixpts filter but it seems to me that pts
> values don't get overwritten (calculated from framerate) which seems the
> only
> way to solve this problem.
> 
> s.
> 
>      ---------------------------------------------------------------------
>      |  As long as we have each other, we'll never run out of problems.  |
>      ---------------------------------------------------------------------


I have this problem for months. And I am sure that ffmpeg has not this
bug after having checked the latest ffmpeg version. That is because the
ffmpeg have flag in some structs for deel with this situation. 

But one thing is convinced that the ffmpeg decode one h264 frame or
field by one time in mplayer. It is  different from Mpeg2 or any others.
I have try Pásztor Szilárd's way but I used another in the end.

I think the mplayer try to analyze some information for h264 video, but
it didn't finish. Some fields information in SEI section not check out.
So I add the h264_parse_sei function in libmpdemux. After analyze the
VUI, the mplayer have to know the SEI information to set the right fps.
If the fps has wrong value, the field codec video will lose AV sync.

Here come my patch.


Index: libmpdemux/video.c
===================================================================
--- libmpdemux/video.c	(revision 31373)
+++ libmpdemux/video.c	(working copy)
@@ -532,6 +532,10 @@
             if(!read_video_packet(d_video)) return -1; // EOF
           }
 
+	  if((i&~0x60) == 0x106){
+            h264_parse_sei(&picture, &(videobuffer[pos]), videobuf_len
- pos);
+          }
+
           // here starts the access unit end detection code
           // see the mail on MPlayer-dev-eng for details:
           // Date: Sat, 17 Sep 2005 11:24:06 +0200
Index: libmpdemux/mpeg_hdr.c
===================================================================
--- libmpdemux/mpeg_hdr.c	(revision 31373)
+++ libmpdemux/mpeg_hdr.c	(working copy)
@@ -323,6 +323,7 @@
 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;
+  unsigned int nal_hrd_parameters_present,vcl_hrd_parameters_present;
 
   if(getbits(buf, n++, 1))
   {
@@ -359,14 +360,44 @@
     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);
+    picture->fixed_fps = getbits(buf, n++, 1);
 
     if(picture->timeinc_unit > 0 && picture->timeinc_resolution > 0)
       picture->fps = (float) picture->timeinc_resolution / (float)
picture->timeinc_unit;
-    if(fixed_fps)
-      picture->fps /= 2;
+    //if(fixed_fps)
+      //picture->fps /= 2;
   }
-
+  /* Analyse the vui for SEI */
+  if((nal_hrd_parameters_present = getbits(buf, n++, 1)) > 0)
+  {
+    unsigned cpb_cnt_minus1;
+    cpb_cnt_minus1 = read_golomb(buf, &n);
+    n += 8;
+    for(int i = 0; i< cpb_cnt_minus1; i++)
+    {
+      read_golomb(buf, &n);
+      read_golomb(buf, &n);
+      n++;
+    }
+    n += 20;
+  }
+  if((vcl_hrd_parameters_present = getbits(buf, n++, 1)) > 0)
+  {
+    unsigned cpb_cnt_minus1;
+    cpb_cnt_minus1 = read_golomb(buf, &n);
+    n += 8;
+    for(int i = 0; i< cpb_cnt_minus1; i++)
+    {
+      read_golomb(buf, &n);
+      read_golomb(buf, &n);
+      n++;
+    }
+    n += 20;
+  }
+  if(nal_hrd_parameters_present || vcl_hrd_parameters_present)
+    n++;
+  picture->pic_struct_present = getbits(buf, n++, 1);
+  
   //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);
 
@@ -438,6 +469,64 @@
   return n;
 }
 
+int h264_parse_sei(mp_mpeg_header_t * picture, unsigned char * buf, int
len)
+{
+  int n=0,size=0,type = 0;
+
+  do{
+    type = getbits(buf, n,8);
+    n+=8;
+  }while(type == 255);
+  do{
+    size = getbits(buf, n,8);
+    n+=8;
+  }while(size == 255);
+  switch(type)
+  {
+    case 1:  /*Picture timing SEI*/
+    {
+      int delta;
+      if(picture->pic_struct_present){
+        picture->picture_structure = getbits(buf, n, 4);
+        n += 4;
+        switch(picture->picture_structure)
+        {
+          case PIC_STRUCT_TOP_FIELD:
+          case PIC_STRUCT_BOTTOM_FIELD:
+            delta = 1;
+            break;
+          case PIC_STRUCT_FRAME:
+          case PIC_STRUCT_TOP_BOTTOM:
+          case PIC_STRUCT_BOTTOM_TOP:
+            delta = 2;
+            break;
+          case PIC_STRUCT_TOP_BOTTOM_TOP:
+          case PIC_STRUCT_BOTTOM_TOP_BOTTOM:
+            delta = 3;
+            break;
+          case PIC_STRUCT_FRAME_DOUBLING:
+            delta = 4;
+            break;
+          case PIC_STRUCT_FRAME_TRIPLING:
+            delta = 6;
+            break;
+	}
+      } else {
+        delta = 2;
+      }
+      if(picture->fixed_fps)
+        picture->fps = (float) picture->timeinc_resolution / (float)
picture->timeinc_unit / delta;
+      break;
+    }
+    default:
+      getbits(buf, n, 8*size);
+      n += 8*size;
+      break;
+  }
+  return n;
+}
+
+
 static int mp_unescape03(unsigned char *buf, int len)
 {
   unsigned char *dest;
Index: libmpdemux/mpeg_hdr.h
===================================================================
--- libmpdemux/mpeg_hdr.h	(revision 31373)
+++ libmpdemux/mpeg_hdr.h	(working copy)
@@ -19,6 +19,16 @@
 #ifndef MPLAYER_MPEG_HDR_H
 #define MPLAYER_MPEG_HDR_H
 
+#define PIC_STRUCT_FRAME 0
+#define PIC_STRUCT_TOP_FIELD 1
+#define PIC_STRUCT_BOTTOM_FIELD 2
+#define PIC_STRUCT_TOP_BOTTOM 3
+#define PIC_STRUCT_BOTTOM_TOP 4
+#define PIC_STRUCT_TOP_BOTTOM_TOP 5
+#define PIC_STRUCT_BOTTOM_TOP_BOTTOM 6
+#define PIC_STRUCT_FRAME_DOUBLING 7
+#define PIC_STRUCT_FRAME_TRIPLING 9
+
 typedef struct {
     // video info:
     int mpeg1; // 0=mpeg2  1=mpeg1
@@ -37,6 +47,8 @@
     int progressive_frame;
     int top_field_first;
     int display_time; // secs*100
+    int pic_struct_present;
+    int fixed_fps;
     //the following are for mpeg4
     unsigned int timeinc_resolution, timeinc_bits, timeinc_unit;
     int picture_type;
@@ -48,6 +60,7 @@
 int mp4_header_process_vol(mp_mpeg_header_t * picture, unsigned char *
buffer);
 void 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);
+int h264_parse_sei(mp_mpeg_header_t * picture, unsigned char * buf, int
len);
 int mp_vc1_decode_sequence_header(mp_mpeg_header_t * picture, unsigned
char * buf, int len);
 
 unsigned char mp_getbits(unsigned char *buffer, unsigned int from,
unsigned char len);



More information about the MPlayer-dev-eng mailing list