summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Downs <heydowns@borg.com>2007-10-08 17:44:38 +0000
committerAndreas Ă–man <andreas@lonelycoder.com>2007-10-08 17:44:38 +0000
commit12d96de3acf660d53d6931e2045ec21fd8ae718f (patch)
treea3bee9fe82e500e22b96d2876287ed61bdcf7dab
parentac6b423b0c070f34de2b6a8df7913c6fe7aaa0de (diff)
Manage Picture buffers for fields as well as frames. Pair complementary fields into one MPV Picture.
Part of PAFF implementation. patch by Jeff Downs, heydowns a borg d com original thread: Subject: [FFmpeg-devel] [PATCH] Implement PAFF in H.264 Date: 18/09/07 20:30 Originally committed as revision 10691 to svn://svn.ffmpeg.org/ffmpeg/trunk
-rw-r--r--libavcodec/h264.c75
-rw-r--r--libavcodec/mpegvideo.c2
2 files changed, 74 insertions, 3 deletions
diff --git a/libavcodec/h264.c b/libavcodec/h264.c
index cfc8de7771..752f2d236f 100644
--- a/libavcodec/h264.c
+++ b/libavcodec/h264.c
@@ -3339,6 +3339,7 @@ static void flush_dpb(AVCodecContext *avctx){
idr(h);
if(h->s.current_picture_ptr)
h->s.current_picture_ptr->reference= 0;
+ h->s.first_field= 0;
}
/**
@@ -3830,6 +3831,7 @@ static void clone_slice(H264Context *dst, H264Context *src)
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;
@@ -3857,12 +3859,14 @@ static void clone_slice(H264Context *dst, H264Context *src)
*/
static int decode_slice_header(H264Context *h, H264Context *h0){
MpegEncContext * const s = &h->s;
+ MpegEncContext * const s0 = &h0->s;
unsigned int first_mb_in_slice;
unsigned int pps_id;
int num_ref_idx_active_override_flag;
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->dropable= h->nal_ref_idc == 0;
@@ -3870,6 +3874,7 @@ static int decode_slice_header(H264Context *h, H264Context *h0){
if((s->flags2 & CODEC_FLAG2_CHUNKS) && first_mb_in_slice == 0){
h0->current_slice = 0;
+ if (!s0->first_field)
s->current_picture_ptr= NULL;
}
@@ -3939,6 +3944,7 @@ static int decode_slice_header(H264Context *h, H264Context *h0){
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);
@@ -3977,6 +3983,7 @@ static int decode_slice_header(H264Context *h, H264Context *h0){
h->mb_mbaff = 0;
h->mb_aff_frame = 0;
+ last_pic_structure = s0->picture_structure;
if(h->sps.frame_mbs_only_flag){
s->picture_structure= PICT_FRAME;
}else{
@@ -3990,8 +3997,50 @@ static int decode_slice_header(H264Context *h, H264Context *h0){
}
if(h0->current_slice == 0){
- if(frame_start(h) < 0)
+ /* See if we have a decoded first field looking for a pair... */
+ if (s0->first_field) {
+ assert(s0->current_picture_ptr);
+ assert(s0->current_picture_ptr->data[0]);
+ assert(s0->current_picture_ptr->reference != DELAYED_PIC_REF);
+
+ /* figure out if we have a complementary field pair */
+ if (!FIELD_PICTURE || s->picture_structure == last_pic_structure) {
+ /*
+ * Previous field is unmatched. Don't display it, but let it
+ * remain for reference if marked as such.
+ */
+ s0->current_picture_ptr = NULL;
+ s0->first_field = FIELD_PICTURE;
+
+ } else {
+ if (h->nal_ref_idc &&
+ s0->current_picture_ptr->reference &&
+ s0->current_picture_ptr->frame_num != h->frame_num) {
+ /*
+ * This and previous field were reference, but had
+ * different frame_nums. Consider this field first in
+ * pair. Throw away previous field except for reference
+ * purposes.
+ */
+ s0->first_field = 1;
+ s0->current_picture_ptr = NULL;
+
+ } else {
+ /* Second field in complementary pair */
+ s0->first_field = 0;
+ }
+ }
+
+ } else {
+ /* Frame or first field in a potentially complementary pair */
+ assert(!s0->current_picture_ptr);
+ s0->first_field = FIELD_PICTURE;
+ }
+
+ if((!FIELD_PICTURE || s0->first_field) && frame_start(h) < 0) {
+ s0->first_field = 0;
return -1;
+ }
}
if(h != h0)
clone_slice(h, h0);
@@ -7363,6 +7412,8 @@ static void execute_decode_slices(H264Context *h, int context_count){
hx = h->thread_context[context_count - 1];
s->mb_x = hx->s.mb_x;
s->mb_y = hx->s.mb_y;
+ s->dropable = hx->s.dropable;
+ s->picture_structure = hx->s.picture_structure;
for(i = 1; i < context_count; i++)
h->s.error_count += h->thread_context[i]->s.error_count;
}
@@ -7385,6 +7436,7 @@ static int decode_nal_units(H264Context *h, uint8_t *buf, int buf_size){
#endif
if(!(s->flags2 & CODEC_FLAG2_CHUNKS)){
h->current_slice = 0;
+ if (!s->first_field)
s->current_picture_ptr= NULL;
}
@@ -7682,16 +7734,34 @@ static int decode_frame(AVCodecContext *avctx,
h->prev_frame_num_offset= h->frame_num_offset;
h->prev_frame_num= h->frame_num;
- if(s->current_picture_ptr->reference & s->picture_structure){
+ if(!s->dropable) {
h->prev_poc_msb= h->poc_msb;
h->prev_poc_lsb= h->poc_lsb;
execute_ref_pic_marking(h, h->mmco, h->mmco_index);
}
+ /*
+ * FIXME: Error handling code does not seem to support interlaced
+ * when slices span multiple rows
+ * The ff_er_add_slice calls don't work right for bottom
+ * fields; they cause massive erroneous error concealing
+ * Error marking covers 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 is
+ * past end by one (callers fault) and resync_mb_y != 0
+ * causes problems for the first MB line, too.
+ */
+ if (!FIELD_PICTURE)
ff_er_frame_end(s);
MPV_frame_end(s);
+ if (s->first_field) {
+ /* Wait for second field. */
+ *data_size = 0;
+
+ } else {
//FIXME do something with unavailable reference frames
#if 0 //decode order
@@ -7762,6 +7832,7 @@ static int decode_frame(AVCodecContext *avctx,
*pict= *(AVFrame*)out;
else
av_log(avctx, AV_LOG_DEBUG, "no picture\n");
+ }
}
assert(pict->data[0] || !*data_size);
diff --git a/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c
index b73ccbd63b..7a14dc1413 100644
--- a/libavcodec/mpegvideo.c
+++ b/libavcodec/mpegvideo.c
@@ -954,7 +954,7 @@ alloc:
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){