[FFmpeg-devel] [PATCH] Implement PAFF in H.264

Jeff Downs heydowns
Tue Sep 18 20:30:39 CEST 2007


Attached is a patch that implements PAFF in H.264.

I don't expect this to be accepted right away, due to size and complexity, 
but I want to get it out there for review and for people to try out and 
comment on.

It is working stable for me on a number of samples, including ones that 
mix PAFF with progressive and/or MBAFF.

Basic overview of how it works:
1. Fields are decoded and deinterlaced.
2. If non-paired fields are encountered, they are not output, but are used 
for reference if so marked.
3. Reference lists are kept as they were before, but now may also contain 
unmatched field pairs.  Reference list construction splits field pairs out 
to fields as needed.

There is a major shortcoming/known issue with this patch;  it disables the 
error concealing calls for field pictures.  This is because the error 
concealer needs slices to be contiguous regions of the picture buffers. 
I'd appreciate input on how best to augment the error concealer to handle 
interlaced slices (or if I am just missing something....)

Also interested in hearing how this should be split into smaller patches 
(I know that at least the addition/changes to header documentation should 
come out).

 	-Jeff
-------------- next part --------------
Index: libavcodec/h264.c
===================================================================
--- libavcodec/h264.c	(revision 10526)
+++ libavcodec/h264.c	(working copy)
@@ -171,7 +171,7 @@
 
     //wow what a mess, why didn't they simplify the interlacing&intra stuff, i can't imagine that these complex rules are worth it
 
-    top_xy     = mb_xy  - s->mb_stride;
+    top_xy     = mb_xy  - (s->mb_stride << FIELD_PICTURE);
     topleft_xy = top_xy - 1;
     topright_xy= top_xy + 1;
     left_xy[1] = left_xy[0] = mb_xy-1;
@@ -1697,7 +1697,7 @@
     const int full_mx= mx>>2;
     const int full_my= my>>2;
     const int pic_width  = 16*s->mb_width;
-    const int pic_height = 16*s->mb_height >> MB_MBAFF;
+    const int pic_height = 16*s->mb_height >> (MB_MBAFF || FIELD_PICTURE);
 
     if(!pic->data[0]) //FIXME this is unacceptable, some senseable error concealment must be done for missing reference frames
         return;
@@ -1721,7 +1721,7 @@
 
     if(ENABLE_GRAY && s->flags&CODEC_FLAG_GRAY) return;
 
