From bad446e251405dc250c3cbee199072e083a1e4b9 Mon Sep 17 00:00:00 2001 From: "Ronald S. Bultje" Date: Sun, 13 Jan 2013 21:46:44 -0800 Subject: [PATCH 1/4] h264: don't clobber mmco opcode tables for non-first slice headers. Clobbering these tables will temporarily clobber the template used as a basis for other threads to start decoding from. If the other decoding thread updates from the template right at that moment, subsequent threads will get invalid (or, usually, none at all) mmco tables. This leads to invalid reference lists and subsequent decode failures. Therefore, instead, decode the mmco tables only for the first slice in a field or frame. For other slices, decode the bits and ensure they are identical to the mmco tables in the first slice, but don't ever clobber the context state. This prevents other threads from using a clobbered/invalid template as starting point for decoding, and thus fixes decoding in these cases. This fixes occasional (~1%) failures of h264-conformance-mr1_bt_a with frame-multithreading enabled. Signed-off-by: Luca Barbato --- libavcodec/h264.c | 12 +++- libavcodec/h264.h | 5 +- libavcodec/h264_refs.c | 143 +++++++++++++++++++++++++++++------------ 3 files changed, 114 insertions(+), 46 deletions(-) diff --git a/libavcodec/h264.c b/libavcodec/h264.c index f1cac2cac1..d2bbe465eb 100644 --- a/libavcodec/h264.c +++ b/libavcodec/h264.c @@ -2904,7 +2904,7 @@ static int decode_slice_header(H264Context *h, H264Context *h0) s->current_picture_ptr->frame_num = h->prev_frame_num; ff_thread_report_progress(&s->current_picture_ptr->f, INT_MAX, 0); ff_thread_report_progress(&s->current_picture_ptr->f, INT_MAX, 1); - ff_generate_sliding_window_mmcos(h); + ff_generate_sliding_window_mmcos(h, 1); if (ff_h264_execute_ref_pic_marking(h, h->mmco, h->mmco_index) < 0 && (s->avctx->err_recognition & AV_EF_EXPLODE)) return AVERROR_INVALIDDATA; @@ -3082,7 +3082,15 @@ static int decode_slice_header(H264Context *h, H264Context *h0) } } - if (h->nal_ref_idc && ff_h264_decode_ref_pic_marking(h0, &s->gb) < 0 && + // If frame-mt is enabled, only update mmco tables for the first slice + // in a field. Subsequent slices can temporarily clobber h->mmco_index + // or h->mmco, which will cause ref list mix-ups and decoding errors + // further down the line. This may break decoding if the first slice is + // corrupt, thus we only do this if frame-mt is enabled. + if (h->nal_ref_idc && + ff_h264_decode_ref_pic_marking(h0, &s->gb, + !(s->avctx->active_thread_type & FF_THREAD_FRAME) || + h0->current_slice == 0) < 0 && (s->avctx->err_recognition & AV_EF_EXPLODE)) return AVERROR_INVALIDDATA; diff --git a/libavcodec/h264.h b/libavcodec/h264.h index 8596121aab..ad4732e1df 100644 --- a/libavcodec/h264.h +++ b/libavcodec/h264.h @@ -645,9 +645,10 @@ void ff_h264_remove_all_refs(H264Context *h); */ int ff_h264_execute_ref_pic_marking(H264Context *h, MMCO *mmco, int mmco_count); -int ff_h264_decode_ref_pic_marking(H264Context *h, GetBitContext *gb); +int ff_h264_decode_ref_pic_marking(H264Context *h, GetBitContext *gb, + int first_slice); -void ff_generate_sliding_window_mmcos(H264Context *h); +void ff_generate_sliding_window_mmcos(H264Context *h, int first_slice); /** * Check if the top & left blocks are available if needed & change the diff --git a/libavcodec/h264_refs.c b/libavcodec/h264_refs.c index 2a71ac1f06..62c2a5758e 100644 --- a/libavcodec/h264_refs.c +++ b/libavcodec/h264_refs.c @@ -476,23 +476,51 @@ static void print_long_term(H264Context *h) { } } -void ff_generate_sliding_window_mmcos(H264Context *h) { +static int check_opcodes(MMCO *mmco1, MMCO *mmco2, int n_mmcos) +{ + int i; + + for (i = 0; i < n_mmcos; i++) { + if (mmco1[i].opcode != mmco2[i].opcode) + return -1; + } + + return 0; +} + +void ff_generate_sliding_window_mmcos(H264Context *h, int first_slice) +{ MpegEncContext * const s = &h->s; + MMCO mmco_temp[MAX_MMCO_COUNT], *mmco = first_slice ? h->mmco : mmco_temp; + int mmco_index = 0, i; + assert(h->long_ref_count + h->short_ref_count <= h->sps.ref_frame_count); - h->mmco_index= 0; - if(h->short_ref_count && h->long_ref_count + h->short_ref_count == h->sps.ref_frame_count && - !(FIELD_PICTURE && !s->first_field && s->current_picture_ptr->f.reference)) { - h->mmco[0].opcode= MMCO_SHORT2UNUSED; - h->mmco[0].short_pic_num= h->short_ref[ h->short_ref_count - 1 ]->frame_num; - h->mmco_index= 1; + if (h->short_ref_count && + h->long_ref_count + h->short_ref_count == h->sps.ref_frame_count && + !(FIELD_PICTURE && !s->first_field && + s->current_picture_ptr->f.reference)) { + mmco[0].opcode = MMCO_SHORT2UNUSED; + mmco[0].short_pic_num = h->short_ref[h->short_ref_count - 1]->frame_num; + 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; + mmco[0].short_pic_num *= 2; + mmco[1].opcode = MMCO_SHORT2UNUSED; + mmco[1].short_pic_num = mmco[0].short_pic_num + 1; + mmco_index = 2; } } + + if (first_slice) { + h->mmco_index = mmco_index; + } else if (!first_slice && mmco_index >= 0 && + (mmco_index != h->mmco_index || + (i = check_opcodes(h->mmco, mmco_temp, mmco_index)))) { + av_log(h->s.avctx, AV_LOG_ERROR, + "Inconsistent MMCO state between slices [%d, %d, %d]\n", + mmco_index, h->mmco_index, i); + return AVERROR_INVALIDDATA; + } } int ff_h264_execute_ref_pic_marking(H264Context *h, MMCO *mmco, int mmco_count){ @@ -654,52 +682,83 @@ int ff_h264_execute_ref_pic_marking(H264Context *h, MMCO *mmco, int mmco_count){ return (h->s.avctx->err_recognition & AV_EF_EXPLODE) ? err : 0; } -int ff_h264_decode_ref_pic_marking(H264Context *h, GetBitContext *gb){ +int ff_h264_decode_ref_pic_marking(H264Context *h, GetBitContext *gb, + int first_slice) +{ MpegEncContext * const s = &h->s; int i; + MMCO mmco_temp[MAX_MMCO_COUNT], *mmco = first_slice ? h->mmco : mmco_temp; + int mmco_index = 0; - h->mmco_index= 0; - if(h->nal_unit_type == NAL_IDR_SLICE){ //FIXME fields - s->broken_link= get_bits1(gb) -1; - if(get_bits1(gb)){ - h->mmco[0].opcode= MMCO_LONG; - h->mmco[0].long_arg= 0; - h->mmco_index= 1; + if (h->nal_unit_type == NAL_IDR_SLICE){ // FIXME fields + s->broken_link = get_bits1(gb) - 1; + if (get_bits1(gb)){ + mmco[0].opcode = MMCO_LONG; + mmco[0].long_arg = 0; + mmco_index = 1; } - }else{ - if(get_bits1(gb)){ // adaptive_ref_pic_marking_mode_flag - for(i= 0; immco[i].opcode= opcode; - if(opcode==MMCO_SHORT2UNUSED || opcode==MMCO_SHORT2LONG){ - h->mmco[i].short_pic_num= (h->curr_pic_num - get_ue_golomb(gb) - 1) & (h->max_pic_num - 1); -/* if(h->mmco[i].short_pic_num >= h->short_ref_count || h->short_ref[ h->mmco[i].short_pic_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_arg= get_ue_golomb_31(gb); - if(long_arg >= 32 || (long_arg >= 16 && !(opcode == MMCO_SET_MAX_LONG && 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); + mmco[i].opcode = opcode; + if (opcode == MMCO_SHORT2UNUSED || opcode == MMCO_SHORT2LONG){ + mmco[i].short_pic_num = + (h->curr_pic_num - get_ue_golomb(gb) - 1) & + (h->max_pic_num - 1); +#if 0 + if (mmco[i].short_pic_num >= h->short_ref_count || + h->short_ref[ mmco[i].short_pic_num ] == NULL){ + av_log(s->avctx, AV_LOG_ERROR, + "illegal short ref in memory management control " + "operation %d\n", mmco); return -1; } - h->mmco[i].long_arg= long_arg; +#endif + } + if (opcode == MMCO_SHORT2LONG || opcode == MMCO_LONG2UNUSED || + opcode == MMCO_LONG || opcode == MMCO_SET_MAX_LONG) { + unsigned int long_arg = get_ue_golomb_31(gb); + if (long_arg >= 32 || + (long_arg >= 16 && !(opcode == MMCO_SET_MAX_LONG && + 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; + } + mmco[i].long_arg = long_arg; } - if(opcode > (unsigned)MMCO_LONG){ - av_log(h->s.avctx, AV_LOG_ERROR, "illegal memory management control operation %d\n", opcode); + if (opcode > (unsigned) MMCO_LONG){ + av_log(h->s.avctx, AV_LOG_ERROR, + "illegal memory management control operation %d\n", + opcode); return -1; } - if(opcode == MMCO_END) + if (opcode == MMCO_END) break; } - h->mmco_index= i; - }else{ - ff_generate_sliding_window_mmcos(h); + mmco_index = i; + } else { + if (first_slice) + ff_generate_sliding_window_mmcos(h, first_slice); + mmco_index = -1; } } + if (first_slice && mmco_index != -1) { + h->mmco_index = mmco_index; + } else if (!first_slice && mmco_index >= 0 && + (mmco_index != h->mmco_index || + (i = check_opcodes(h->mmco, mmco_temp, mmco_index)))) { + av_log(h->s.avctx, AV_LOG_ERROR, + "Inconsistent MMCO state between slices [%d, %d, %d]\n", + mmco_index, h->mmco_index, i); + return AVERROR_INVALIDDATA; + } + return 0; } From 39403c6c1baf9035d376bf4d7d5b196a6006ce27 Mon Sep 17 00:00:00 2001 From: Giorgio Vazzana Date: Fri, 5 Oct 2012 13:37:20 +0200 Subject: [PATCH 2/4] oggparsetheora: fix comment header parsing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pass the correct header size to ff_vorbis_comment() Signed-off-by: Martin Storsjö --- libavformat/oggparsetheora.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavformat/oggparsetheora.c b/libavformat/oggparsetheora.c index dfb73c9bd1..ed31d539d9 100644 --- a/libavformat/oggparsetheora.c +++ b/libavformat/oggparsetheora.c @@ -114,7 +114,7 @@ theora_header (AVFormatContext * s, int idx) } break; case 0x81: - ff_vorbis_comment(s, &st->metadata, os->buf + os->pstart + 7, os->psize - 8); + ff_vorbis_comment(s, &st->metadata, os->buf + os->pstart + 7, os->psize - 7); case 0x82: if (!thp->version) return -1; From 055b37308080d1143b69a0dc488f63b2ea1d0043 Mon Sep 17 00:00:00 2001 From: Maximilian Seesslen Date: Fri, 4 Jan 2013 16:56:00 +0100 Subject: [PATCH 3/4] libtheoraenc: fix granularity of video quality MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The floating point version of av_clip has to be used when converting the quality level. Signed-off-by: Maximilian Seesslen Signed-off-by: Martin Storsjö --- libavcodec/libtheoraenc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavcodec/libtheoraenc.c b/libavcodec/libtheoraenc.c index f20fabb8d6..3990692145 100644 --- a/libavcodec/libtheoraenc.c +++ b/libavcodec/libtheoraenc.c @@ -207,7 +207,7 @@ static av_cold int encode_init(AVCodecContext* avc_context) * 0 <= p <=63 * an int value */ - t_info.quality = av_clip(avc_context->global_quality / (float)FF_QP2LAMBDA, 0, 10) * 6.3; + t_info.quality = av_clipf(avc_context->global_quality / (float)FF_QP2LAMBDA, 0, 10) * 6.3; t_info.target_bitrate = 0; } else { t_info.target_bitrate = avc_context->bit_rate; From 5e753ed502d3597077d8675ca1438e1bcade1459 Mon Sep 17 00:00:00 2001 From: Sean McGovern Date: Mon, 14 Jan 2013 12:51:59 -0500 Subject: [PATCH 4/4] suncc: Replace more GCC flags by their equivalents in suncc_flags() Signed-off-by: Diego Biurrun --- configure | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 554d578bb9..3d5fe7cd4f 100755 --- a/configure +++ b/configure @@ -2241,7 +2241,8 @@ suncc_flags(){ -fomit-frame-pointer) echo -xregs=frameptr ;; -fPIC) echo -KPIC -xcode=pic32 ;; -W*,*) echo $flag ;; - -f*-*|-W*) ;; + -f*-*|-W*|-mimpure-text) ;; + -shared) echo -G ;; *) echo $flag ;; esac done