aboutsummaryrefslogtreecommitdiffstats
path: root/libavcodec/h264.c
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 /libavcodec/h264.c
parentac6b423b0c070f34de2b6a8df7913c6fe7aaa0de (diff)
downloadffmpeg-12d96de3acf660d53d6931e2045ec21fd8ae718f.tar.gz
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
Diffstat (limited to 'libavcodec/h264.c')
-rw-r--r--libavcodec/h264.c75
1 files changed, 73 insertions, 2 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);