-    if(MB_MBAFF){
+    if(MB_MBAFF || FIELD_PICTURE){
         // chroma offset when predicting from a field of opposite parity
         my += 2 * ((s->mb_y & 1) - (h->ref_cache[list][scan8[n]] & 1));
         emu |= (my>>3) < 0 || (my>>3) + 8 >= (pic_height>>1);
@@ -1756,7 +1756,7 @@
     dest_cb +=   x_offset +   y_offset*h->mb_uvlinesize;
     dest_cr +=   x_offset +   y_offset*h->mb_uvlinesize;
     x_offset += 8*s->mb_x;
-    y_offset += 8*(s->mb_y >> MB_MBAFF);
+    y_offset += 8*(s->mb_y >> (MB_MBAFF || FIELD_PICTURE));
 
     if(list0){
         Picture *ref= &h->ref_list[0][ h->ref_cache[0][ scan8[n] ] ];
@@ -1789,7 +1789,7 @@
     dest_cb +=   x_offset +   y_offset*h->mb_uvlinesize;
     dest_cr +=   x_offset +   y_offset*h->mb_uvlinesize;
     x_offset += 8*s->mb_x;
-    y_offset += 8*(s->mb_y >> MB_MBAFF);
+    y_offset += 8*(s->mb_y >> (MB_MBAFF || FIELD_PICTURE));
 
     if(list0 && list1){
         /* don't optimize for luma-only case, since B-frames usually
@@ -2752,15 +2752,125 @@
 }
 
 /**
+ * Split one reference list into field parts, interleaving by parity
+ * as per H.264 spec section 8.2.4.2.5. Output fields have their data pointers
+ * set to look at the actual start of data for that field.
+ *
+ * @param dest output list
+ * @param dest_len maximum number of fields to put in dest
+ * @param src the source reference list containing fields and/or field pairs
+ *            (aka short_ref/long_ref, or 
+ *             refFrameListXShortTerm/refFrameListLongTerm in spec-speak)
+ * @param src_len number of Picture's in source (pairs and unmatched fields)
+ * @param parity the parity of the picture being decoded/needing 
+ *        these ref pics (PICT_{TOP,BOTTOM}_FIELD)
+ * @return number of fields placed in dest
+ */
+static inline int split_field_half_ref_list(Picture *dest, int dest_len, Picture *src, int src_len, int parity)
+{
+    int same_i, opp_i;
+    int i;
+    int same;
+    int out_i;
+
+    same_i = 0;
+    opp_i = 0;
+    same = 1;
+    out_i = 0;
+
+    while (out_i < dest_len) {
+        if (same && same_i < src_len) {
+            if ((src[same_i].valid_structure & parity)) {
+                same = 0;
+                dest[out_i] = src[same_i];
+                for (i = 0; i < 4; ++i) {
+                    if (parity == PICT_BOTTOM_FIELD)
+                        dest[out_i].data[i] += dest[out_i].linesize[i];
+                    dest[out_i].linesize[i] *= 2;
+                    dest[out_i].pic_id *= 2;
+                }
+                out_i++;
+            }
+            same_i++;
+
+        } else if (opp_i < src_len) {
+            if ((src[opp_i].valid_structure & (PICT_FRAME - parity))) {
+                same = 1;
+                dest[out_i] = src[opp_i];
+                for (i = 0; i < 4; ++i) {
+                    if (parity == PICT_TOP_FIELD)
+                        dest[out_i].data[i] += dest[out_i].linesize[i];
+                    dest[out_i].linesize[i] *= 2;
+                    dest[out_i].pic_id *= 2;
+                    dest[out_i].pic_id++;
+                }
+                out_i++;
+            }
+            opp_i++;
+
+        } else {
+            break;
+        }
+    }
+
+    return out_i;
+}
+
+/**
+ * Split a the reference frame list into a reference field list.
+ * This implements H.264 spec 8.2.4.2.5 for a combined input list.
+ * The input list contains both reference field pairs and
+ * unmatched reference fields; it is ordered as spec describes
+ * RefPicListX for frames in 8.2.4.2.1 and 8.2.4.2.3, except that
+ * unmatched field pairs are also present. Conceptually this is equivalent
+ * to concatenation of refFrameListXShortTerm with refFrameListLongTerm.
+ *
+ * @param dest output reference list where ordered fields are to be placed
+ * @param dest_len max number of fields to place at dest
+ * @param src source reference list, as described above
+ * @param src_len number of pictures (pairs and unmatched fields) in src
+ * @param parity parity of field being currently decoded 
+ *        (one of PICT_{TOP,BOTTOM}_FIELD)
+ * @param long_i index into src array that holds first long reference picture,
+ *        or src_len if no long refs present.
+ */
+static int split_field_ref_list(Picture *dest, int dest_len, Picture *src, int src_len, int parity, int long_i)
+{
+
+    int i = split_field_half_ref_list(dest, dest_len, src, src_len, parity);
+    dest += i;
+    dest_len -= i;
+
+    i += split_field_half_ref_list(dest, dest_len, src + long_i, src_len - long_i, parity);
+    return i;
+}
+
+/**
  * fills the default_ref_list.
  */
 static int fill_default_ref_list(H264Context *h){
     MpegEncContext * const s = &h->s;
     int i;
     int smallest_poc_greater_than_current = -1;
+    int structure_sel;
     Picture sorted_short_ref[32];
+    Picture field_entry_list[2][32];
+    Picture *frame_list[2];
+    
+    if (!FIELD_PICTURE) {
+        structure_sel = 0;
+        frame_list[0] = h->default_ref_list[0];
+        frame_list[1] = h->default_ref_list[1];
+    } else {
+        structure_sel = PICT_FRAME;
+        frame_list[0] = field_entry_list[0];
+        frame_list[1] = field_entry_list[1];
+    }
 
     if(h->slice_type==B_TYPE){
+        int list;
+        int len[2];
+        int short_len[2];
         int out_i;
         int limit= INT_MIN;
 
@@ -2788,71 +2898,82 @@
                 }
             }
         }
-    }
 
-    if(s->picture_structure == PICT_FRAME){
-        if(h->slice_type==B_TYPE){
-            int list;
-            tprintf(h->s.avctx, "current poc: %d, smallest_poc_greater_than_current: %d\n", s->current_picture_ptr->poc, smallest_poc_greater_than_current);
+        tprintf(h->s.avctx, "current poc: %d, smallest_poc_greater_than_current: %d\n", s->current_picture_ptr->poc, smallest_poc_greater_than_current);
 
-            // find the largest poc
-            for(list=0; list<2; list++){
-                int index = 0;
-                int j= -99;
-                int step= list ? -1 : 1;
 
-                for(i=0; i<h->short_ref_count && index < h->ref_count[list]; i++, j+=step) {
-                    while(j<0 || j>= h->short_ref_count){
-                        if(j != -99 && step == (list ? -1 : 1))
-                            return -1;
-                        step = -step;
-                        j= smallest_poc_greater_than_current + (step>>1);
-                    }
-                    if(sorted_short_ref[j].reference != 3) continue;
-                    h->default_ref_list[list][index  ]= sorted_short_ref[j];
-                    h->default_ref_list[list][index++].pic_id= sorted_short_ref[j].frame_num;
-                }
+        // find the largest poc
+        for(list=0; list<2; list++){
+            int index = 0;
+            int j= -99;
+            int step= list ? -1 : 1;
 
-                for(i = 0; i < 16 && index < h->ref_count[ list ]; i++){
-                    if(h->long_ref[i] == NULL) continue;
-                    if(h->long_ref[i]->reference != 3) continue;
-
-                    h->default_ref_list[ list ][index  ]= *h->long_ref[i];
-                    h->default_ref_list[ list ][index++].pic_id= i;;
+            for(i=0; i<h->short_ref_count && index < h->ref_count[list]; i++, j+=step) {
+                while(j<0 || j>= h->short_ref_count){
+                    if(j != -99 && step == (list ? -1 : 1))
+                        return -1;
+                    step = -step;
+                    j= smallest_poc_greater_than_current + (step>>1);
                 }
+                if(sorted_short_ref[j].reference != 3) continue;
+                if((sorted_short_ref[j].valid_structure | structure_sel) != PICT_FRAME) continue;
+                frame_list[list][index  ]= sorted_short_ref[j];
+                frame_list[list][index++].pic_id= sorted_short_ref[j].frame_num;
+            }
+            short_len[list] = index;
 
-                if(list && (smallest_poc_greater_than_current<=0 || smallest_poc_greater_than_current>=h->short_ref_count) && (1 < index)){
-                    // swap the two first elements of L1 when
-                    // L0 and L1 are identical
-                    Picture temp= h->default_ref_list[1][0];
-                    h->default_ref_list[1][0] = h->default_ref_list[1][1];
-                    h->default_ref_list[1][1] = temp;
-                }
+            for(i = 0; i < 16 && index < h->ref_count[ list ]; i++){
+                if(h->long_ref[i] == NULL) continue;
+                if(h->long_ref[i]->reference != 3) continue;
+                if((h->long_ref[i]->valid_structure | structure_sel) != PICT_FRAME) continue;
 
-                if(index < h->ref_count[ list ])
-                    memset(&h->default_ref_list[list][index], 0, sizeof(Picture)*(h->ref_count[ list ] - index));
+                frame_list[ list ][index  ]= *h->long_ref[i];
+                frame_list[ list ][index++].pic_id= i;;
             }
-        }else{
-            int index=0;
-            for(i=0; i<h->short_ref_count; i++){
-                if(h->short_ref[i]->reference != 3) continue; //FIXME refernce field shit
-                h->default_ref_list[0][index  ]= *h->short_ref[i];
-                h->default_ref_list[0][index++].pic_id= h->short_ref[i]->frame_num;
+            len[list] = index;
+
+            if(list && (smallest_poc_greater_than_current<=0 || smallest_poc_greater_than_current>=h->short_ref_count) && (1 < index)){
+                // swap the two first elements of L1 when
+                // L0 and L1 are identical
+                Picture temp= frame_list[1][0];
+                frame_list[1][0] = frame_list[1][1];
+                frame_list[1][1] = temp;
             }
-            for(i = 0; i < 16; i++){
-                if(h->long_ref[i] == NULL) continue;
-                if(h->long_ref[i]->reference != 3) continue;
-                h->default_ref_list[0][index  ]= *h->long_ref[i];
-                h->default_ref_list[0][index++].pic_id= i;;
-            }
-            if(index < h->ref_count[0])
-                memset(&h->default_ref_list[0][index], 0, sizeof(Picture)*(h->ref_count[0] - index));
+
         }
-    }else{ //FIELD
-        if(h->slice_type==B_TYPE){
-        }else{
-            //FIXME second field balh
+
+        for(list=0; list<2; list++){
+            if (s->picture_structure != PICT_FRAME)
+                len[list] = split_field_ref_list(h->default_ref_list[list], h->ref_count[list], frame_list[list], len[list], s->picture_structure, short_len[list]);
+        
+            if(len[list] < h->ref_count[ list ])
+                memset(&h->default_ref_list[list][len[list]], 0, sizeof(Picture)*(h->ref_count[ list ] - len[list]));
         }
+
+
+    }else{
+        int index=0;
+        int short_len;
+        for(i=0; i<h->short_ref_count; i++){
+            if(h->short_ref[i]->reference != 3) continue;
+            if((h->short_ref[i]->valid_structure | structure_sel) != PICT_FRAME) continue;
+            frame_list[0][index  ]= *h->short_ref[i];
+            frame_list[0][index++].pic_id= h->short_ref[i]->frame_num;
+        }
+        short_len = index;
+        for(i = 0; i < 16; i++){
+            if(h->long_ref[i] == NULL) continue;
+            if(h->long_ref[i]->reference != 3) continue;
+            if((h->long_ref[i]->valid_structure | structure_sel) != PICT_FRAME) continue;
+            frame_list[0][index  ]= *h->long_ref[i];
+            frame_list[0][index++].pic_id= i;;
+        }
+        
+        if (s->picture_structure != PICT_FRAME)
+            index = split_field_ref_list(h->default_ref_list[0], h->ref_count[0], frame_list[0], index, s->picture_structure, short_len);
+        
+        if(index < h->ref_count[0])
+            memset(&h->default_ref_list[0][index], 0, sizeof(Picture)*(h->ref_count[0] - index));
     }
 #ifdef TRACE
     for (i=0; i<h->ref_count[0]; i++) {
@@ -2872,7 +2993,7 @@
 
 static int decode_ref_pic_list_reordering(H264Context *h){
     MpegEncContext * const s = &h->s;
-    int list, index;
+    int list, index, pic_structure;
 
     print_short_term(h);
     print_long_term(h);
@@ -2899,8 +3020,10 @@
                 }
 
                 if(reordering_of_pic_nums_idc<3){
+                    int add;
                     if(reordering_of_pic_nums_idc<2){
                         const unsigned int abs_diff_pic_num= get_ue_golomb(&s->gb) + 1;
+                        int frame_num;
 
                         if(abs_diff_pic_num >= h->max_pic_num){
                             av_log(h->s.avctx, AV_LOG_ERROR, "abs_diff_pic_num overflow\n");
@@ -2911,23 +3034,58 @@
                         else                                pred+= abs_diff_pic_num;
                         pred &= h->max_pic_num - 1;
 
+                        if (FIELD_PICTURE) {
+                            frame_num = pred >> 1;
+                            if (pred & 1) {
+                                pic_structure = s->picture_structure;
+                                add = (s->picture_structure == PICT_BOTTOM_FIELD);
+                            } else {
+                                pic_structure = PICT_FRAME - s->picture_structure;
+                                add = (s->picture_structure == PICT_TOP_FIELD);
+                            }
+                        } else {
+                            frame_num = pred;
+                            pic_structure = PICT_FRAME;
+                            add = 0;
+                        }
+                        
                         for(i= h->short_ref_count-1; i>=0; i--){
                             ref = h->short_ref[i];
                             assert(ref->reference == 3);
                             assert(!ref->long_ref);
-                            if(ref->data[0] != NULL && ref->frame_num == pred && ref->long_ref == 0) // ignore non existing pictures by testing data[0] pointer
+                            if(ref->data[0] != NULL &&
+                                   ref->frame_num == frame_num && 
+                                   (ref->valid_structure & pic_structure) && 
+                                   ref->long_ref == 0) // ignore non existing pictures by testing data[0] pointer and valid_structure
                                 break;
                         }
                         if(i>=0)
-                            ref->pic_id= ref->frame_num;
+                            ref->pic_id= pred;
                     }else{
+                        int long_idx;
                         pic_id= get_ue_golomb(&s->gb); //long_term_pic_idx
-                        if(pic_id>31){
+
+                        if (FIELD_PICTURE) {
+                            long_idx = pic_id >> 1;
+                            if (pic_id & 1) {
+                                pic_structure = s->picture_structure;
+                                add = (s->picture_structure == PICT_BOTTOM_FIELD);
+                            } else {
+                                pic_structure = PICT_FRAME - s->picture_structure;
+                                add = (s->picture_structure == PICT_TOP_FIELD);
+                            }
+                        } else {
+                            long_idx = pic_id;
+                            pic_structure = PICT_FRAME;
+                            add = 0;
+                        }
+
+                        if(long_idx>31){
                             av_log(h->s.avctx, AV_LOG_ERROR, "long_term_pic_idx overflow\n");
                             return -1;
                         }
-                        ref = h->long_ref[pic_id];
-                        if(ref){
+                        ref = h->long_ref[long_idx];
+                        if(ref && (ref->valid_structure & pic_structure)){
                             ref->pic_id= pic_id;
                             assert(ref->reference == 3);
                             assert(ref->long_ref);
@@ -2949,6 +3107,14 @@
                             h->ref_list[list][i]= h->ref_list[list][i-1];
                         }
                         h->ref_list[list][index]= *ref;
+                        if (FIELD_PICTURE) {
+                            for (i = 0; i < 4; ++i) {
+                                if (add)
+                                    h->ref_list[list][index].data[i] += h->ref_list[list][index].linesize[i];
+                                h->ref_list[list][index].linesize[i] *= 2;
+                            }
+                        }
+                                
                     }
                 }else{
                     av_log(h->s.avctx, AV_LOG_ERROR, "illegal reordering_of_pic_nums_idc\n");
@@ -3090,6 +3256,7 @@
 static inline void unreference_pic(H264Context *h, Picture *pic){
     int i;
     pic->reference=0;
+    pic->valid_structure=0;
     if(pic == h->delayed_output_pic)
         pic->reference=1;
     else{
@@ -3137,6 +3304,7 @@
     idr(h);
     if(h->s.current_picture_ptr)
         h->s.current_picture_ptr->reference= 0;
+    h->s.first_field= 0;
 }
 
 /**
@@ -3165,6 +3333,57 @@
 }
 
 /**
+ * Removes reference marking from a field or field pair by picture number.
+ * If an unmatched field pair, or both fields in a pair become unreferenced,
+ * the field (pair) is removed from the short term reference list and list
+ * state is updated accordingly.
+ * @param picret set to the unreferenced and removed picture, or NULL if the 
+ *         picture still has fields in reference or was not found.
+ * @return -1 if picture with pic_num not found. 0 otherwise
+ */
+static int remove_field_short(H264Context *h, int pic_num, Picture **picret){
+    MpegEncContext * const s = &h->s;
+    int i;
+    Picture *pic = NULL;
+    int frame_num = pic_num >> 1;
+
+    if(s->avctx->debug&FF_DEBUG_MMCO)
+        av_log(h->s.avctx, AV_LOG_DEBUG, "remove field short %d count %d\n", pic_num, h->short_ref_count);
+
+    for(i=0; i<h->short_ref_count; i++){
+        pic= h->short_ref[i];
+
+        if(s->avctx->debug&FF_DEBUG_MMCO)
+            av_log(h->s.avctx, AV_LOG_DEBUG, "%d %d %p\n", i, pic->frame_num, pic);
+
+        if (pic->frame_num == frame_num)
+            break;        
+    }
+    
+    *picret = NULL;
+    if (pic) {
+        int mask;
+        
+        mask = (pic_num & 1) ? ~s->picture_structure : s->picture_structure;
+        pic->valid_structure &= mask;
+        
+        if (pic->valid_structure == 0) {
+            h->short_ref[i]= NULL;
+            if (--h->short_ref_count)
+                memmove(&h->short_ref[i], &h->short_ref[i+1], (h->short_ref_count - i)*sizeof(Picture*));
+            *picret = pic;
+        }
+        return 0;
+    }
+    
+    return -1;
+}
+
+/**
+ * Removes reference marking from a field or field pair by picture number.
+ * If an unmatched field pair, or both fields in a pair become unreferenced,
+ * the field (pair) is removed from the short term reference list and list
+ * state is updated accordingly.
  *
  * @return the removed picture or NULL if an error occurs
  */
@@ -3179,6 +3398,40 @@
 }
 
 /**
+ * Removes reference marking from a field or field pair by picture number.
+ * If an unmatched field pair, or both fields in a pair become unreferenced,
+ * the field (pair) is removed from the long term reference list and list
+ * state is updated accordingly.
+ *
+ * @param picret set to the unreferenced and removed picture, or NULL if the 
+ *         picture still has fields in reference or was not found.
+ * @return -1 if picture with pic_num not found. 0 otherwise
+ */
+static int remove_field_long(H264Context *h, int pic_num, Picture **picret){
+    MpegEncContext * const s = &h->s;
+    Picture *pic;
+    int i = pic_num / 2;
+
+    pic= h->long_ref[i];
+    *picret = NULL;
+    if (pic) {
+        int mask;
+        
+        mask = (pic_num & 1) ? ~s->picture_structure : s->picture_structure;
+        pic->valid_structure &= mask;
+        
+        if (pic->valid_structure == 0) {
+            h->long_ref[i]= NULL;
+            h->long_ref_count--;
+            *picret = pic;
+        }
+        return 0;
+    }
+
+    return -1;
+}
+
+/**
  * print short term list
  */
 static void print_short_term(H264Context *h) {
@@ -3214,7 +3467,7 @@
 static int execute_ref_pic_marking(H264Context *h, MMCO *mmco, int mmco_count){
     MpegEncContext * const s = &h->s;
     int i, j;
-    int current_is_long=0;
+    int current_ref_assigned=0;
     Picture *pic;
 
     if((s->avctx->debug&FF_DEBUG_MMCO) && mmco_count==0)
@@ -3222,47 +3475,86 @@
 
     for(i=0; i<mmco_count; i++){
         if(s->avctx->debug&FF_DEBUG_MMCO)
-            av_log(h->s.avctx, AV_LOG_DEBUG, "mmco:%d %d %d\n", h->mmco[i].opcode, h->mmco[i].short_frame_num, h->mmco[i].long_index);
+            av_log(h->s.avctx, AV_LOG_DEBUG, "mmco:%d %d %d\n", h->mmco[i].opcode, h->mmco[i].short_pic_num, h->mmco[i].long_arg);
 
         switch(mmco[i].opcode){
         case MMCO_SHORT2UNUSED:
-            pic= remove_short(h, mmco[i].short_frame_num);
+            if (FIELD_PICTURE) {
+                j= remove_field_short(h, mmco[i].short_pic_num, &pic);
+            } else {
+                pic= remove_short(h, mmco[i].short_pic_num);
+                j= -1;
+            }
+
             if(pic)
                 unreference_pic(h, pic);
-            else if(s->avctx->debug&FF_DEBUG_MMCO)
+            else if(s->avctx->debug&FF_DEBUG_MMCO && j < 0)
                 av_log(h->s.avctx, AV_LOG_DEBUG, "mmco: remove_short() failure\n");
             break;
         case MMCO_SHORT2LONG:
-            pic= remove_long(h, mmco[i].long_index);
-            if(pic) unreference_pic(h, pic);
+            if (s->picture_structure != PICT_FRAME && 
+                    mmco[i].long_arg < h->long_ref_count &&
+                    h->long_ref[mmco[i].long_arg]->frame_num == mmco[i].short_pic_num / 2) {
+                /* do nothing, we've already moved this field pair. */
+            } else {
+                int frame_num = mmco[i].short_pic_num >> 
+                                   (s->picture_structure != PICT_FRAME);
 
-            h->long_ref[ mmco[i].long_index ]= remove_short(h, mmco[i].short_frame_num);
-            if (h->long_ref[ mmco[i].long_index ]){
-                h->long_ref[ mmco[i].long_index ]->long_ref=1;
-                h->long_ref_count++;
+                pic= remove_long(h, mmco[i].long_arg);
+                if(pic) unreference_pic(h, pic);
+
+                h->long_ref[ mmco[i].long_arg ]= remove_short(h, frame_num);
+                if (h->long_ref[ mmco[i].long_arg ]){
+                    h->long_ref[ mmco[i].long_arg ]->long_ref=1;
+                    h->long_ref_count++;
+                }
             }
             break;
         case MMCO_LONG2UNUSED:
-            pic= remove_long(h, mmco[i].long_index);
+            if (FIELD_PICTURE) {
+                j= remove_field_long(h, mmco[i].long_arg, &pic);
+            } else {
+                pic= remove_long(h, mmco[i].long_arg);
+                j= -1;
+            }
+
             if(pic)
                 unreference_pic(h, pic);
-            else if(s->avctx->debug&FF_DEBUG_MMCO)
+            else if(s->avctx->debug&FF_DEBUG_MMCO && j < 0)
                 av_log(h->s.avctx, AV_LOG_DEBUG, "mmco: remove_long() failure\n");
             break;
         case MMCO_LONG:
-            pic= remove_long(h, mmco[i].long_index);
-            if(pic) unreference_pic(h, pic);
+            j = 1;
+            if (FIELD_PICTURE && !s->first_field) {
 
-            h->long_ref[ mmco[i].long_index ]= s->current_picture_ptr;
-            h->long_ref[ mmco[i].long_index ]->long_ref=1;
-            h->long_ref_count++;
+                if (h->long_ref[ mmco[i].long_arg ] == s->current_picture_ptr) {
+                    /* Just mark second field as referenced */
+                    j = 0;
+                } else if (s->current_picture_ptr->valid_structure) {
+                    /* First field in pair in short term list.
+                     * This is not allowed; see 7.4.3, notes 2 and 3.
+                     */
+                    av_log(h->s.avctx, AV_LOG_ERROR, "illegal long term reference assignment for second field in complementary field pair (first field is short term)\n");
+                    j = 0;
+                }
+            }
 
-            current_is_long=1;
+            if (j) {
+                pic= remove_long(h, mmco[i].long_arg);
+                if(pic) unreference_pic(h, pic);
+
+                h->long_ref[ mmco[i].long_arg ]= s->current_picture_ptr;
+                h->long_ref[ mmco[i].long_arg ]->long_ref=1;
+                h->long_ref_count++;
+            }
+
+            s->current_picture_ptr->valid_structure |= s->picture_structure;
+            current_ref_assigned=1;
             break;
         case MMCO_SET_MAX_LONG:
-            assert(mmco[i].long_index <= 16);
+            assert(mmco[i].long_arg <= 16);
             // just remove the long term which index is greater than new max
-            for(j = mmco[i].long_index; j<16; j++){
+            for(j = mmco[i].long_arg; j<16; j++){
                 pic = remove_long(h, j);
                 if (pic) unreference_pic(h, pic);
             }
@@ -3281,7 +3573,30 @@
         }
     }
 
-    if(!current_is_long){
+    if (!current_ref_assigned && FIELD_PICTURE && 
+            !s->first_field && s->current_picture_ptr->valid_structure) {
+
+        /* Second field of complementary field pair; the first field of
+         * which is already referenced. If short referenced, it
+         * should be first entry in short_ref. If not, it must exist
+         * in long_ref; trying to put it on the short list here is an
+         * error in the encoded bit stream (ref: 7.4.3, NOTE 2 and 3).
+         * If on neither list, we have a logic problem elsewhere
+         */
+        if (h->short_ref_count && h->short_ref[0] == s->current_picture_ptr) {
+            /* Just mark the second field valid */
+            s->current_picture_ptr->valid_structure = PICT_FRAME;
+            current_ref_assigned = 1;
+        } else if (s->current_picture_ptr->long_ref) {
+            av_log(h->s.avctx, AV_LOG_ERROR, "illegal short term reference assignment for second field in complementary field pair (first field is long term)\n");
+            current_ref_assigned = 1;
+        } else {
+            av_log(h->s.avctx, AV_LOG_ERROR, "problem in internal reference list handling; second field in pair claims first field is reference, but not in any ref list\n");
+            s->current_picture_ptr->valid_structure = 0;
+        }
+    }
+    
+    if(!current_ref_assigned){
         pic= remove_short(h, s->current_picture_ptr->frame_num);
         if(pic){
             unreference_pic(h, pic);
@@ -3294,6 +3609,7 @@
         h->short_ref[0]= s->current_picture_ptr;
         h->short_ref[0]->long_ref=0;
         h->short_ref_count++;
+        s->current_picture_ptr->valid_structure |= s->picture_structure;
     }
 
     print_short_term(h);
@@ -3307,8 +3623,8 @@
 
     if(h->nal_unit_type == NAL_IDR_SLICE){ //FIXME fields
         s->broken_link= get_bits1(gb) -1;
-        h->mmco[0].long_index= get_bits1(gb) - 1; // current_long_term_idx
-        if(h->mmco[0].long_index == -1)
+        h->mmco[0].long_arg= get_bits1(gb) - 1; // current_long_term_idx
+        if(h->mmco[0].long_arg == -1)
             h->mmco_index= 0;
         else{
             h->mmco[0].opcode= MMCO_LONG;
@@ -3321,19 +3637,19 @@
 
                 h->mmco[i].opcode= opcode;
                 if(opcode==MMCO_SHORT2UNUSED || opcode==MMCO_SHORT2LONG){
-                    h->mmco[i].short_frame_num= (h->frame_num - get_ue_golomb(gb) - 1) & ((1<<h->sps.log2_max_frame_num)-1); //FIXME fields
+                    h->mmco[i].short_pic_num= h->curr_pic_num - get_ue_golomb(gb) - 1;
 /*                    if(h->mmco[i].short_frame_num >= h->short_ref_count || h->short_ref[ h->mmco[i].short_frame_num ] == NULL){
                         av_log(s->avctx, AV_LOG_ERROR, "illegal short ref in memory management control operation %d\n", mmco);
                         return -1;
                     }*/
                 }
                 if(opcode==MMCO_SHORT2LONG || opcode==MMCO_LONG2UNUSED || opcode==MMCO_LONG || opcode==MMCO_SET_MAX_LONG){
-                    unsigned int long_index= get_ue_golomb(gb);
-                    if(/*h->mmco[i].long_index >= h->long_ref_count || h->long_ref[ h->mmco[i].long_index ] == NULL*/ long_index >= 16){
+                    unsigned int long_arg= get_ue_golomb(gb);
+                    if(long_arg >= 32 || (long_arg >= 16 && !(opcode == MMCO_LONG2UNUSED && FIELD_PICTURE))){
                         av_log(h->s.avctx, AV_LOG_ERROR, "illegal long ref in memory management control operation %d\n", opcode);
                         return -1;
                     }
-                    h->mmco[i].long_index= long_index;
+                    h->mmco[i].long_arg= long_arg;
                 }
 
                 if(opcode > (unsigned)MMCO_LONG){
@@ -3347,10 +3663,17 @@
         }else{
             assert(h->long_ref_count + h->short_ref_count <= h->sps.ref_frame_count);
 
-            if(h->long_ref_count + h->short_ref_count == h->sps.ref_frame_count){ //FIXME fields
+            if(h->long_ref_count + h->short_ref_count == h->sps.ref_frame_count &&
+                    !(FIELD_PICTURE && !s->first_field && s->current_picture_ptr->valid_structure)) {
                 h->mmco[0].opcode= MMCO_SHORT2UNUSED;
-                h->mmco[0].short_frame_num= h->short_ref[ h->short_ref_count - 1 ]->frame_num;
+                h->mmco[0].short_pic_num= h->short_ref[ h->short_ref_count - 1 ]->frame_num;
                 h->mmco_index= 1;
+                if (FIELD_PICTURE) {
+                    h->mmco[0].short_pic_num *= 2;
+                    h->mmco[1].opcode= MMCO_SHORT2UNUSED;
+                    h->mmco[1].short_pic_num= h->mmco[0].short_pic_num + 1;
+                    h->mmco_index= 2;
+                }
             }else
                 h->mmco_index= 0;
         }
@@ -3438,11 +3761,15 @@
         field_poc[1]= poc;
     }
 
-    if(s->picture_structure != PICT_BOTTOM_FIELD)
+    if(s->picture_structure != PICT_BOTTOM_FIELD) {
         s->current_picture_ptr->field_poc[0]= field_poc[0];
-    if(s->picture_structure != PICT_TOP_FIELD)
+        s->current_picture_ptr->poc = field_poc[0];
+    }
+    if(s->picture_structure != PICT_TOP_FIELD) {
         s->current_picture_ptr->field_poc[1]= field_poc[1];
-    if(s->picture_structure == PICT_FRAME) // FIXME field pix?
+        s->current_picture_ptr->poc = field_poc[1];
+    }
+    if(!FIELD_PICTURE || !s->first_field)
         s->current_picture_ptr->poc= FFMIN(field_poc[0], field_poc[1]);
 
     return 0;
@@ -3508,6 +3835,7 @@
     dst->s.current_picture      = src->s.current_picture;
     dst->s.linesize             = src->s.linesize;
     dst->s.uvlinesize           = src->s.uvlinesize;
+    dst->s.first_field          = src->s.first_field;
 
     dst->prev_poc_msb           = src->prev_poc_msb;
     dst->prev_poc_lsb           = src->prev_poc_lsb;
@@ -3541,6 +3869,7 @@
     static const uint8_t slice_type_map[5]= {P_TYPE, B_TYPE, I_TYPE, SP_TYPE, SI_TYPE};
     unsigned int slice_type, tmp, i;
     int default_ref_list_done = 0;
+    int last_pic_structure;
 
     s->current_picture.reference= h->nal_ref_idc != 0;
     s->dropable= h->nal_ref_idc == 0;
@@ -3549,7 +3878,8 @@
 
     if((s->flags2 & CODEC_FLAG2_CHUNKS) && first_mb_in_slice == 0){
         h0->current_slice = 0;
-        s->current_picture_ptr= NULL;
+        if (!s->first_slice)
+            s->current_picture_ptr= NULL;
     }
 
     slice_type= get_ue_golomb(&s->gb);
@@ -3618,6 +3948,7 @@
             return -1;  // we cant (re-)initialize context during parallel decoding
         if (MPV_common_init(s) < 0)
             return -1;
+        s->first_field = 0;
 
         init_scan_tables(h);
         alloc_tables(h);
@@ -3652,29 +3983,76 @@
         }
     }
 
-    if(h0->current_slice == 0){
-        if(frame_start(h) < 0)
-            return -1;
-    }
-    if(h != h0)
-        clone_slice(h, h0);
-
-    s->current_picture_ptr->frame_num= //FIXME frame_num cleanup
     h->frame_num= get_bits(&s->gb, h->sps.log2_max_frame_num);
 
     h->mb_mbaff = 0;
     h->mb_aff_frame = 0;
+    last_pic_structure = s->picture_structure;
     if(h->sps.frame_mbs_only_flag){
         s->picture_structure= PICT_FRAME;
     }else{
         if(get_bits1(&s->gb)) { //field_pic_flag
             s->picture_structure= PICT_TOP_FIELD + get_bits1(&s->gb); //bottom_field_flag
-            av_log(h->s.avctx, AV_LOG_ERROR, "PAFF interlacing is not implemented\n");
         } else {
             s->picture_structure= PICT_FRAME;
             h->mb_aff_frame = h->sps.mb_aff;
         }
     }
+
+    if(h0->current_slice == 0){
+        /* figure out if we have a complementary field pair */
+        if (s->first_field) {
+            assert(s->current_picture_ptr && s->current_picture_ptr->data[0]);
+
+            if (s->picture_structure == PICT_FRAME ||
+                    s->picture_structure == last_pic_structure) {
+                /* 
+                 * Unmatched field pair. Don't display it, but use
+                 * for reference if so marked
+                 */
+                if (s->current_picture_ptr->reference == 1)
+                    s->current_picture_ptr->reference = 0;
+                s->current_picture_ptr = NULL;
+                
+                s->first_field = FIELD_PICTURE;
+
+            } else {
+                if (s->current_picture.reference &&
+                        s->current_picture_ptr->reference == 3 &&
+                        s->current_picture_ptr->frame_num != h->frame_num) {
+                    /* 
+                     * This and previous field were reference, but had
+                     * different frame_nums.  Dump first field (keep in 
+                     * reference list) and consider this as first field.
+                     */
+                    s->first_field = 1;
+                    s->current_picture_ptr = NULL;
+
+                } else {
+                    /* Second field in complementary pair */
+                    if (s->current_picture.reference)
+                        s->current_picture_ptr->reference = 3;
+                    s->first_field = 0;
+                }
+            }
+
+        } else {
+            /* Frame or first field in a potentially complementary pair */
+            assert(!s->current_picture_ptr);
+            s->first_field = FIELD_PICTURE;
+        }
+        
+        if((!FIELD_PICTURE || s->first_field) && frame_start(h) < 0) {
+            s->first_field = 0;
+            return -1;
+        }
+    }
+
+    if(h != h0)
+        clone_slice(h, h0);
+
+    s->current_picture_ptr->frame_num= h->frame_num; //FIXME frame_num cleanup
+
     assert(s->mb_num == s->mb_width * s->mb_height);
     if(first_mb_in_slice << h->mb_aff_frame >= s->mb_num ||
        first_mb_in_slice                    >= s->mb_num){
@@ -3683,13 +4061,18 @@
     }
     s->resync_mb_x = s->mb_x = first_mb_in_slice % s->mb_width;
     s->resync_mb_y = s->mb_y = (first_mb_in_slice / s->mb_width) << h->mb_aff_frame;
+    if (FIELD_PICTURE) {
+        s->resync_mb_y = s->mb_y = s->mb_y * 2;
+        if (s->picture_structure == PICT_BOTTOM_FIELD)
+            s->resync_mb_y = s->mb_y = s->mb_y + 1;
+    }
     assert(s->mb_y < s->mb_height);
 
     if(s->picture_structure==PICT_FRAME){
         h->curr_pic_num=   h->frame_num;
         h->max_pic_num= 1<< h->sps.log2_max_frame_num;
     }else{
-        h->curr_pic_num= 2*h->frame_num;
+        h->curr_pic_num= 2*h->frame_num + 1;
         h->max_pic_num= 1<<(h->sps.log2_max_frame_num + 1);
     }
 
@@ -3725,7 +4108,7 @@
     if(h->slice_type == P_TYPE || h->slice_type == SP_TYPE || h->slice_type == B_TYPE){
         if(h->slice_type == B_TYPE){
             h->direct_spatial_mv_pred= get_bits1(&s->gb);
-            if(h->sps.mb_aff && h->direct_spatial_mv_pred)
+            if(h->mb_aff_frame && h->direct_spatial_mv_pred)
                 av_log(h->s.avctx, AV_LOG_ERROR, "MBAFF + spatial direct mode is not implemented\n");
         }
         num_ref_idx_active_override_flag= get_bits1(&s->gb);
@@ -3845,7 +4228,7 @@
     h->slice_num = ++h0->current_slice;
 
     h->emu_edge_width= (s->flags&CODEC_FLAG_EMU_EDGE) ? 0 : 16;
-    h->emu_edge_height= FRAME_MBAFF ? 0 : h->emu_edge_width;
+    h->emu_edge_height= (FRAME_MBAFF || FIELD_PICTURE) ? 0 : h->emu_edge_width;
 
     if(s->avctx->debug&FF_DEBUG_PICT_INFO){
         av_log(h->s.avctx, AV_LOG_DEBUG, "slice:%d %s mb:%d %c pps:%u frame:%d poc:%d/%d ref:%d/%d qp:%d loop:%d:%d:%d weight:%d%s\n",
@@ -4743,6 +5126,8 @@
         int mb_xy = mb_x + mb_y*s->mb_stride;
         mba_xy = mb_xy - 1;
         mbb_xy = mb_xy - s->mb_stride;
+        if (FIELD_PICTURE)
+            mbb_xy -= s->mb_stride;
     }
 
     if( h->slice_table[mba_xy] == h->slice_num && !IS_SKIP( s->current_picture.mb_type[mba_xy] ))
@@ -4875,15 +5260,9 @@
     return 1 + get_cabac_noinline( &h->cabac, &h->cabac_state[77 + ctx] );
 }
 static int decode_cabac_mb_dqp( H264Context *h) {
-    MpegEncContext * const s = &h->s;
-    int mbn_xy;
     int   ctx = 0;
     int   val = 0;
 
-    if( s->mb_x > 0 )
-        mbn_xy = s->mb_x + s->mb_y*s->mb_stride - 1;
-    else
-        mbn_xy = s->mb_width - 1 + (s->mb_y-1)*s->mb_stride;
 
     if( h->last_qscale_diff != 0 )
         ctx++;
@@ -5238,6 +5617,8 @@
         if (left_mb_frame_flag != curr_mb_frame_flag) {
             h->left_mb_xy[0] = pair_xy - 1;
         }
+    } else if (FIELD_PICTURE) {
+        h->top_mb_xy -= s->mb_stride;
     }
     return;
 }
@@ -6469,7 +6850,7 @@
                 s->mb_x = 0;
                 ff_draw_horiz_band(s, 16*s->mb_y, 16);
                 ++s->mb_y;
-                if(FRAME_MBAFF) {
+                if(FRAME_MBAFF || FIELD_PICTURE) {
                     ++s->mb_y;
                 }
             }
@@ -6506,9 +6887,14 @@
                 s->mb_x=0;
                 ff_draw_horiz_band(s, 16*s->mb_y, 16);
                 ++s->mb_y;
-                if(FRAME_MBAFF) {
+                if(FRAME_MBAFF || FIELD_PICTURE) {
                     ++s->mb_y;
                 }
+                /// FIXME - These slice add calls don't work right for bottom fields; they cause massive erroneous error concealing
+                /// When called with the supplied args, they cover both fields (top and bottom). This causes
+                /// a mismatched s->error_count and a bad error table. Further, the error count goes to INT_MAX
+                /// when called for bottom field, because mb_y goes past end by one (see ++s->mb_y above)
+                /// and resync_mb_y != 0 causes problems for the first MB line, too.
                 if(s->mb_y >= s->mb_height){
                     tprintf(s->avctx, "slice end %d %d\n", get_bits_count(&s->gb), s->gb.size_in_bits);
 
@@ -7105,7 +7491,8 @@
 #endif
     if(!(s->flags2 & CODEC_FLAG2_CHUNKS)){
         h->current_slice = 0;
-        s->current_picture_ptr= NULL;
+        if (!s->first_field)
+            s->current_picture_ptr= NULL;
     }
 
     for(;;){
@@ -7402,87 +7789,101 @@
 
         h->prev_frame_num_offset= h->frame_num_offset;
         h->prev_frame_num= h->frame_num;
-        if(s->current_picture_ptr->reference){
+        if(s->current_picture.reference){
+            /* 
+             * The above tests current_picture (not _ptr) to get reference
+             * mark of the actual picture. For fields, this may be different
+             * than the field pair (_ptr)
+             */
             h->prev_poc_msb= h->poc_msb;
             h->prev_poc_lsb= h->poc_lsb;
+            execute_ref_pic_marking(h, h->mmco, h->mmco_index);
         }
-        if(s->current_picture_ptr->reference)
-            execute_ref_pic_marking(h, h->mmco, h->mmco_index);
 
-        ff_er_frame_end(s);
+        if (s->first_field) {
+            /* Wait for second field. */
+            *data_size = 0;
+        } else {
+            /* 
+             * FIXME: Error handling code does not seem to support interlaced
+             * when slices span multiple rows
+             */
+            if (!FIELD_PICTURE)
+                ff_er_frame_end(s);
 
-        MPV_frame_end(s);
+            MPV_frame_end(s);
 
-    //FIXME do something with unavailable reference frames
+        //FIXME do something with unavailable reference frames
 
 #if 0 //decode order
-        *data_size = sizeof(AVFrame);
+            *data_size = sizeof(AVFrame);
 #else
-        /* Sort B-frames into display order */
+            /* Sort B-frames into display order */
 
-        if(h->sps.bitstream_restriction_flag
-           && s->avctx->has_b_frames < h->sps.num_reorder_frames){
-            s->avctx->has_b_frames = h->sps.num_reorder_frames;
-            s->low_delay = 0;
-        }
+            if(h->sps.bitstream_restriction_flag
+               && s->avctx->has_b_frames < h->sps.num_reorder_frames){
+                s->avctx->has_b_frames = h->sps.num_reorder_frames;
+                s->low_delay = 0;
+            }
 
-        pics = 0;
-        while(h->delayed_pic[pics]) pics++;
+            pics = 0;
+            while(h->delayed_pic[pics]) pics++;
 
-        assert(pics+1 < sizeof(h->delayed_pic) / sizeof(h->delayed_pic[0]));
+            assert(pics+1 < sizeof(h->delayed_pic) / sizeof(h->delayed_pic[0]));
 
-        h->delayed_pic[pics++] = cur;
-        if(cur->reference == 0)
-            cur->reference = 1;
+            h->delayed_pic[pics++] = cur;
+            if(cur->reference == 0)
+                cur->reference = 1;
 
-        cross_idr = 0;
-        for(i=0; h->delayed_pic[i]; i++)
-            if(h->delayed_pic[i]->key_frame || h->delayed_pic[i]->poc==0)
-                cross_idr = 1;
+            cross_idr = 0;
+            for(i=0; h->delayed_pic[i]; i++)
+                if(h->delayed_pic[i]->key_frame || h->delayed_pic[i]->poc==0)
+                    cross_idr = 1;
 
-        out = h->delayed_pic[0];
-        out_idx = 0;
-        for(i=1; h->delayed_pic[i] && !h->delayed_pic[i]->key_frame; i++)
-            if(h->delayed_pic[i]->poc < out->poc){
-                out = h->delayed_pic[i];
-                out_idx = i;
+            out = h->delayed_pic[0];
+            out_idx = 0;
+            for(i=1; h->delayed_pic[i] && !h->delayed_pic[i]->key_frame; i++)
+                if(h->delayed_pic[i]->poc < out->poc){
+                    out = h->delayed_pic[i];
+                    out_idx = i;
+                }
+
+            out_of_order = !cross_idr && prev && out->poc < prev->poc;
+            if(h->sps.bitstream_restriction_flag && s->avctx->has_b_frames >= h->sps.num_reorder_frames)
+                { }
+            else if(prev && pics <= s->avctx->has_b_frames)
+                out = prev;
+            else if((out_of_order && pics-1 == s->avctx->has_b_frames && pics < 15)
+               || (s->low_delay &&
+                ((!cross_idr && prev && out->poc > prev->poc + 2)
+                 || cur->pict_type == B_TYPE)))
+            {
+                s->low_delay = 0;
+                s->avctx->has_b_frames++;
+                out = prev;
             }
+            else if(out_of_order)
+                out = prev;
 
-        out_of_order = !cross_idr && prev && out->poc < prev->poc;
-        if(h->sps.bitstream_restriction_flag && s->avctx->has_b_frames >= h->sps.num_reorder_frames)
-            { }
-        else if(prev && pics <= s->avctx->has_b_frames)
-            out = prev;
-        else if((out_of_order && pics-1 == s->avctx->has_b_frames && pics < 15)
-           || (s->low_delay &&
-            ((!cross_idr && prev && out->poc > prev->poc + 2)
-             || cur->pict_type == B_TYPE)))
-        {
-            s->low_delay = 0;
-            s->avctx->has_b_frames++;
-            out = prev;
-        }
-        else if(out_of_order)
-            out = prev;
+            if(out_of_order || pics > s->avctx->has_b_frames){
+                for(i=out_idx; h->delayed_pic[i]; i++)
+                    h->delayed_pic[i] = h->delayed_pic[i+1];
+            }
 
-        if(out_of_order || pics > s->avctx->has_b_frames){
-            for(i=out_idx; h->delayed_pic[i]; i++)
-                h->delayed_pic[i] = h->delayed_pic[i+1];
-        }
-
-        if(prev == out)
-            *data_size = 0;
-        else
-            *data_size = sizeof(AVFrame);
-        if(prev && prev != out && prev->reference == 1)
-            prev->reference = 0;
-        h->delayed_output_pic = out;
+            if(prev == out)
+                *data_size = 0;
+            else
+                *data_size = sizeof(AVFrame);
+            if(prev && prev != out && prev->reference == 1)
+                prev->reference = 0;
+            h->delayed_output_pic = out;
 #endif
 
-        if(out)
-            *pict= *(AVFrame*)out;
-        else
-            av_log(avctx, AV_LOG_DEBUG, "no picture\n");
+            if(out)
+                *pict= *(AVFrame*)out;
+            else
+                av_log(avctx, AV_LOG_DEBUG, "no picture\n");
+        }
     }
 
     assert(pict->data[0] || !*data_size);
Index: libavcodec/h264.h
===================================================================
--- libavcodec/h264.h	(revision 10526)
+++ libavcodec/h264.h	(working copy)
@@ -59,10 +59,12 @@
 #define MB_MBAFF h->mb_mbaff
 #define MB_FIELD h->mb_field_decoding_flag
 #define FRAME_MBAFF h->mb_aff_frame
+#define FIELD_PICTURE (s->picture_structure != PICT_FRAME)
 #else
 #define MB_MBAFF 0
 #define MB_FIELD 0
 #define FRAME_MBAFF 0
+#define FIELD_PICTURE 0
 #undef  IS_INTERLACED
 #define IS_INTERLACED(mb_type) 0
 #endif
@@ -84,8 +86,8 @@
     int poc_cycle_length;              ///< num_ref_frames_in_pic_order_cnt_cycle
     int ref_frame_count;               ///< num_ref_frames
     int gaps_in_frame_num_allowed_flag;
-    int mb_width;                      ///< frame_width_in_mbs_minus1 + 1
-    int mb_height;                     ///< frame_height_in_mbs_minus1 + 1
+    int mb_width;                      ///< pic_width_in_mbs_minus1 + 1
+    int mb_height;                     ///< pic_height_in_map_units_minus1 + 1
     int frame_mbs_only_flag;
     int mb_aff;                        ///<mb_adaptive_frame_field_flag
     int direct_8x8_inference_flag;
@@ -151,8 +153,8 @@
  */
 typedef struct MMCO{
     MMCOOpcode opcode;
-    int short_frame_num;
-    int long_index;
+    int short_pic_num;
+    int long_arg;  ///< index, pic_num, or num long refs depending on opcode
 } MMCO;
 
 /**
@@ -283,7 +285,7 @@
     int prev_frame_num;           ///< frame_num of the last pic for POC type 1/2
 
     /**
-     * frame_num for frames or 2*frame_num for field pics.
+     * frame_num for frames or 2*frame_num+1 for field pics.
      */
     int curr_pic_num;
 
@@ -323,8 +325,9 @@
     unsigned int list_count;
     Picture *short_ref[32];
     Picture *long_ref[32];
-    Picture default_ref_list[2][32];
+    Picture default_ref_list[2][32]; ///< base reference list for all slices of a coded picture
     Picture ref_list[2][48];     ///< 0..15: frame refs, 16..47: mbaff field refs
+                                 ///< Reordered version of default_ref_list according to picture reordering in slice header
     Picture *delayed_pic[18]; //FIXME size?
     Picture *delayed_output_pic;
 
Index: libavcodec/mpegvideo.c
===================================================================
--- libavcodec/mpegvideo.c	(revision 10526)
+++ libavcodec/mpegvideo.c	(working copy)
@@ -949,7 +949,7 @@
 
     assert(s->pict_type == I_TYPE || (s->last_picture_ptr && s->last_picture_ptr->data[0]));
 
-    if(s->picture_structure!=PICT_FRAME){
+    if(s->picture_structure!=PICT_FRAME && s->out_format != FMT_H264){
         int i;
         for(i=0; i<4; i++){
             if(s->picture_structure == PICT_BOTTOM_FIELD){
Index: libavcodec/mpegvideo.h
===================================================================
--- libavcodec/mpegvideo.h	(revision 10526)
+++ libavcodec/mpegvideo.h	(working copy)
@@ -138,8 +138,9 @@
 
     int field_poc[2];           ///< h264 top/bottom POC
     int poc;                    ///< h264 frame POC
-    int frame_num;              ///< h264 frame_num
-    int pic_id;                 ///< h264 pic_num or long_term_pic_idx
+    int valid_structure;        ///< h264 one of PICT_XXXX, stating which fields are referenced
+    int frame_num;              ///< h264 frame_num (raw frame_num from slice header)
+    int pic_id;                 ///< h264 pic_num (short or long term)
     int long_ref;               ///< 1->long term reference 0->short term reference
     int ref_poc[2][16];         ///< h264 POCs of the frames used as reference
     int ref_count[2];           ///< number of entries in ref_poc
@@ -622,9 +623,9 @@
     int mpeg_f_code[2][2];
     int picture_structure;
 /* picture type */
-#define PICT_TOP_FIELD     1
-#define PICT_BOTTOM_FIELD  2
-#define PICT_FRAME         3
+#define PICT_TOP_FIELD     0x1
+#define PICT_BOTTOM_FIELD  0x2
+#define PICT_FRAME         (PICT_TOP_FIELD | PICT_BOTTOM_FIELD)
 
     int intra_dc_precision;
     int frame_pred_frame_dct;



More information about the ffmpeg-devel mailing list