From 8d36932c8d33f93ce1afdd5c1f402e7b6655d5ae Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Tue, 17 May 2016 14:51:01 +0200 Subject: [PATCH 01/71] h264: move the block starting a new field out of slice_header_parse() There is no bitstream parsing in that block and messing with decoder-global state is not something that belongs into header parsing. Nothing else in this function depends on the value of current_slice, except for two validity checks. Those checks are also moved out of slice_header_parse(). --- libavcodec/h264_slice.c | 68 ++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index 17608b455acfc..c43a0beca09ef 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -1177,21 +1177,6 @@ static int h264_slice_header_parse(H264Context *h, H264SliceContext *sl, sl->first_mb_addr = get_ue_golomb(&sl->gb); - if (sl->first_mb_addr == 0) { // FIXME better field boundary detection - if (h->current_slice && h->cur_pic_ptr && FIELD_PICTURE(h)) { - ff_h264_field_end(h, sl, 1); - } - - h->current_slice = 0; - if (!h->first_field) { - if (h->cur_pic_ptr && !h->droppable) { - ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX, - h->picture_structure == PICT_BOTTOM_FIELD); - } - h->cur_pic_ptr = NULL; - } - } - slice_type = get_ue_golomb_31(&sl->gb); if (slice_type > 9) { av_log(h->avctx, AV_LOG_ERROR, @@ -1226,11 +1211,6 @@ static int h264_slice_header_parse(H264Context *h, H264SliceContext *sl, sl->pps_id); return AVERROR_INVALIDDATA; } - if (h->current_slice > 0 && - h->ps.pps != (const PPS*)h->ps.pps_list[sl->pps_id]->data) { - av_log(h->avctx, AV_LOG_ERROR, "PPS changed between slices\n"); - return AVERROR_INVALIDDATA; - } pps = (const PPS*)h->ps.pps_list[sl->pps_id]->data; if (!h->ps.sps_list[pps->sps_id]) { @@ -1265,21 +1245,6 @@ static int h264_slice_header_parse(H264Context *h, H264SliceContext *sl, sl->picture_structure = picture_structure; sl->mb_field_decoding_flag = picture_structure != PICT_FRAME; - if (h->current_slice != 0) { - if (h->picture_structure != picture_structure || - h->droppable != droppable) { - av_log(h->avctx, AV_LOG_ERROR, - "Changing field mode (%d -> %d) between slices is not allowed\n", - h->picture_structure, picture_structure); - return AVERROR_INVALIDDATA; - } else if (!h->cur_pic_ptr) { - av_log(h->avctx, AV_LOG_ERROR, - "unset cur_pic_ptr on slice %d\n", - h->current_slice + 1); - return AVERROR_INVALIDDATA; - } - } - if (picture_structure == PICT_FRAME) { h->curr_pic_num = h->poc.frame_num; h->max_pic_num = 1 << sps->log2_max_frame_num; @@ -1430,10 +1395,43 @@ int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl, if (ret < 0) return ret; + if (sl->first_mb_addr == 0) { // FIXME better field boundary detection + if (h->current_slice && h->cur_pic_ptr && FIELD_PICTURE(h)) { + ff_h264_field_end(h, sl, 1); + } + + h->current_slice = 0; + if (!h->first_field) { + if (h->cur_pic_ptr && !h->droppable) { + ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX, + h->picture_structure == PICT_BOTTOM_FIELD); + } + h->cur_pic_ptr = NULL; + } + } + if (h->current_slice == 0) { ret = h264_field_start(h, sl, nal); if (ret < 0) return ret; + } else { + if (h->ps.pps != (const PPS*)h->ps.pps_list[sl->pps_id]->data) { + av_log(h->avctx, AV_LOG_ERROR, "PPS changed between slices\n"); + return AVERROR_INVALIDDATA; + } + + if (h->picture_structure != sl->picture_structure || + h->droppable != (nal->ref_idc == 0)) { + av_log(h->avctx, AV_LOG_ERROR, + "Changing field mode (%d -> %d) between slices is not allowed\n", + h->picture_structure, sl->picture_structure); + return AVERROR_INVALIDDATA; + } else if (!h->cur_pic_ptr) { + av_log(h->avctx, AV_LOG_ERROR, + "unset cur_pic_ptr on slice %d\n", + h->current_slice + 1); + return AVERROR_INVALIDDATA; + } } assert(h->mb_num == h->mb_width * h->mb_height); From 54dd9b1cdd9e54f1ee39ae25af0324f8aba2831b Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Tue, 17 May 2016 15:07:23 +0200 Subject: [PATCH 02/71] h264: set mb_aff_frame in frame_start() Avoid unnecessary modification of the decoder-global state in per-slice code. --- libavcodec/h264_slice.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index c43a0beca09ef..4b0adab110373 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -377,6 +377,7 @@ int ff_h264_update_thread_context(AVCodecContext *dst, h->coded_picture_number = h1->coded_picture_number; h->first_field = h1->first_field; h->picture_structure = h1->picture_structure; + h->mb_aff_frame = h1->mb_aff_frame; h->droppable = h1->droppable; for (i = 0; i < H264_MAX_PICTURE_COUNT; i++) { @@ -501,6 +502,8 @@ static int h264_frame_start(H264Context *h) h->postpone_filter = 0; + h->mb_aff_frame = h->ps.sps->mb_aff && (h->picture_structure == PICT_FRAME); + assert(h->cur_pic_ptr->long_ref == 0); return 0; @@ -1173,7 +1176,6 @@ static int h264_slice_header_parse(H264Context *h, H264SliceContext *sl, unsigned int slice_type, tmp, i; int field_pic_flag, bottom_field_flag; int frame_num, droppable, picture_structure; - int mb_aff_frame = 0; sl->first_mb_addr = get_ue_golomb(&sl->gb); @@ -1236,12 +1238,8 @@ static int h264_slice_header_parse(H264Context *h, H264SliceContext *sl, picture_structure = PICT_TOP_FIELD + bottom_field_flag; } else { picture_structure = PICT_FRAME; - mb_aff_frame = sps->mb_aff; } } - if (!h->setup_finished) { - h->mb_aff_frame = mb_aff_frame; - } sl->picture_structure = picture_structure; sl->mb_field_decoding_flag = picture_structure != PICT_FRAME; From f966498e433fead2f5e6b5b66fad2ac062146d22 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Tue, 17 May 2016 15:35:50 +0200 Subject: [PATCH 03/71] h264: decode the poc values from the slice header into the per-slice context Copy them into the decoder-global context in field_start(). This avoids modifying the decoder-global context during bitstream parsing. --- libavcodec/h264.h | 5 +++++ libavcodec/h264_slice.c | 41 ++++++++++++++++------------------------- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/libavcodec/h264.h b/libavcodec/h264.h index 6cd2506e6f047..4a109e119c2c5 100644 --- a/libavcodec/h264.h +++ b/libavcodec/h264.h @@ -446,6 +446,11 @@ typedef struct H264SliceContext { MMCO mmco[MAX_MMCO_COUNT]; int nb_mmco; int explicit_ref_marking; + + int frame_num; + int poc_lsb; + int delta_poc_bottom; + int delta_poc[2]; } H264SliceContext; /** diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index 4b0adab110373..be44e66b3ea28 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -1009,6 +1009,12 @@ static int h264_field_start(H264Context *h, const H264SliceContext *sl, h->droppable = (nal->ref_idc == 0); h->picture_structure = sl->picture_structure; + h->poc.frame_num = sl->frame_num; + h->poc.poc_lsb = sl->poc_lsb; + h->poc.delta_poc_bottom = sl->delta_poc_bottom; + h->poc.delta_poc[0] = sl->delta_poc[0]; + h->poc.delta_poc[1] = sl->delta_poc[1]; + /* Shorten frame num gaps so we don't have to allocate reference * frames just to throw them away */ if (h->poc.frame_num != h->poc.prev_frame_num) { @@ -1175,7 +1181,7 @@ static int h264_slice_header_parse(H264Context *h, H264SliceContext *sl, int ret; unsigned int slice_type, tmp, i; int field_pic_flag, bottom_field_flag; - int frame_num, droppable, picture_structure; + int droppable, picture_structure; sl->first_mb_addr = get_ue_golomb(&sl->gb); @@ -1222,9 +1228,7 @@ static int h264_slice_header_parse(H264Context *h, H264SliceContext *sl, } sps = (const SPS*)h->ps.sps_list[pps->sps_id]->data; - frame_num = get_bits(&sl->gb, sps->log2_max_frame_num); - if (!h->setup_finished) - h->poc.frame_num = frame_num; + sl->frame_num = get_bits(&sl->gb, sps->log2_max_frame_num); sl->mb_mbaff = 0; @@ -1244,10 +1248,10 @@ static int h264_slice_header_parse(H264Context *h, H264SliceContext *sl, sl->mb_field_decoding_flag = picture_structure != PICT_FRAME; if (picture_structure == PICT_FRAME) { - h->curr_pic_num = h->poc.frame_num; + h->curr_pic_num = sl->frame_num; h->max_pic_num = 1 << sps->log2_max_frame_num; } else { - h->curr_pic_num = 2 * h->poc.frame_num + 1; + h->curr_pic_num = 2 * sl->frame_num + 1; h->max_pic_num = 1 << (sps->log2_max_frame_num + 1); } @@ -1255,30 +1259,17 @@ static int h264_slice_header_parse(H264Context *h, H264SliceContext *sl, get_ue_golomb(&sl->gb); /* idr_pic_id */ if (sps->poc_type == 0) { - int poc_lsb = get_bits(&sl->gb, sps->log2_max_poc_lsb); - - if (!h->setup_finished) - h->poc.poc_lsb = poc_lsb; + sl->poc_lsb = get_bits(&sl->gb, sps->log2_max_poc_lsb); - if (pps->pic_order_present == 1 && picture_structure == PICT_FRAME) { - int delta_poc_bottom = get_se_golomb(&sl->gb); - if (!h->setup_finished) - h->poc.delta_poc_bottom = delta_poc_bottom; - } + if (pps->pic_order_present == 1 && picture_structure == PICT_FRAME) + sl->delta_poc_bottom = get_se_golomb(&sl->gb); } if (sps->poc_type == 1 && !sps->delta_pic_order_always_zero_flag) { - int delta_poc = get_se_golomb(&sl->gb); + sl->delta_poc[0] = get_se_golomb(&sl->gb); - if (!h->setup_finished) - h->poc.delta_poc[0] = delta_poc; - - if (pps->pic_order_present == 1 && picture_structure == PICT_FRAME) { - delta_poc = get_se_golomb(&sl->gb); - - if (!h->setup_finished) - h->poc.delta_poc[1] = delta_poc; - } + if (pps->pic_order_present == 1 && picture_structure == PICT_FRAME) + sl->delta_poc[1] = get_se_golomb(&sl->gb); } if (pps->redundant_pic_cnt_present) From debca90863e4ee53447efd02483c500f89766384 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Tue, 17 May 2016 16:45:15 +0200 Subject: [PATCH 04/71] h264: store {curr,max}_pic_num in the per-slice context While the value of those variables will be constant for the whole frame, they are only used in two functions called from slice header decoding. Moving them to the per-slice context allows us to make the H264Context passed to slice_header_parse() constant. --- libavcodec/h264.h | 12 ++---------- libavcodec/h264_refs.c | 10 +++++----- libavcodec/h264_slice.c | 13 +++++-------- 3 files changed, 12 insertions(+), 23 deletions(-) diff --git a/libavcodec/h264.h b/libavcodec/h264.h index 4a109e119c2c5..cc7dd7ffea521 100644 --- a/libavcodec/h264.h +++ b/libavcodec/h264.h @@ -451,6 +451,8 @@ typedef struct H264SliceContext { int poc_lsb; int delta_poc_bottom; int delta_poc[2]; + int curr_pic_num; + int max_pic_num; } H264SliceContext; /** @@ -565,16 +567,6 @@ typedef struct H264Context { H264POCContext poc; - /** - * frame_num for frames or 2 * frame_num + 1 for field pics. - */ - int curr_pic_num; - - /** - * max_frame_num or 2 * max_frame_num for field pics. - */ - int max_pic_num; - H264Picture *short_ref[32]; H264Picture *long_ref[32]; H264Picture *delayed_pic[MAX_DELAYED_PIC_COUNT + 2]; // FIXME size? diff --git a/libavcodec/h264_refs.c b/libavcodec/h264_refs.c index 2e43a8f4e543c..f7b7211a5c226 100644 --- a/libavcodec/h264_refs.c +++ b/libavcodec/h264_refs.c @@ -262,7 +262,7 @@ int ff_h264_build_ref_list(const H264Context *h, H264SliceContext *sl) h264_initialise_ref_list(h, sl); for (list = 0; list < sl->list_count; list++) { - int pred = h->curr_pic_num; + int pred = sl->curr_pic_num; for (index = 0; index < sl->nb_ref_modifications[list]; index++) { unsigned int modification_of_pic_nums_idc = sl->ref_modifications[list][index].op; @@ -277,7 +277,7 @@ int ff_h264_build_ref_list(const H264Context *h, H264SliceContext *sl) const unsigned int abs_diff_pic_num = val + 1; int frame_num; - if (abs_diff_pic_num > h->max_pic_num) { + if (abs_diff_pic_num > sl->max_pic_num) { av_log(h->avctx, AV_LOG_ERROR, "abs_diff_pic_num overflow\n"); return AVERROR_INVALIDDATA; @@ -287,7 +287,7 @@ int ff_h264_build_ref_list(const H264Context *h, H264SliceContext *sl) pred -= abs_diff_pic_num; else pred += abs_diff_pic_num; - pred &= h->max_pic_num - 1; + pred &= sl->max_pic_num - 1; frame_num = pic_num_extract(h, pred, &pic_structure); @@ -751,8 +751,8 @@ int ff_h264_decode_ref_pic_marking(const H264Context *h, H264SliceContext *sl, 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); + (sl->curr_pic_num - get_ue_golomb(gb) - 1) & + (sl->max_pic_num - 1); #if 0 if (mmco[i].short_pic_num >= h->short_ref_count || !h->short_ref[mmco[i].short_pic_num]) { diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index be44e66b3ea28..d9268840bffc5 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -405,9 +405,6 @@ int ff_h264_update_thread_context(AVCodecContext *dst, memcpy(&h->poc, &h1->poc, sizeof(h->poc)); - h->curr_pic_num = h1->curr_pic_num; - h->max_pic_num = h1->max_pic_num; - memcpy(h->short_ref, h1->short_ref, sizeof(h->short_ref)); memcpy(h->long_ref, h1->long_ref, sizeof(h->long_ref)); memcpy(h->delayed_pic, h1->delayed_pic, sizeof(h->delayed_pic)); @@ -1173,7 +1170,7 @@ static int h264_field_start(H264Context *h, const H264SliceContext *sl, return 0; } -static int h264_slice_header_parse(H264Context *h, H264SliceContext *sl, +static int h264_slice_header_parse(const H264Context *h, H264SliceContext *sl, const H2645NAL *nal) { const SPS *sps; @@ -1248,11 +1245,11 @@ static int h264_slice_header_parse(H264Context *h, H264SliceContext *sl, sl->mb_field_decoding_flag = picture_structure != PICT_FRAME; if (picture_structure == PICT_FRAME) { - h->curr_pic_num = sl->frame_num; - h->max_pic_num = 1 << sps->log2_max_frame_num; + sl->curr_pic_num = sl->frame_num; + sl->max_pic_num = 1 << sps->log2_max_frame_num; } else { - h->curr_pic_num = 2 * sl->frame_num + 1; - h->max_pic_num = 1 << (sps->log2_max_frame_num + 1); + sl->curr_pic_num = 2 * sl->frame_num + 1; + sl->max_pic_num = 1 << (sps->log2_max_frame_num + 1); } if (nal->type == NAL_IDR_SLICE) From 17e7c03e12d1e4490921e7bffaeaa6b46a7ada4e Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Tue, 17 May 2016 18:57:23 +0200 Subject: [PATCH 05/71] h264: only allow ending a field/starting a new one before finish_setup() Doing this after ff_thread_finish_setup() is called is invalid and can conflict with reads from the other thread. --- libavcodec/h264_slice.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index d9268840bffc5..990c85bdba993 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -1381,26 +1381,30 @@ int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl, if (ret < 0) return ret; - if (sl->first_mb_addr == 0) { // FIXME better field boundary detection - if (h->current_slice && h->cur_pic_ptr && FIELD_PICTURE(h)) { - ff_h264_field_end(h, sl, 1); - } + if (!h->setup_finished) { + if (sl->first_mb_addr == 0) { // FIXME better field boundary detection + if (h->current_slice && h->cur_pic_ptr && FIELD_PICTURE(h)) { + ff_h264_field_end(h, sl, 1); + } - h->current_slice = 0; - if (!h->first_field) { - if (h->cur_pic_ptr && !h->droppable) { - ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX, - h->picture_structure == PICT_BOTTOM_FIELD); + h->current_slice = 0; + if (!h->first_field) { + if (h->cur_pic_ptr && !h->droppable) { + ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX, + h->picture_structure == PICT_BOTTOM_FIELD); + } + h->cur_pic_ptr = NULL; } - h->cur_pic_ptr = NULL; + } + + if (h->current_slice == 0) { + ret = h264_field_start(h, sl, nal); + if (ret < 0) + return ret; } } - if (h->current_slice == 0) { - ret = h264_field_start(h, sl, nal); - if (ret < 0) - return ret; - } else { + if (h->current_slice > 0) { if (h->ps.pps != (const PPS*)h->ps.pps_list[sl->pps_id]->data) { av_log(h->avctx, AV_LOG_ERROR, "PPS changed between slices\n"); return AVERROR_INVALIDDATA; From bcd91f1644b46dd142c5355c8b742b27d9028903 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Tue, 17 May 2016 19:00:18 +0200 Subject: [PATCH 06/71] h264: move a per-field block from decode_slice_header() to field_start() This is a more appropriate place for it. --- libavcodec/h264_slice.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index 990c85bdba993..ec8a82c0a64a2 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -1167,6 +1167,13 @@ static int h264_field_start(H264Context *h, const H264SliceContext *sl, release_unused_pictures(h, 0); } + ff_h264_init_poc(h->cur_pic_ptr->field_poc, &h->cur_pic_ptr->poc, + h->ps.sps, &h->poc, h->picture_structure, nal->ref_idc); + + memcpy(h->mmco, sl->mmco, sl->nb_mmco * sizeof(*h->mmco)); + h->nb_mmco = sl->nb_mmco; + h->explicit_ref_marking = sl->explicit_ref_marking; + return 0; } @@ -1437,15 +1444,6 @@ int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl, sl->resync_mb_y = sl->mb_y = sl->mb_y + 1; assert(sl->mb_y < h->mb_height); - if (!h->setup_finished) { - ff_h264_init_poc(h->cur_pic_ptr->field_poc, &h->cur_pic_ptr->poc, - h->ps.sps, &h->poc, h->picture_structure, nal->ref_idc); - - memcpy(h->mmco, sl->mmco, sl->nb_mmco * sizeof(*h->mmco)); - h->nb_mmco = sl->nb_mmco; - h->explicit_ref_marking = sl->explicit_ref_marking; - } - ret = ff_h264_build_ref_list(h, sl); if (ret < 0) return ret; From 19446dc5fff6a2f5ccd1a73db66e266255a5d768 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Tue, 17 May 2016 20:01:34 +0200 Subject: [PATCH 07/71] h264: drop unused NAL_FF_IGNORE --- libavcodec/h264.c | 2 -- libavcodec/h264.h | 1 - 2 files changed, 3 deletions(-) diff --git a/libavcodec/h264.c b/libavcodec/h264.c index b96b95a20e145..df7c120c34158 100644 --- a/libavcodec/h264.c +++ b/libavcodec/h264.c @@ -926,8 +926,6 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size) case NAL_SPS_EXT: case NAL_AUXILIARY_SLICE: break; - case NAL_FF_IGNORE: - break; default: av_log(avctx, AV_LOG_DEBUG, "Unknown NAL code: %d (%d bits)\n", nal->type, nal->size_bits); diff --git a/libavcodec/h264.h b/libavcodec/h264.h index cc7dd7ffea521..398a2837b8000 100644 --- a/libavcodec/h264.h +++ b/libavcodec/h264.h @@ -124,7 +124,6 @@ enum { NAL_FILLER_DATA = 12, NAL_SPS_EXT = 13, NAL_AUXILIARY_SLICE = 19, - NAL_FF_IGNORE = 0xff0f001, }; /** From f651c6a259d4bc78f25db11d25df9256d5110bd3 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Wed, 18 May 2016 07:27:32 +0200 Subject: [PATCH 08/71] h264: factor out setting frame properties / side data Right now this code is mixed with selecting the next output frame. Move it to a separate function called from h264_field_start(), which is a more appropriate place for this. --- libavcodec/h264.c | 147 ----------------------------------- libavcodec/h264_slice.c | 166 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 166 insertions(+), 147 deletions(-) diff --git a/libavcodec/h264.c b/libavcodec/h264.c index df7c120c34158..7949ee66ac519 100644 --- a/libavcodec/h264.c +++ b/libavcodec/h264.c @@ -449,153 +449,6 @@ static void decode_postinit(H264Context *h, int setup_finished) return; } - cur->f->interlaced_frame = 0; - cur->f->repeat_pict = 0; - - /* Signal interlacing information externally. */ - /* Prioritize picture timing SEI information over used - * decoding process if it exists. */ - - if (sps->pic_struct_present_flag) { - H264SEIPictureTiming *pt = &h->sei.picture_timing; - switch (pt->pic_struct) { - case SEI_PIC_STRUCT_FRAME: - break; - case SEI_PIC_STRUCT_TOP_FIELD: - case SEI_PIC_STRUCT_BOTTOM_FIELD: - cur->f->interlaced_frame = 1; - break; - case SEI_PIC_STRUCT_TOP_BOTTOM: - case SEI_PIC_STRUCT_BOTTOM_TOP: - if (FIELD_OR_MBAFF_PICTURE(h)) - cur->f->interlaced_frame = 1; - else - // try to flag soft telecine progressive - cur->f->interlaced_frame = h->prev_interlaced_frame; - break; - case SEI_PIC_STRUCT_TOP_BOTTOM_TOP: - case SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM: - /* Signal the possibility of telecined film externally - * (pic_struct 5,6). From these hints, let the applications - * decide if they apply deinterlacing. */ - cur->f->repeat_pict = 1; - break; - case SEI_PIC_STRUCT_FRAME_DOUBLING: - cur->f->repeat_pict = 2; - break; - case SEI_PIC_STRUCT_FRAME_TRIPLING: - cur->f->repeat_pict = 4; - break; - } - - if ((pt->ct_type & 3) && - pt->pic_struct <= SEI_PIC_STRUCT_BOTTOM_TOP) - cur->f->interlaced_frame = (pt->ct_type & (1 << 1)) != 0; - } else { - /* Derive interlacing flag from used decoding process. */ - cur->f->interlaced_frame = FIELD_OR_MBAFF_PICTURE(h); - } - h->prev_interlaced_frame = cur->f->interlaced_frame; - - if (cur->field_poc[0] != cur->field_poc[1]) { - /* Derive top_field_first from field pocs. */ - cur->f->top_field_first = cur->field_poc[0] < cur->field_poc[1]; - } else { - if (cur->f->interlaced_frame || sps->pic_struct_present_flag) { - /* Use picture timing SEI information. Even if it is a - * information of a past frame, better than nothing. */ - if (h->sei.picture_timing.pic_struct == SEI_PIC_STRUCT_TOP_BOTTOM || - h->sei.picture_timing.pic_struct == SEI_PIC_STRUCT_TOP_BOTTOM_TOP) - cur->f->top_field_first = 1; - else - cur->f->top_field_first = 0; - } else { - /* Most likely progressive */ - cur->f->top_field_first = 0; - } - } - - if (h->sei.frame_packing.present && - h->sei.frame_packing.arrangement_type >= 0 && - h->sei.frame_packing.arrangement_type <= 6 && - h->sei.frame_packing.content_interpretation_type > 0 && - h->sei.frame_packing.content_interpretation_type < 3) { - H264SEIFramePacking *fp = &h->sei.frame_packing; - AVStereo3D *stereo = av_stereo3d_create_side_data(cur->f); - if (!stereo) - return; - - switch (fp->arrangement_type) { - case 0: - stereo->type = AV_STEREO3D_CHECKERBOARD; - break; - case 1: - stereo->type = AV_STEREO3D_COLUMNS; - break; - case 2: - stereo->type = AV_STEREO3D_LINES; - break; - case 3: - if (fp->quincunx_subsampling) - stereo->type = AV_STEREO3D_SIDEBYSIDE_QUINCUNX; - else - stereo->type = AV_STEREO3D_SIDEBYSIDE; - break; - case 4: - stereo->type = AV_STEREO3D_TOPBOTTOM; - break; - case 5: - stereo->type = AV_STEREO3D_FRAMESEQUENCE; - break; - case 6: - stereo->type = AV_STEREO3D_2D; - break; - } - - if (fp->content_interpretation_type == 2) - stereo->flags = AV_STEREO3D_FLAG_INVERT; - } - - if (h->sei.display_orientation.present && - (h->sei.display_orientation.anticlockwise_rotation || - h->sei.display_orientation.hflip || - h->sei.display_orientation.vflip)) { - H264SEIDisplayOrientation *o = &h->sei.display_orientation; - double angle = o->anticlockwise_rotation * 360 / (double) (1 << 16); - AVFrameSideData *rotation = av_frame_new_side_data(cur->f, - AV_FRAME_DATA_DISPLAYMATRIX, - sizeof(int32_t) * 9); - if (!rotation) - return; - - av_display_rotation_set((int32_t *)rotation->data, angle); - av_display_matrix_flip((int32_t *)rotation->data, - o->hflip, o->vflip); - } - - if (h->sei.afd.present) { - AVFrameSideData *sd = av_frame_new_side_data(cur->f, AV_FRAME_DATA_AFD, - sizeof(uint8_t)); - if (!sd) - return; - - *sd->data = h->sei.afd.active_format_description; - h->sei.afd.present = 0; - } - - if (h->sei.a53_caption.a53_caption) { - H264SEIA53Caption *a53 = &h->sei.a53_caption; - AVFrameSideData *sd = av_frame_new_side_data(cur->f, - AV_FRAME_DATA_A53_CC, - a53->a53_caption_size); - if (!sd) - return; - - memcpy(sd->data, a53->a53_caption, a53->a53_caption_size); - av_freep(&a53->a53_caption); - a53->a53_caption_size = 0; - } - // FIXME do something with unavailable reference frames /* Sort B-frames into display order */ diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index ec8a82c0a64a2..6a89a416ac31a 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -26,7 +26,9 @@ */ #include "libavutil/avassert.h" +#include "libavutil/display.h" #include "libavutil/imgutils.h" +#include "libavutil/stereo3d.h" #include "libavutil/timer.h" #include "internal.h" #include "cabac.h" @@ -984,6 +986,161 @@ static int h264_init_ps(H264Context *h, const H264SliceContext *sl) return 0; } +static int h264_export_frame_props(H264Context *h) +{ + const SPS *sps = h->ps.sps; + H264Picture *cur = h->cur_pic_ptr; + + cur->f->interlaced_frame = 0; + cur->f->repeat_pict = 0; + + /* Signal interlacing information externally. */ + /* Prioritize picture timing SEI information over used + * decoding process if it exists. */ + + if (sps->pic_struct_present_flag) { + H264SEIPictureTiming *pt = &h->sei.picture_timing; + switch (pt->pic_struct) { + case SEI_PIC_STRUCT_FRAME: + break; + case SEI_PIC_STRUCT_TOP_FIELD: + case SEI_PIC_STRUCT_BOTTOM_FIELD: + cur->f->interlaced_frame = 1; + break; + case SEI_PIC_STRUCT_TOP_BOTTOM: + case SEI_PIC_STRUCT_BOTTOM_TOP: + if (FIELD_OR_MBAFF_PICTURE(h)) + cur->f->interlaced_frame = 1; + else + // try to flag soft telecine progressive + cur->f->interlaced_frame = h->prev_interlaced_frame; + break; + case SEI_PIC_STRUCT_TOP_BOTTOM_TOP: + case SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM: + /* Signal the possibility of telecined film externally + * (pic_struct 5,6). From these hints, let the applications + * decide if they apply deinterlacing. */ + cur->f->repeat_pict = 1; + break; + case SEI_PIC_STRUCT_FRAME_DOUBLING: + cur->f->repeat_pict = 2; + break; + case SEI_PIC_STRUCT_FRAME_TRIPLING: + cur->f->repeat_pict = 4; + break; + } + + if ((pt->ct_type & 3) && + pt->pic_struct <= SEI_PIC_STRUCT_BOTTOM_TOP) + cur->f->interlaced_frame = (pt->ct_type & (1 << 1)) != 0; + } else { + /* Derive interlacing flag from used decoding process. */ + cur->f->interlaced_frame = FIELD_OR_MBAFF_PICTURE(h); + } + h->prev_interlaced_frame = cur->f->interlaced_frame; + + if (cur->field_poc[0] != cur->field_poc[1]) { + /* Derive top_field_first from field pocs. */ + cur->f->top_field_first = cur->field_poc[0] < cur->field_poc[1]; + } else { + if (cur->f->interlaced_frame || sps->pic_struct_present_flag) { + /* Use picture timing SEI information. Even if it is a + * information of a past frame, better than nothing. */ + if (h->sei.picture_timing.pic_struct == SEI_PIC_STRUCT_TOP_BOTTOM || + h->sei.picture_timing.pic_struct == SEI_PIC_STRUCT_TOP_BOTTOM_TOP) + cur->f->top_field_first = 1; + else + cur->f->top_field_first = 0; + } else { + /* Most likely progressive */ + cur->f->top_field_first = 0; + } + } + + if (h->sei.frame_packing.present && + h->sei.frame_packing.arrangement_type >= 0 && + h->sei.frame_packing.arrangement_type <= 6 && + h->sei.frame_packing.content_interpretation_type > 0 && + h->sei.frame_packing.content_interpretation_type < 3) { + H264SEIFramePacking *fp = &h->sei.frame_packing; + AVStereo3D *stereo = av_stereo3d_create_side_data(cur->f); + if (!stereo) + return AVERROR(ENOMEM); + + switch (fp->arrangement_type) { + case 0: + stereo->type = AV_STEREO3D_CHECKERBOARD; + break; + case 1: + stereo->type = AV_STEREO3D_COLUMNS; + break; + case 2: + stereo->type = AV_STEREO3D_LINES; + break; + case 3: + if (fp->quincunx_subsampling) + stereo->type = AV_STEREO3D_SIDEBYSIDE_QUINCUNX; + else + stereo->type = AV_STEREO3D_SIDEBYSIDE; + break; + case 4: + stereo->type = AV_STEREO3D_TOPBOTTOM; + break; + case 5: + stereo->type = AV_STEREO3D_FRAMESEQUENCE; + break; + case 6: + stereo->type = AV_STEREO3D_2D; + break; + } + + if (fp->content_interpretation_type == 2) + stereo->flags = AV_STEREO3D_FLAG_INVERT; + } + + if (h->sei.display_orientation.present && + (h->sei.display_orientation.anticlockwise_rotation || + h->sei.display_orientation.hflip || + h->sei.display_orientation.vflip)) { + H264SEIDisplayOrientation *o = &h->sei.display_orientation; + double angle = o->anticlockwise_rotation * 360 / (double) (1 << 16); + AVFrameSideData *rotation = av_frame_new_side_data(cur->f, + AV_FRAME_DATA_DISPLAYMATRIX, + sizeof(int32_t) * 9); + if (!rotation) + return AVERROR(ENOMEM); + + av_display_rotation_set((int32_t *)rotation->data, angle); + av_display_matrix_flip((int32_t *)rotation->data, + o->hflip, o->vflip); + } + + if (h->sei.afd.present) { + AVFrameSideData *sd = av_frame_new_side_data(cur->f, AV_FRAME_DATA_AFD, + sizeof(uint8_t)); + if (!sd) + return AVERROR(ENOMEM); + + *sd->data = h->sei.afd.active_format_description; + h->sei.afd.present = 0; + } + + if (h->sei.a53_caption.a53_caption) { + H264SEIA53Caption *a53 = &h->sei.a53_caption; + AVFrameSideData *sd = av_frame_new_side_data(cur->f, + AV_FRAME_DATA_A53_CC, + a53->a53_caption_size); + if (!sd) + return AVERROR(ENOMEM); + + memcpy(sd->data, a53->a53_caption, a53->a53_caption_size); + av_freep(&a53->a53_caption); + a53->a53_caption_size = 0; + } + + return 0; +} + /* This function is called right after decoding the slice header for a first * slice in a field (or a frame). It decides whether we are decoding a new frame * or a second field in a pair and does the necessary setup. @@ -1174,6 +1331,15 @@ static int h264_field_start(H264Context *h, const H264SliceContext *sl, h->nb_mmco = sl->nb_mmco; h->explicit_ref_marking = sl->explicit_ref_marking; + /* Set the frame properties/side data. Only done for the second field in + * field coded frames, since some SEI information is present for each field + * and is merged by the SEI parsing code. */ + if (!FIELD_PICTURE(h) || !h->first_field) { + ret = h264_export_frame_props(h); + if (ret < 0) + return ret; + } + return 0; } From 9df889a5f116c1ee78c2f239e0ba599c492431aa Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Wed, 18 May 2016 09:02:39 +0200 Subject: [PATCH 09/71] h264: rename h264.[ch] to h264dec.[ch] This is more consistent with the naming of other decoders. --- libavcodec/Makefile | 2 +- libavcodec/dxva2_h264.c | 2 +- libavcodec/h264_cabac.c | 2 +- libavcodec/h264_cavlc.c | 2 +- libavcodec/h264_direct.c | 2 +- libavcodec/h264_loopfilter.c | 2 +- libavcodec/h264_mb.c | 2 +- libavcodec/h264_mc_template.c | 2 +- libavcodec/h264_mvpred.h | 2 +- libavcodec/h264_parse.c | 2 +- libavcodec/h264_parser.c | 2 +- libavcodec/h264_picture.c | 2 +- libavcodec/h264_ps.c | 2 +- libavcodec/h264_refs.c | 2 +- libavcodec/h264_sei.c | 2 +- libavcodec/h264_slice.c | 2 +- libavcodec/h264data.c | 2 +- libavcodec/h264data.h | 2 +- libavcodec/{h264.c => h264dec.c} | 2 +- libavcodec/{h264.h => h264dec.h} | 6 +++--- libavcodec/h264idct_template.c | 2 +- libavcodec/omx.c | 2 +- libavcodec/ppc/h264dsp.c | 2 +- libavcodec/qsvenc_h264.c | 2 +- libavcodec/svq3.c | 2 +- libavcodec/vaapi.c | 2 +- libavcodec/vaapi_encode_h264.c | 2 +- libavcodec/vaapi_h264.c | 2 +- libavcodec/vda_h264.c | 2 +- libavcodec/vdpau.c | 2 +- libavcodec/vdpau_h264.c | 2 +- libavcodec/x86/h264_qpel.c | 2 +- 32 files changed, 34 insertions(+), 34 deletions(-) rename libavcodec/{h264.c => h264dec.c} (99%) rename libavcodec/{h264.h => h264dec.h} (99%) diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 1f2096cf86a55..622e1007ee7fa 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -249,7 +249,7 @@ OBJS-$(CONFIG_H263_DECODER) += h263dec.o h263.o ituh263dec.o \ intelh263dec.o h263data.o OBJS-$(CONFIG_H263_ENCODER) += mpeg4videoenc.o mpeg4video.o \ h263.o ituh263enc.o flvenc.o h263data.o -OBJS-$(CONFIG_H264_DECODER) += h264.o h264_cabac.o h264_cavlc.o \ +OBJS-$(CONFIG_H264_DECODER) += h264dec.o h264_cabac.o h264_cavlc.o \ h264_direct.o h264_loopfilter.o \ h264_mb.o h264_picture.o h264_ps.o \ h264_refs.o h264_sei.o \ diff --git a/libavcodec/dxva2_h264.c b/libavcodec/dxva2_h264.c index e2e987d259c39..c2ff15baaba26 100644 --- a/libavcodec/dxva2_h264.c +++ b/libavcodec/dxva2_h264.c @@ -20,7 +20,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "h264.h" +#include "h264dec.h" #include "h264data.h" #include "mpegutils.h" diff --git a/libavcodec/h264_cabac.c b/libavcodec/h264_cabac.c index 783bc0f5c9427..203803fbdf723 100644 --- a/libavcodec/h264_cabac.c +++ b/libavcodec/h264_cabac.c @@ -35,7 +35,7 @@ #include "cabac_functions.h" #include "internal.h" #include "avcodec.h" -#include "h264.h" +#include "h264dec.h" #include "h264data.h" #include "h264_mvpred.h" #include "mpegutils.h" diff --git a/libavcodec/h264_cavlc.c b/libavcodec/h264_cavlc.c index dabd61cd79eea..4fa2de01844ae 100644 --- a/libavcodec/h264_cavlc.c +++ b/libavcodec/h264_cavlc.c @@ -29,7 +29,7 @@ #include "internal.h" #include "avcodec.h" -#include "h264.h" +#include "h264dec.h" #include "h264_mvpred.h" #include "h264data.h" #include "golomb.h" diff --git a/libavcodec/h264_direct.c b/libavcodec/h264_direct.c index 177ec10d55438..d0d16e9793f62 100644 --- a/libavcodec/h264_direct.c +++ b/libavcodec/h264_direct.c @@ -27,7 +27,7 @@ #include "internal.h" #include "avcodec.h" -#include "h264.h" +#include "h264dec.h" #include "mpegutils.h" #include "rectangle.h" #include "thread.h" diff --git a/libavcodec/h264_loopfilter.c b/libavcodec/h264_loopfilter.c index 2bac17a3d4366..71334e90b265e 100644 --- a/libavcodec/h264_loopfilter.c +++ b/libavcodec/h264_loopfilter.c @@ -29,7 +29,7 @@ #include "libavutil/intreadwrite.h" #include "internal.h" #include "avcodec.h" -#include "h264.h" +#include "h264dec.h" #include "mathops.h" #include "mpegutils.h" #include "rectangle.h" diff --git a/libavcodec/h264_mb.c b/libavcodec/h264_mb.c index 6f3c719ce0218..55bf1c35e03c9 100644 --- a/libavcodec/h264_mb.c +++ b/libavcodec/h264_mb.c @@ -31,7 +31,7 @@ #include "libavutil/common.h" #include "libavutil/intreadwrite.h" #include "avcodec.h" -#include "h264.h" +#include "h264dec.h" #include "qpeldsp.h" #include "thread.h" diff --git a/libavcodec/h264_mc_template.c b/libavcodec/h264_mc_template.c index 0c8a925d1dd67..7e6f62f10ada2 100644 --- a/libavcodec/h264_mc_template.c +++ b/libavcodec/h264_mc_template.c @@ -19,7 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "h264.h" +#include "h264dec.h" #undef MCFUNC diff --git a/libavcodec/h264_mvpred.h b/libavcodec/h264_mvpred.h index e9d2b62208aeb..83b1ea6a71a8a 100644 --- a/libavcodec/h264_mvpred.h +++ b/libavcodec/h264_mvpred.h @@ -30,7 +30,7 @@ #include "internal.h" #include "avcodec.h" -#include "h264.h" +#include "h264dec.h" #include "mpegutils.h" #include diff --git a/libavcodec/h264_parse.c b/libavcodec/h264_parse.c index 052e8e41d9bcb..be75b054e620b 100644 --- a/libavcodec/h264_parse.c +++ b/libavcodec/h264_parse.c @@ -19,7 +19,7 @@ #include "bytestream.h" #include "get_bits.h" #include "golomb.h" -#include "h264.h" +#include "h264dec.h" #include "h264_parse.h" int ff_h264_pred_weight_table(GetBitContext *gb, const SPS *sps, diff --git a/libavcodec/h264_parser.c b/libavcodec/h264_parser.c index b86bf2b9b72e0..c4741833666d5 100644 --- a/libavcodec/h264_parser.c +++ b/libavcodec/h264_parser.c @@ -36,7 +36,7 @@ #include "get_bits.h" #include "golomb.h" -#include "h264.h" +#include "h264dec.h" #include "h264_sei.h" #include "h264data.h" #include "internal.h" diff --git a/libavcodec/h264_picture.c b/libavcodec/h264_picture.c index cd7ff82d71602..e22852a24fa4a 100644 --- a/libavcodec/h264_picture.c +++ b/libavcodec/h264_picture.c @@ -33,7 +33,7 @@ #include "cabac_functions.h" #include "error_resilience.h" #include "avcodec.h" -#include "h264.h" +#include "h264dec.h" #include "h264data.h" #include "h264chroma.h" #include "h264_mvpred.h" diff --git a/libavcodec/h264_ps.c b/libavcodec/h264_ps.c index 8d567cad2581f..9b39992c10733 100644 --- a/libavcodec/h264_ps.c +++ b/libavcodec/h264_ps.c @@ -31,7 +31,7 @@ #include "internal.h" #include "mathops.h" #include "avcodec.h" -#include "h264.h" +#include "h264dec.h" #include "h264data.h" #include "golomb.h" diff --git a/libavcodec/h264_refs.c b/libavcodec/h264_refs.c index f7b7211a5c226..d6dee7a2900e7 100644 --- a/libavcodec/h264_refs.c +++ b/libavcodec/h264_refs.c @@ -29,7 +29,7 @@ #include "internal.h" #include "avcodec.h" -#include "h264.h" +#include "h264dec.h" #include "golomb.h" #include "mpegutils.h" diff --git a/libavcodec/h264_sei.c b/libavcodec/h264_sei.c index 0e3952d2c985a..380e86c983f5c 100644 --- a/libavcodec/h264_sei.c +++ b/libavcodec/h264_sei.c @@ -28,7 +28,7 @@ #include "avcodec.h" #include "get_bits.h" #include "golomb.h" -#include "h264.h" +#include "h264dec.h" #include "h264_sei.h" #include "internal.h" diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index 6a89a416ac31a..d49c619a224f4 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -35,7 +35,7 @@ #include "cabac_functions.h" #include "error_resilience.h" #include "avcodec.h" -#include "h264.h" +#include "h264dec.h" #include "h264data.h" #include "h264chroma.h" #include "h264_mvpred.h" diff --git a/libavcodec/h264data.c b/libavcodec/h264data.c index 79c5b57cbc4a0..a2a4a47036b91 100644 --- a/libavcodec/h264data.c +++ b/libavcodec/h264data.c @@ -31,7 +31,7 @@ #include "libavutil/avutil.h" #include "avcodec.h" -#include "h264.h" +#include "h264dec.h" #include "h264data.h" const uint8_t ff_h264_golomb_to_pict_type[5] = { diff --git a/libavcodec/h264data.h b/libavcodec/h264data.h index ab96f0835acfb..f1284e6b69798 100644 --- a/libavcodec/h264data.h +++ b/libavcodec/h264data.h @@ -21,7 +21,7 @@ #include -#include "h264.h" +#include "h264dec.h" extern const uint8_t ff_h264_golomb_to_pict_type[5]; extern const uint8_t ff_h264_golomb_to_intra4x4_cbp[48]; diff --git a/libavcodec/h264.c b/libavcodec/h264dec.c similarity index 99% rename from libavcodec/h264.c rename to libavcodec/h264dec.c index 7949ee66ac519..6eb2da8665a42 100644 --- a/libavcodec/h264.c +++ b/libavcodec/h264dec.c @@ -36,7 +36,7 @@ #include "cabac_functions.h" #include "error_resilience.h" #include "avcodec.h" -#include "h264.h" +#include "h264dec.h" #include "h2645_parse.h" #include "h264data.h" #include "h264chroma.h" diff --git a/libavcodec/h264.h b/libavcodec/h264dec.h similarity index 99% rename from libavcodec/h264.h rename to libavcodec/h264dec.h index 398a2837b8000..300077d7f22cf 100644 --- a/libavcodec/h264.h +++ b/libavcodec/h264dec.h @@ -25,8 +25,8 @@ * @author Michael Niedermayer */ -#ifndef AVCODEC_H264_H -#define AVCODEC_H264_H +#ifndef AVCODEC_H264DEC_H +#define AVCODEC_H264DEC_H #include "libavutil/buffer.h" #include "libavutil/intreadwrite.h" @@ -935,4 +935,4 @@ void ff_h264_flush_change(H264Context *h); void ff_h264_free_tables(H264Context *h); -#endif /* AVCODEC_H264_H */ +#endif /* AVCODEC_H264DEC_H */ diff --git a/libavcodec/h264idct_template.c b/libavcodec/h264idct_template.c index 83c2a959b2b62..08a71cd4e9664 100644 --- a/libavcodec/h264idct_template.c +++ b/libavcodec/h264idct_template.c @@ -27,7 +27,7 @@ #include "bit_depth_template.c" #include "libavutil/common.h" -#include "h264.h" +#include "h264dec.h" #include "h264idct.h" void FUNCC(ff_h264_idct_add)(uint8_t *_dst, int16_t *_block, int stride) diff --git a/libavcodec/omx.c b/libavcodec/omx.c index 961ff867641fe..d556a202e32b5 100644 --- a/libavcodec/omx.c +++ b/libavcodec/omx.c @@ -41,7 +41,7 @@ #include "libavutil/opt.h" #include "avcodec.h" -#include "h264.h" +#include "h264dec.h" #include "internal.h" #ifdef OMX_SKIP64BIT diff --git a/libavcodec/ppc/h264dsp.c b/libavcodec/ppc/h264dsp.c index ce514e3d861cc..0538dbceed9b6 100644 --- a/libavcodec/ppc/h264dsp.c +++ b/libavcodec/ppc/h264dsp.c @@ -31,7 +31,7 @@ #include "libavutil/ppc/types_altivec.h" #include "libavutil/ppc/util_altivec.h" -#include "libavcodec/h264.h" +#include "libavcodec/h264dec.h" #include "libavcodec/h264dsp.h" #if HAVE_ALTIVEC && HAVE_BIGENDIAN diff --git a/libavcodec/qsvenc_h264.c b/libavcodec/qsvenc_h264.c index 7f4fb8126f30d..035f9c65f6f09 100644 --- a/libavcodec/qsvenc_h264.c +++ b/libavcodec/qsvenc_h264.c @@ -30,7 +30,7 @@ #include "avcodec.h" #include "internal.h" -#include "h264.h" +#include "h264dec.h" #include "qsv.h" #include "qsv_internal.h" #include "qsvenc.h" diff --git a/libavcodec/svq3.c b/libavcodec/svq3.c index 9dc1fb5d02459..bf68389b5bb29 100644 --- a/libavcodec/svq3.c +++ b/libavcodec/svq3.c @@ -46,7 +46,7 @@ #include "internal.h" #include "avcodec.h" #include "mpegutils.h" -#include "h264.h" +#include "h264dec.h" #include "h264data.h" #include "golomb.h" #include "hpeldsp.h" diff --git a/libavcodec/vaapi.c b/libavcodec/vaapi.c index 094692e2a2f48..d2aafac38e46b 100644 --- a/libavcodec/vaapi.c +++ b/libavcodec/vaapi.c @@ -21,7 +21,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "h264.h" +#include "h264dec.h" #include "mpegvideo.h" #include "vaapi_internal.h" diff --git a/libavcodec/vaapi_encode_h264.c b/libavcodec/vaapi_encode_h264.c index a2889806f9993..95450f8edcb94 100644 --- a/libavcodec/vaapi_encode_h264.c +++ b/libavcodec/vaapi_encode_h264.c @@ -25,7 +25,7 @@ #include "libavutil/pixfmt.h" #include "avcodec.h" -#include "h264.h" +#include "h264dec.h" #include "h264_sei.h" #include "internal.h" #include "vaapi_encode.h" diff --git a/libavcodec/vaapi_h264.c b/libavcodec/vaapi_h264.c index 0925985235cc8..cd32bbbeb2a96 100644 --- a/libavcodec/vaapi_h264.c +++ b/libavcodec/vaapi_h264.c @@ -21,7 +21,7 @@ */ #include "vaapi_internal.h" -#include "h264.h" +#include "h264dec.h" #include "mpegutils.h" /** diff --git a/libavcodec/vda_h264.c b/libavcodec/vda_h264.c index 8ae979220062f..037715da81021 100644 --- a/libavcodec/vda_h264.c +++ b/libavcodec/vda_h264.c @@ -25,7 +25,7 @@ #include #include "libavutil/avutil.h" -#include "h264.h" +#include "h264dec.h" #include "internal.h" #include "vda.h" #include "vda_internal.h" diff --git a/libavcodec/vdpau.c b/libavcodec/vdpau.c index b7784393dfd3a..f638d201159dd 100644 --- a/libavcodec/vdpau.c +++ b/libavcodec/vdpau.c @@ -25,7 +25,7 @@ #include "avcodec.h" #include "internal.h" -#include "h264.h" +#include "h264dec.h" #include "vc1.h" #include "vdpau.h" #include "vdpau_internal.h" diff --git a/libavcodec/vdpau_h264.c b/libavcodec/vdpau_h264.c index c34e323197fff..34dc630efcc3c 100644 --- a/libavcodec/vdpau_h264.c +++ b/libavcodec/vdpau_h264.c @@ -25,7 +25,7 @@ #include "avcodec.h" #include "internal.h" -#include "h264.h" +#include "h264dec.h" #include "mpegutils.h" #include "vdpau.h" #include "vdpau_internal.h" diff --git a/libavcodec/x86/h264_qpel.c b/libavcodec/x86/h264_qpel.c index 76d2ab05d5c02..541ebb2a0409d 100644 --- a/libavcodec/x86/h264_qpel.c +++ b/libavcodec/x86/h264_qpel.c @@ -23,7 +23,7 @@ #include "libavutil/cpu.h" #include "libavutil/x86/asm.h" #include "libavutil/x86/cpu.h" -#include "libavcodec/h264.h" +#include "libavcodec/h264dec.h" #include "libavcodec/h264qpel.h" #include "libavcodec/pixels.h" #include "fpel.h" From 251cbb44003caf179fb17afbb8a6c56643c2a646 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Wed, 18 May 2016 09:16:35 +0200 Subject: [PATCH 10/71] h264: create a new header for common h264 definitions Move the NAL unit types into it. This will allow to stop including the whole decoder-specific h264dec.h in some code that is unrelated to the decoder and only needs some enum values. --- libavcodec/h264.h | 45 ++++++++++++++++++++++++++++++++++ libavcodec/h264_parse.c | 1 + libavcodec/h264_parser.c | 1 + libavcodec/h264_refs.c | 1 + libavcodec/h264_slice.c | 1 + libavcodec/h264dec.c | 1 + libavcodec/h264dec.h | 18 -------------- libavcodec/omx.c | 2 +- libavcodec/vaapi_encode_h264.c | 2 +- 9 files changed, 52 insertions(+), 20 deletions(-) create mode 100644 libavcodec/h264.h diff --git a/libavcodec/h264.h b/libavcodec/h264.h new file mode 100644 index 0000000000000..650371f803a29 --- /dev/null +++ b/libavcodec/h264.h @@ -0,0 +1,45 @@ +/* + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * H.264 common definitions + */ + +#ifndef AVCODEC_H264_H +#define AVCODEC_H264_H + +/* NAL unit types */ +enum { + NAL_SLICE = 1, + NAL_DPA = 2, + NAL_DPB = 3, + NAL_DPC = 4, + NAL_IDR_SLICE = 5, + NAL_SEI = 6, + NAL_SPS = 7, + NAL_PPS = 8, + NAL_AUD = 9, + NAL_END_SEQUENCE = 10, + NAL_END_STREAM = 11, + NAL_FILLER_DATA = 12, + NAL_SPS_EXT = 13, + NAL_AUXILIARY_SLICE = 19, +}; + +#endif /* AVCODEC_H264_H */ diff --git a/libavcodec/h264_parse.c b/libavcodec/h264_parse.c index be75b054e620b..ba67f4e0122aa 100644 --- a/libavcodec/h264_parse.c +++ b/libavcodec/h264_parse.c @@ -19,6 +19,7 @@ #include "bytestream.h" #include "get_bits.h" #include "golomb.h" +#include "h264.h" #include "h264dec.h" #include "h264_parse.h" diff --git a/libavcodec/h264_parser.c b/libavcodec/h264_parser.c index c4741833666d5..9e36118ac0b03 100644 --- a/libavcodec/h264_parser.c +++ b/libavcodec/h264_parser.c @@ -36,6 +36,7 @@ #include "get_bits.h" #include "golomb.h" +#include "h264.h" #include "h264dec.h" #include "h264_sei.h" #include "h264data.h" diff --git a/libavcodec/h264_refs.c b/libavcodec/h264_refs.c index d6dee7a2900e7..4172fbdaa3d3d 100644 --- a/libavcodec/h264_refs.c +++ b/libavcodec/h264_refs.c @@ -29,6 +29,7 @@ #include "internal.h" #include "avcodec.h" +#include "h264.h" #include "h264dec.h" #include "golomb.h" #include "mpegutils.h" diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index d49c619a224f4..1c4cf33532b1a 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -35,6 +35,7 @@ #include "cabac_functions.h" #include "error_resilience.h" #include "avcodec.h" +#include "h264.h" #include "h264dec.h" #include "h264data.h" #include "h264chroma.h" diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c index 6eb2da8665a42..94229fe85a415 100644 --- a/libavcodec/h264dec.c +++ b/libavcodec/h264dec.c @@ -36,6 +36,7 @@ #include "cabac_functions.h" #include "error_resilience.h" #include "avcodec.h" +#include "h264.h" #include "h264dec.h" #include "h2645_parse.h" #include "h264data.h" diff --git a/libavcodec/h264dec.h b/libavcodec/h264dec.h index 300077d7f22cf..e79257ea36579 100644 --- a/libavcodec/h264dec.h +++ b/libavcodec/h264dec.h @@ -108,24 +108,6 @@ #define QP_MAX_NUM (51 + 2 * 6) // The maximum supported qp -/* NAL unit types */ -enum { - NAL_SLICE = 1, - NAL_DPA = 2, - NAL_DPB = 3, - NAL_DPC = 4, - NAL_IDR_SLICE = 5, - NAL_SEI = 6, - NAL_SPS = 7, - NAL_PPS = 8, - NAL_AUD = 9, - NAL_END_SEQUENCE = 10, - NAL_END_STREAM = 11, - NAL_FILLER_DATA = 12, - NAL_SPS_EXT = 13, - NAL_AUXILIARY_SLICE = 19, -}; - /** * Sequence parameter set */ diff --git a/libavcodec/omx.c b/libavcodec/omx.c index d556a202e32b5..961ff867641fe 100644 --- a/libavcodec/omx.c +++ b/libavcodec/omx.c @@ -41,7 +41,7 @@ #include "libavutil/opt.h" #include "avcodec.h" -#include "h264dec.h" +#include "h264.h" #include "internal.h" #ifdef OMX_SKIP64BIT diff --git a/libavcodec/vaapi_encode_h264.c b/libavcodec/vaapi_encode_h264.c index 95450f8edcb94..a2889806f9993 100644 --- a/libavcodec/vaapi_encode_h264.c +++ b/libavcodec/vaapi_encode_h264.c @@ -25,7 +25,7 @@ #include "libavutil/pixfmt.h" #include "avcodec.h" -#include "h264dec.h" +#include "h264.h" #include "h264_sei.h" #include "internal.h" #include "vaapi_encode.h" From 4e2f6212483ae1b2a4043cddf0a1cb001b476abc Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Wed, 18 May 2016 09:34:05 +0200 Subject: [PATCH 11/71] svq3: stop using H264Picture The SVQ3 decoder has been decoupled from the H.264 decoder, so it can now use its own data type. --- libavcodec/svq3.c | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/libavcodec/svq3.c b/libavcodec/svq3.c index bf68389b5bb29..aa85e7c59f5c3 100644 --- a/libavcodec/svq3.c +++ b/libavcodec/svq3.c @@ -65,6 +65,20 @@ * svq3 decoder. */ +typedef struct SVQ3Frame { + AVFrame *f; + + AVBufferRef *motion_val_buf[2]; + int16_t (*motion_val[2])[2]; + + AVBufferRef *mb_type_buf; + uint32_t *mb_type; + + + AVBufferRef *ref_index_buf[2]; + int8_t *ref_index[2]; +} SVQ3Frame; + typedef struct SVQ3Context { AVCodecContext *avctx; @@ -74,9 +88,9 @@ typedef struct SVQ3Context { TpelDSPContext tdsp; VideoDSPContext vdsp; - H264Picture *cur_pic; - H264Picture *next_pic; - H264Picture *last_pic; + SVQ3Frame *cur_pic; + SVQ3Frame *next_pic; + SVQ3Frame *last_pic; GetBitContext gb; GetBitContext gb_slice; uint8_t *slice_buf; @@ -410,7 +424,7 @@ static inline void svq3_mc_dir_part(SVQ3Context *s, int mx, int my, int dxy, int thirdpel, int dir, int avg) { - const H264Picture *pic = (dir == 0) ? s->last_pic : s->next_pic; + const SVQ3Frame *pic = (dir == 0) ? s->last_pic : s->next_pic; uint8_t *src, *dest; int i, emu = 0; int blocksize = 2 - (width >> 3); // 16->0, 8->1, 4->2 @@ -1298,7 +1312,7 @@ static av_cold int svq3_decode_init(AVCodecContext *avctx) return 0; } -static void free_picture(AVCodecContext *avctx, H264Picture *pic) +static void free_picture(AVCodecContext *avctx, SVQ3Frame *pic) { int i; for (i = 0; i < 2; i++) { @@ -1310,7 +1324,7 @@ static void free_picture(AVCodecContext *avctx, H264Picture *pic) av_frame_unref(pic->f); } -static int get_buffer(AVCodecContext *avctx, H264Picture *pic) +static int get_buffer(AVCodecContext *avctx, SVQ3Frame *pic) { SVQ3Context *s = avctx->priv_data; const int big_mb_num = s->mb_stride * (s->mb_height + 1) + 1; @@ -1339,10 +1353,10 @@ static int get_buffer(AVCodecContext *avctx, H264Picture *pic) pic->ref_index[i] = pic->ref_index_buf[i]->data; } } - pic->reference = !(s->pict_type == AV_PICTURE_TYPE_B); ret = ff_get_buffer(avctx, pic->f, - pic->reference ? AV_GET_BUFFER_FLAG_REF : 0); + (s->pict_type != AV_PICTURE_TYPE_B) ? + AV_GET_BUFFER_FLAG_REF : 0); if (ret < 0) goto fail; @@ -1388,7 +1402,7 @@ static int svq3_decode_frame(AVCodecContext *avctx, void *data, return -1; if (s->pict_type != AV_PICTURE_TYPE_B) - FFSWAP(H264Picture*, s->next_pic, s->last_pic); + FFSWAP(SVQ3Frame*, s->next_pic, s->last_pic); av_frame_unref(s->cur_pic->f); @@ -1539,7 +1553,7 @@ static int svq3_decode_frame(AVCodecContext *avctx, void *data, *got_frame = 1; if (s->pict_type != AV_PICTURE_TYPE_B) { - FFSWAP(H264Picture*, s->cur_pic, s->next_pic); + FFSWAP(SVQ3Frame*, s->cur_pic, s->next_pic); } else { av_frame_unref(s->cur_pic->f); } From b8aaedcd0147be00c7d9b58c85a9caf49fb6b6db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20B=C5=93sch?= Date: Sun, 24 Jul 2016 14:21:01 +0200 Subject: [PATCH 12/71] lavfi/selectivecolor: fix picking black as neutral when alpha is present --- libavfilter/vf_selectivecolor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavfilter/vf_selectivecolor.c b/libavfilter/vf_selectivecolor.c index e590094943808..38e6ad536582a 100644 --- a/libavfilter/vf_selectivecolor.c +++ b/libavfilter/vf_selectivecolor.c @@ -338,7 +338,7 @@ static inline int selective_color(AVFilterContext *ctx, ThreadData *td, | (b == max_color) << RANGE_BLUES | (b == min_color) << RANGE_YELLOWS | (r > 128 && g > 128 && b > 128) << RANGE_WHITES - | (color && (color & 0xffffff) != 0xffffff) << RANGE_NEUTRALS + | ((r || g || b) && (r != 255 || g != 255 || b != 255)) << RANGE_NEUTRALS | (r < 128 && g < 128 && b < 128) << RANGE_BLACKS; const float rnorm = r / 255.; From 308f9b1c49445abefc85c02e1c8ccf8eb463465b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20B=C5=93sch?= Date: Thu, 14 Jul 2016 17:23:08 +0200 Subject: [PATCH 13/71] lavfi/selectivecolor: add 16-bit support --- Changelog | 1 + libavfilter/version.h | 2 +- libavfilter/vf_selectivecolor.c | 270 +++++++++++++++++++------------- 3 files changed, 162 insertions(+), 111 deletions(-) diff --git a/Changelog b/Changelog index a5d25f2ce4de7..479f1648c09de 100644 --- a/Changelog +++ b/Changelog @@ -9,6 +9,7 @@ version : - VP8 in Ogg muxing - curves filter doesn't automatically insert points at x=0 and x=1 anymore - 16-bit support in curves filter +- 16-bit support in selectivecolor filter version 3.1: diff --git a/libavfilter/version.h b/libavfilter/version.h index 89d6fbc9ada89..9d21de4309f94 100644 --- a/libavfilter/version.h +++ b/libavfilter/version.h @@ -30,7 +30,7 @@ #include "libavutil/version.h" #define LIBAVFILTER_VERSION_MAJOR 6 -#define LIBAVFILTER_VERSION_MINOR 48 +#define LIBAVFILTER_VERSION_MINOR 49 #define LIBAVFILTER_VERSION_MICRO 100 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ diff --git a/libavfilter/vf_selectivecolor.c b/libavfilter/vf_selectivecolor.c index 38e6ad536582a..33716ec5f5eff 100644 --- a/libavfilter/vf_selectivecolor.c +++ b/libavfilter/vf_selectivecolor.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Clément Bœsch + * Copyright (c) 2015-2016 Clément Bœsch * * This file is part of FFmpeg. * @@ -21,18 +21,24 @@ /** * @todo * - use integers so it can be made bitexact and a FATE test can be added - * - >8 bit support */ #include "libavutil/avassert.h" #include "libavutil/file.h" #include "libavutil/intreadwrite.h" #include "libavutil/opt.h" +#include "libavutil/pixdesc.h" #include "avfilter.h" +#include "drawutils.h" #include "formats.h" #include "internal.h" #include "video.h" +#define R 0 +#define G 1 +#define B 2 +#define A 3 + enum color_range { // WARNING: do NOT reorder (see parse_psfile()) RANGE_REDS, @@ -77,6 +83,9 @@ typedef struct { struct process_range process_ranges[NB_RANGES]; // color ranges to process int nb_process_ranges; char *psfile; + uint8_t rgba_map[4]; + int is_16bit; + int step; } SelectiveColorContext; #define OFFSET(x) offsetof(SelectiveColorContext, x) @@ -141,23 +150,28 @@ static int get_cmy_adjust_range(int r, int g, int b, int min_val, int max_val) return mid_val - min_val; } -static int get_neutrals_adjust_range(int r, int g, int b, int min_val, int max_val) -{ - // 1 - (|max-0.5| + |min-0.5|) - return (255*2 - (abs((max_val<<1) - 255) + abs((min_val<<1) - 255)) + 1) >> 1; -} - -static int get_whites_adjust_range(int r, int g, int b, int min_val, int max_val) -{ - // (min - 0.5) * 2 - return (min_val<<1) - 255; -} +#define DECLARE_ADJUST_RANGE_FUNCS(nbits) \ +static int get_neutrals_adjust_range##nbits(int r, int g, int b, int min_val, int max_val) \ +{ \ + /* 1 - (|max-0.5| + |min-0.5|) */ \ + return (((1<> 1; \ +} \ + \ +static int get_whites_adjust_range##nbits(int r, int g, int b, int min_val, int max_val) \ +{ \ + /* (min - 0.5) * 2 */ \ + return (min_val<<1) - ((1<mask = 1 << range_id; if (pr->mask & (1<get_adjust_range = get_rgb_adjust_range; else if (pr->mask & (1<get_adjust_range = get_cmy_adjust_range; - else if (pr->mask & 1<get_adjust_range = get_whites_adjust_range; - else if (pr->mask & 1<get_adjust_range = get_neutrals_adjust_range; - else if (pr->mask & 1<get_adjust_range = get_blacks_adjust_range; + else if (!s->is_16bit && (pr->mask & 1<get_adjust_range = get_whites_adjust_range8; + else if (!s->is_16bit && (pr->mask & 1<get_adjust_range = get_neutrals_adjust_range8; + else if (!s->is_16bit && (pr->mask & 1<get_adjust_range = get_blacks_adjust_range8; + else if ( s->is_16bit && (pr->mask & 1<get_adjust_range = get_whites_adjust_range16; + else if ( s->is_16bit && (pr->mask & 1<get_adjust_range = get_neutrals_adjust_range16; + else if ( s->is_16bit && (pr->mask & 1<get_adjust_range = get_blacks_adjust_range16; else av_assert0(0); } @@ -244,10 +261,19 @@ static int parse_psfile(AVFilterContext *ctx, const char *fname) return ret; } -static av_cold int init(AVFilterContext *ctx) +static int config_input(AVFilterLink *inlink) { int i, ret; + AVFilterContext *ctx = inlink->dst; SelectiveColorContext *s = ctx->priv; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); + + s->is_16bit = desc->comp[0].depth > 8; + s->step = av_get_padded_bits_per_pixel(desc) >> (3 + s->is_16bit); + + ret = ff_fill_rgba_map(s->rgba_map, inlink->format); + if (ret < 0) + return ret; /* If the following conditions are not met, it will cause trouble while * parsing the PS file */ @@ -287,7 +313,16 @@ static av_cold int init(AVFilterContext *ctx) static int query_formats(AVFilterContext *ctx) { - static const enum AVPixelFormat pix_fmts[] = {AV_PIX_FMT_RGB32, AV_PIX_FMT_0RGB32, AV_PIX_FMT_NONE}; + static const enum AVPixelFormat pix_fmts[] = { + AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24, + AV_PIX_FMT_RGBA, AV_PIX_FMT_BGRA, + AV_PIX_FMT_ARGB, AV_PIX_FMT_ABGR, + AV_PIX_FMT_0RGB, AV_PIX_FMT_0BGR, + AV_PIX_FMT_RGB0, AV_PIX_FMT_BGR0, + AV_PIX_FMT_RGB48, AV_PIX_FMT_BGR48, + AV_PIX_FMT_RGBA64, AV_PIX_FMT_BGRA64, + AV_PIX_FMT_NONE + }; AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts); if (!fmts_list) return AVERROR(ENOMEM); @@ -304,91 +339,101 @@ static inline int comp_adjust(int adjust_range, float value, float adjust, float return lrint(av_clipf(res, min, max) * adjust_range); } -static inline int selective_color(AVFilterContext *ctx, ThreadData *td, - int jobnr, int nb_jobs, int direct, int correction_method) -{ - int i, x, y; - const AVFrame *in = td->in; - AVFrame *out = td->out; - const SelectiveColorContext *s = ctx->priv; - const int height = in->height; - const int width = in->width; - const int slice_start = (height * jobnr ) / nb_jobs; - const int slice_end = (height * (jobnr+1)) / nb_jobs; - const int dst_linesize = out->linesize[0]; - const int src_linesize = in->linesize[0]; - uint8_t *dst = out->data[0] + slice_start * dst_linesize; - const uint8_t *src = in->data[0] + slice_start * src_linesize; - - for (y = slice_start; y < slice_end; y++) { - const uint32_t *src32 = (const uint32_t *)src; - uint32_t *dst32 = (uint32_t *)dst; - - for (x = 0; x < width; x++) { - const uint32_t color = *src32++; - const int r = color >> 16 & 0xff; - const int g = color >> 8 & 0xff; - const int b = color & 0xff; - const int min_color = FFMIN3(r, g, b); - const int max_color = FFMAX3(r, g, b); - const uint32_t range_flag = (r == max_color) << RANGE_REDS - | (r == min_color) << RANGE_CYANS - | (g == max_color) << RANGE_GREENS - | (g == min_color) << RANGE_MAGENTAS - | (b == max_color) << RANGE_BLUES - | (b == min_color) << RANGE_YELLOWS - | (r > 128 && g > 128 && b > 128) << RANGE_WHITES - | ((r || g || b) && (r != 255 || g != 255 || b != 255)) << RANGE_NEUTRALS - | (r < 128 && g < 128 && b < 128) << RANGE_BLACKS; - - const float rnorm = r / 255.; - const float gnorm = g / 255.; - const float bnorm = b / 255.; - int adjust_r = 0, adjust_g = 0, adjust_b = 0; - - for (i = 0; i < s->nb_process_ranges; i++) { - const struct process_range *pr = &s->process_ranges[i]; - - if (range_flag & pr->mask) { - const int adjust_range = pr->get_adjust_range(r, g, b, min_color, max_color); - - if (adjust_range > 0) { - const float *cmyk_adjust = s->cmyk_adjust[pr->range_id]; - const float adj_c = cmyk_adjust[0]; - const float adj_m = cmyk_adjust[1]; - const float adj_y = cmyk_adjust[2]; - const float k = cmyk_adjust[3]; - - adjust_r += comp_adjust(adjust_range, rnorm, adj_c, k, correction_method); - adjust_g += comp_adjust(adjust_range, gnorm, adj_m, k, correction_method); - adjust_b += comp_adjust(adjust_range, bnorm, adj_y, k, correction_method); - } - } - } - - if (!direct || adjust_r || adjust_g || adjust_b) - *dst32 = (color & 0xff000000) - | av_clip_uint8(r + adjust_r) << 16 - | av_clip_uint8(g + adjust_g) << 8 - | av_clip_uint8(b + adjust_b); - dst32++; - } - src += src_linesize; - dst += dst_linesize; - } - return 0; +#define DECLARE_SELECTIVE_COLOR_FUNC(nbits) \ +static inline int selective_color_##nbits(AVFilterContext *ctx, ThreadData *td, \ + int jobnr, int nb_jobs, int direct, int correction_method) \ +{ \ + int i, x, y; \ + const AVFrame *in = td->in; \ + AVFrame *out = td->out; \ + const SelectiveColorContext *s = ctx->priv; \ + const int height = in->height; \ + const int width = in->width; \ + const int slice_start = (height * jobnr ) / nb_jobs; \ + const int slice_end = (height * (jobnr+1)) / nb_jobs; \ + const int dst_linesize = out->linesize[0]; \ + const int src_linesize = in->linesize[0]; \ + const uint8_t roffset = s->rgba_map[R]; \ + const uint8_t goffset = s->rgba_map[G]; \ + const uint8_t boffset = s->rgba_map[B]; \ + const uint8_t aoffset = s->rgba_map[A]; \ + \ + for (y = slice_start; y < slice_end; y++) { \ + uint##nbits##_t *dst = ( uint##nbits##_t *)(out->data[0] + y * dst_linesize); \ + const uint##nbits##_t *src = (const uint##nbits##_t *)( in->data[0] + y * src_linesize); \ + \ + for (x = 0; x < width * s->step; x += s->step) { \ + const int r = src[x + roffset]; \ + const int g = src[x + goffset]; \ + const int b = src[x + boffset]; \ + const int min_color = FFMIN3(r, g, b); \ + const int max_color = FFMAX3(r, g, b); \ + const int is_white = (r > 1<<(nbits-1) && g > 1<<(nbits-1) && b > 1<<(nbits-1)); \ + const int is_neutral = (r || g || b) && \ + r != (1<nb_process_ranges; i++) { \ + const struct process_range *pr = &s->process_ranges[i]; \ + \ + if (range_flag & pr->mask) { \ + const int adjust_range = pr->get_adjust_range(r, g, b, min_color, max_color); \ + \ + if (adjust_range > 0) { \ + const float *cmyk_adjust = s->cmyk_adjust[pr->range_id]; \ + const float adj_c = cmyk_adjust[0]; \ + const float adj_m = cmyk_adjust[1]; \ + const float adj_y = cmyk_adjust[2]; \ + const float k = cmyk_adjust[3]; \ + \ + adjust_r += comp_adjust(adjust_range, rnorm, adj_c, k, correction_method); \ + adjust_g += comp_adjust(adjust_range, gnorm, adj_m, k, correction_method); \ + adjust_b += comp_adjust(adjust_range, bnorm, adj_y, k, correction_method); \ + } \ + } \ + } \ + \ + if (!direct || adjust_r || adjust_g || adjust_b) { \ + dst[x + roffset] = av_clip_uint##nbits(r + adjust_r); \ + dst[x + goffset] = av_clip_uint##nbits(g + adjust_g); \ + dst[x + boffset] = av_clip_uint##nbits(b + adjust_b); \ + if (!direct && s->step == 4) \ + dst[x + aoffset] = src[x + aoffset]; \ + } \ + } \ + } \ + return 0; \ } -#define DEF_SELECTIVE_COLOR_FUNC(name, direct, correction_method) \ -static int selective_color_##name(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \ -{ \ - return selective_color(ctx, arg, jobnr, nb_jobs, direct, correction_method); \ +#define DEF_SELECTIVE_COLOR_FUNC(name, direct, correction_method, nbits) \ +static int selective_color_##name##_##nbits(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \ +{ \ + return selective_color_##nbits(ctx, arg, jobnr, nb_jobs, direct, correction_method); \ } -DEF_SELECTIVE_COLOR_FUNC(indirect_absolute, 0, CORRECTION_METHOD_ABSOLUTE) -DEF_SELECTIVE_COLOR_FUNC(indirect_relative, 0, CORRECTION_METHOD_RELATIVE) -DEF_SELECTIVE_COLOR_FUNC( direct_absolute, 1, CORRECTION_METHOD_ABSOLUTE) -DEF_SELECTIVE_COLOR_FUNC( direct_relative, 1, CORRECTION_METHOD_RELATIVE) +#define DEF_SELECTIVE_COLOR_FUNCS(nbits) \ +DECLARE_SELECTIVE_COLOR_FUNC(nbits) \ +DEF_SELECTIVE_COLOR_FUNC(indirect_absolute, 0, CORRECTION_METHOD_ABSOLUTE, nbits) \ +DEF_SELECTIVE_COLOR_FUNC(indirect_relative, 0, CORRECTION_METHOD_RELATIVE, nbits) \ +DEF_SELECTIVE_COLOR_FUNC( direct_absolute, 1, CORRECTION_METHOD_ABSOLUTE, nbits) \ +DEF_SELECTIVE_COLOR_FUNC( direct_relative, 1, CORRECTION_METHOD_RELATIVE, nbits) + +DEF_SELECTIVE_COLOR_FUNCS(8) +DEF_SELECTIVE_COLOR_FUNCS(16) typedef int (*selective_color_func_type)(AVFilterContext *ctx, void *td, int jobnr, int nb_jobs); @@ -400,9 +445,14 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) AVFrame *out; ThreadData td; const SelectiveColorContext *s = ctx->priv; - static const selective_color_func_type funcs[2][2] = { - {selective_color_indirect_absolute, selective_color_indirect_relative}, - {selective_color_direct_absolute, selective_color_direct_relative}, + static const selective_color_func_type funcs[2][2][2] = { + { + {selective_color_indirect_absolute_8, selective_color_indirect_relative_8}, + {selective_color_direct_absolute_8, selective_color_direct_relative_8}, + },{ + {selective_color_indirect_absolute_16, selective_color_indirect_relative_16}, + {selective_color_direct_absolute_16, selective_color_direct_relative_16}, + } }; if (av_frame_is_writable(in)) { @@ -420,8 +470,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) td.in = in; td.out = out; - ctx->internal->execute(ctx, funcs[direct][s->correction_method], &td, NULL, - FFMIN(inlink->h, ctx->graph->nb_threads)); + ctx->internal->execute(ctx, funcs[s->is_16bit][direct][s->correction_method], + &td, NULL, FFMIN(inlink->h, ctx->graph->nb_threads)); if (!direct) av_frame_free(&in); @@ -433,6 +483,7 @@ static const AVFilterPad selectivecolor_inputs[] = { .name = "default", .type = AVMEDIA_TYPE_VIDEO, .filter_frame = filter_frame, + .config_props = config_input, }, { NULL } }; @@ -449,7 +500,6 @@ AVFilter ff_vf_selectivecolor = { .name = "selectivecolor", .description = NULL_IF_CONFIG_SMALL("Apply CMYK adjustments to specific color ranges."), .priv_size = sizeof(SelectiveColorContext), - .init = init, .query_formats = query_formats, .inputs = selectivecolor_inputs, .outputs = selectivecolor_outputs, From b4054100f675b395204f1a0471fba0b06fe08e9f Mon Sep 17 00:00:00 2001 From: Ivan Uskov Date: Sun, 24 Jul 2016 09:59:42 -0400 Subject: [PATCH 14/71] Revert "Merge commit '3c53627ac17fc6bdea5029be57da1e03b32d265d'" This reverts commit d30cf57a7b2097b565db02ecfffbdc9c16423d0e, reversing changes made to acc155ac55baa95d1c16c0364b02244bc04d83a8. The commit d30cf57a7b2097b565db02ecfffbdc9c16423d0e provided irrelevant code complexity and decoding slowdown. But the main disadvantage of this commit is a decoder crash. So it should be reverted. Signed-off-by: Michael Niedermayer --- libavcodec/qsvdec.c | 34 ++++++---------------------------- 1 file changed, 6 insertions(+), 28 deletions(-) diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c index c17606dad9c70..9125700e8a88a 100644 --- a/libavcodec/qsvdec.c +++ b/libavcodec/qsvdec.c @@ -142,7 +142,7 @@ static int qsv_decode_init(AVCodecContext *avctx, QSVContext *q, AVPacket *avpkt */ if (!q->async_fifo) { q->async_fifo = av_fifo_alloc((1 + 16) * - (sizeof(mfxSyncPoint*) + sizeof(QSVFrame*))); + (sizeof(mfxSyncPoint) + sizeof(QSVFrame*))); if (!q->async_fifo) return AVERROR(ENOMEM); } @@ -297,16 +297,6 @@ static void close_decoder(QSVContext *q) if (q->session) MFXVideoDECODE_Close(q->session); - while (q->async_fifo && av_fifo_size(q->async_fifo)) { - QSVFrame *out_frame; - mfxSyncPoint *sync; - - av_fifo_generic_read(q->async_fifo, &out_frame, sizeof(out_frame), NULL); - av_fifo_generic_read(q->async_fifo, &sync, sizeof(sync), NULL); - - av_freep(&sync); - } - cur = q->work_frames; while (cur) { q->work_frames = cur->next; @@ -326,7 +316,7 @@ static int do_qsv_decode(AVCodecContext *avctx, QSVContext *q, QSVFrame *out_frame; mfxFrameSurface1 *insurf; mfxFrameSurface1 *outsurf; - mfxSyncPoint *sync; + mfxSyncPoint sync; mfxBitstream bs = { { { 0 } } }; int ret; int n_out_frames; @@ -359,19 +349,13 @@ static int do_qsv_decode(AVCodecContext *avctx, QSVContext *q, bs.TimeStamp = avpkt->pts; } - sync = av_mallocz(sizeof(*sync)); - if (!sync) { - av_freep(&sync); - return AVERROR(ENOMEM); - } - while (1) { ret = get_surface(avctx, q, &insurf); if (ret < 0) return ret; do { ret = MFXVideoDECODE_DecodeFrameAsync(q->session, flush ? NULL : &bs, - insurf, &outsurf, sync); + insurf, &outsurf, &sync); if (ret != MFX_WRN_DEVICE_BUSY) break; av_usleep(500); @@ -385,11 +369,10 @@ static int do_qsv_decode(AVCodecContext *avctx, QSVContext *q, continue; } - if (*sync) { + if (sync) { QSVFrame *out_frame = find_frame(q, outsurf); if (!out_frame) { - av_freep(&sync); av_log(avctx, AV_LOG_ERROR, "The returned surface does not correspond to any frame\n"); return AVERROR_BUG; @@ -400,8 +383,6 @@ static int do_qsv_decode(AVCodecContext *avctx, QSVContext *q, av_fifo_generic_write(q->async_fifo, &sync, sizeof(sync), NULL); continue; - } else { - av_freep(&sync); } if (MFX_ERR_MORE_SURFACE != ret && ret < 0) break; @@ -409,7 +390,7 @@ static int do_qsv_decode(AVCodecContext *avctx, QSVContext *q, /* make sure we do not enter an infinite loop if the SDK * did not consume any data and did not return anything */ - if (!*sync && !bs.DataOffset && !flush) { + if (!sync && !bs.DataOffset && !flush) { av_log(avctx, AV_LOG_WARNING, "A decode call did not consume any data\n"); bs.DataOffset = avpkt->size; } @@ -423,7 +404,6 @@ static int do_qsv_decode(AVCodecContext *avctx, QSVContext *q, } if (MFX_ERR_MORE_DATA!=ret && ret < 0) { - av_freep(&sync); av_log(avctx, AV_LOG_ERROR, "Error %d during QSV decoding.\n", ret); return ff_qsv_error(ret); } @@ -437,11 +417,9 @@ static int do_qsv_decode(AVCodecContext *avctx, QSVContext *q, out_frame->queued = 0; do { - ret = MFXVideoCORE_SyncOperation(q->session, *sync, 1000); + ret = MFXVideoCORE_SyncOperation(q->session, sync, 1000); } while (ret == MFX_WRN_IN_EXECUTION); - av_freep(&sync); - src_frame = out_frame->frame; ret = av_frame_ref(frame, src_frame); From 9bd35a76fc94e2ac633c9b3e831859e2846e59ea Mon Sep 17 00:00:00 2001 From: Carl Eugen Hoyos Date: Fri, 22 Jul 2016 19:24:15 +0200 Subject: [PATCH 15/71] lavc/h264_ps: Be more verbose when truncating likely oversized PPS. --- libavcodec/h264_ps.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libavcodec/h264_ps.c b/libavcodec/h264_ps.c index 3bcc6e15b30b4..7d1cf192714ab 100644 --- a/libavcodec/h264_ps.c +++ b/libavcodec/h264_ps.c @@ -732,7 +732,9 @@ int ff_h264_decode_picture_parameter_set(GetBitContext *gb, AVCodecContext *avct pps->data_size = gb->buffer_end - gb->buffer; if (pps->data_size > sizeof(pps->data)) { - av_log(avctx, AV_LOG_WARNING, "Truncating likely oversized PPS\n"); + av_log(avctx, AV_LOG_WARNING, "Truncating likely oversized PPS " + "(%"SIZE_SPECIFIER" > %"SIZE_SPECIFIER")\n", + pps->data_size, sizeof(pps->data)); pps->data_size = sizeof(pps->data); } memcpy(pps->data, gb->buffer, pps->data_size); From 2adbea4e216ce38a8bf6c72de16267c9162c174d Mon Sep 17 00:00:00 2001 From: Matthieu Bouron Date: Sun, 24 Jul 2016 22:26:47 +0200 Subject: [PATCH 16/71] lavc: always build dnxhddata lavc/movenc rely on avpriv_dnxhd_parse_header_prefix declared by dnxhddata.h since e47981dab7fb7c9499b959cb0125b7281301969a. Fixes a missing symbol error in lavc/movenc if the dnxhd encoder is not enabled. --- libavcodec/Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libavcodec/Makefile b/libavcodec/Makefile index abef19e18b590..4fc4b09067008 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -32,6 +32,7 @@ OBJS = allcodecs.o \ codec_desc.o \ d3d11va.o \ dirac.o \ + dnxhddata.o \ dv_profile.o \ imgconvert.o \ jni.o \ @@ -241,8 +242,8 @@ OBJS-$(CONFIG_DIRAC_DECODER) += diracdec.o dirac.o diracdsp.o diractab dirac_arith.o mpeg12data.o dirac_dwt.o \ dirac_vlc.o OBJS-$(CONFIG_DFA_DECODER) += dfa.o -OBJS-$(CONFIG_DNXHD_DECODER) += dnxhddec.o dnxhddata.o -OBJS-$(CONFIG_DNXHD_ENCODER) += dnxhdenc.o dnxhddata.o +OBJS-$(CONFIG_DNXHD_DECODER) += dnxhddec.o +OBJS-$(CONFIG_DNXHD_ENCODER) += dnxhdenc.o OBJS-$(CONFIG_DPX_DECODER) += dpx.o OBJS-$(CONFIG_DPX_ENCODER) += dpxenc.o OBJS-$(CONFIG_DSD_LSBF_DECODER) += dsddec.o dsd.o From 71167f7f8434341b3f76da68a10923b6525e2e87 Mon Sep 17 00:00:00 2001 From: Carl Eugen Hoyos Date: Sun, 24 Jul 2016 23:50:33 +0200 Subject: [PATCH 17/71] lavc/Makefile: Fix standalone compilation of the svq3 decoder. Regression since 0bf5fd2e --- libavcodec/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 4fc4b09067008..2564ab8be65c8 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -532,7 +532,8 @@ OBJS-$(CONFIG_SUNRAST_ENCODER) += sunrastenc.o OBJS-$(CONFIG_SVQ1_DECODER) += svq1dec.o svq1.o svq13.o h263data.o OBJS-$(CONFIG_SVQ1_ENCODER) += svq1enc.o svq1.o h263data.o \ h263.o ituh263enc.o -OBJS-$(CONFIG_SVQ3_DECODER) += svq3.o svq13.o mpegutils.o h264_parse.o h264data.o +OBJS-$(CONFIG_SVQ3_DECODER) += svq3.o svq13.o mpegutils.o \ + h264_parse.o h264data.o h264_ps.o h2645_parse.o OBJS-$(CONFIG_TEXT_DECODER) += textdec.o ass.o OBJS-$(CONFIG_TEXT_ENCODER) += srtenc.o ass_split.o OBJS-$(CONFIG_TAK_DECODER) += takdec.o tak.o takdsp.o From 26cb7232c3432faa7a83d52dbff4503530f833ab Mon Sep 17 00:00:00 2001 From: James Almer Date: Mon, 25 Jul 2016 12:19:31 -0300 Subject: [PATCH 18/71] Revert "lavc: always build dnxhddata" This reverts commit 2adbea4e216ce38a8bf6c72de16267c9162c174d. A better solution will follow in the next commit. --- libavcodec/Makefile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 2564ab8be65c8..a548e02597f6c 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -32,7 +32,6 @@ OBJS = allcodecs.o \ codec_desc.o \ d3d11va.o \ dirac.o \ - dnxhddata.o \ dv_profile.o \ imgconvert.o \ jni.o \ @@ -242,8 +241,8 @@ OBJS-$(CONFIG_DIRAC_DECODER) += diracdec.o dirac.o diracdsp.o diractab dirac_arith.o mpeg12data.o dirac_dwt.o \ dirac_vlc.o OBJS-$(CONFIG_DFA_DECODER) += dfa.o -OBJS-$(CONFIG_DNXHD_DECODER) += dnxhddec.o -OBJS-$(CONFIG_DNXHD_ENCODER) += dnxhdenc.o +OBJS-$(CONFIG_DNXHD_DECODER) += dnxhddec.o dnxhddata.o +OBJS-$(CONFIG_DNXHD_ENCODER) += dnxhdenc.o dnxhddata.o OBJS-$(CONFIG_DPX_DECODER) += dpx.o OBJS-$(CONFIG_DPX_ENCODER) += dpxenc.o OBJS-$(CONFIG_DSD_LSBF_DECODER) += dsddec.o dsd.o From 0c75bd8e3cd7f92a65878fc643d17d7826ecc561 Mon Sep 17 00:00:00 2001 From: James Almer Date: Mon, 25 Jul 2016 12:09:22 -0300 Subject: [PATCH 19/71] avcodec/dnxhddata: move avpriv_dnxhd_parse_header_prefix to a header It's a small and simple function that can be inlined. This removes one private symbol and should reduce object dependencies with the next major bump Signed-off-by: James Almer --- libavcodec/dnxhddata.c | 7 +++---- libavcodec/dnxhddata.h | 11 +++++++++++ libavcodec/dnxhddec.c | 2 +- libavformat/dnxhddec.c | 2 +- libavformat/movenc.c | 2 +- 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/libavcodec/dnxhddata.c b/libavcodec/dnxhddata.c index 480b8069cf10c..2011829a06587 100644 --- a/libavcodec/dnxhddata.c +++ b/libavcodec/dnxhddata.c @@ -22,7 +22,6 @@ #include "avcodec.h" #include "dnxhddata.h" #include "libavutil/common.h" -#include "libavutil/intreadwrite.h" /* The quantization tables below are in zigzag order! */ @@ -1103,12 +1102,12 @@ int avpriv_dnxhd_get_interlaced(int cid) return ff_dnxhd_cid_table[i].flags & DNXHD_INTERLACED ? 1 : 0; } +#if LIBAVCODEC_VERSION_MAJOR < 58 uint64_t avpriv_dnxhd_parse_header_prefix(const uint8_t *buf) { - uint64_t prefix = AV_RB32(buf); - prefix = (prefix << 16) | buf[4] << 8; - return ff_dnxhd_check_header_prefix(prefix); + return ff_dnxhd_parse_header_prefix(buf); } +#endif static int dnxhd_find_hr_cid(AVCodecContext *avctx) { diff --git a/libavcodec/dnxhddata.h b/libavcodec/dnxhddata.h index 06e7128d4d7c2..89262a13c1c33 100644 --- a/libavcodec/dnxhddata.h +++ b/libavcodec/dnxhddata.h @@ -25,6 +25,7 @@ #include #include "avcodec.h" #include "libavutil/internal.h" +#include "libavutil/intreadwrite.h" /** Additional profile info flags */ #define DNXHD_INTERLACED (1<<0) @@ -83,7 +84,17 @@ static av_always_inline uint64_t ff_dnxhd_check_header_prefix(uint64_t prefix) return 0; } +static av_always_inline uint64_t ff_dnxhd_parse_header_prefix(const uint8_t *buf) +{ + uint64_t prefix = AV_RB32(buf); + prefix = (prefix << 16) | buf[4] << 8; + return ff_dnxhd_check_header_prefix(prefix); +} + int avpriv_dnxhd_get_frame_size(int cid); int avpriv_dnxhd_get_interlaced(int cid); +#if LIBAVCODEC_VERSION_MAJOR < 58 +attribute_deprecated uint64_t avpriv_dnxhd_parse_header_prefix(const uint8_t *buf); +#endif #endif /* AVCODEC_DNXHDDATA_H */ diff --git a/libavcodec/dnxhddec.c b/libavcodec/dnxhddec.c index 627bc3b5e4e04..4d3a4a6d22289 100644 --- a/libavcodec/dnxhddec.c +++ b/libavcodec/dnxhddec.c @@ -190,7 +190,7 @@ static int dnxhd_decode_header(DNXHDContext *ctx, AVFrame *frame, return AVERROR_INVALIDDATA; } - header_prefix = avpriv_dnxhd_parse_header_prefix(buf); + header_prefix = ff_dnxhd_parse_header_prefix(buf); if (header_prefix == 0) { av_log(ctx->avctx, AV_LOG_ERROR, "unknown header 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\n", diff --git a/libavformat/dnxhddec.c b/libavformat/dnxhddec.c index 48c890d1853df..0ad51b597b530 100644 --- a/libavformat/dnxhddec.c +++ b/libavformat/dnxhddec.c @@ -30,7 +30,7 @@ static int dnxhd_probe(AVProbeData *p) int w, h, compression_id; if (p->buf_size < 0x2c) return 0; - if (avpriv_dnxhd_parse_header_prefix(p->buf) == 0) + if (ff_dnxhd_parse_header_prefix(p->buf) == 0) return 0; h = AV_RB16(p->buf + 0x18); w = AV_RB16(p->buf + 0x1a); diff --git a/libavformat/movenc.c b/libavformat/movenc.c index 014b465b1c32c..9064cec1a16c4 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -1071,7 +1071,7 @@ static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track) int cid; if (track->vos_data && track->vos_len > 0x29) { - if (avpriv_dnxhd_parse_header_prefix(track->vos_data) != 0) { + if (ff_dnxhd_parse_header_prefix(track->vos_data) != 0) { /* looks like a DNxHD bit stream */ interlaced = (track->vos_data[5] & 2); cid = AV_RB32(track->vos_data + 0x28); From e947b75b1c76ef6793209c2c445b8c224a28717a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Sat, 23 Jul 2016 23:47:39 +0200 Subject: [PATCH 20/71] libavformat/rtpdec_asf: zero initialize the AVIOContext struct This fixes crash in avformat_open_input() when accessing protocol_whitelist field. Signed-off-by: Michael Niedermayer --- libavformat/rtpdec_asf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavformat/rtpdec_asf.c b/libavformat/rtpdec_asf.c index 8459a513fb6b0..2c09fda10b7dc 100644 --- a/libavformat/rtpdec_asf.c +++ b/libavformat/rtpdec_asf.c @@ -101,7 +101,7 @@ int ff_wms_parse_sdp_a_line(AVFormatContext *s, const char *p) { int ret = 0; if (av_strstart(p, "pgmpu:data:application/vnd.ms.wms-hdr.asfv1;base64,", &p)) { - AVIOContext pb; + AVIOContext pb = { 0 }; RTSPState *rt = s->priv_data; AVDictionary *opts = NULL; int len = strlen(p) * 6 / 8; From 384251daffb98d88b0fe897b341bb68445f885de Mon Sep 17 00:00:00 2001 From: Josh de Kock Date: Sun, 24 Jul 2016 19:49:40 +0100 Subject: [PATCH 21/71] lavd/libdc1394: distinguish between enumeration errors and no cameras found Signed-off-by: Michael Niedermayer --- libavdevice/libdc1394.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/libavdevice/libdc1394.c b/libavdevice/libdc1394.c index 43fa23292252d..60c61466524b3 100644 --- a/libavdevice/libdc1394.c +++ b/libavdevice/libdc1394.c @@ -302,9 +302,14 @@ static int dc1394_v2_read_header(AVFormatContext *c) /* Now let us prep the hardware. */ dc1394->d = dc1394_new(); - dc1394_camera_enumerate (dc1394->d, &list); - if ( !list || list->num == 0) { - av_log(c, AV_LOG_ERROR, "Unable to look for an IIDC camera\n\n"); + if (dc1394_camera_enumerate(dc1394->d, &list) != DC1394_SUCCESS || !list) { + av_log(c, AV_LOG_ERROR, "Unable to look for an IIDC camera.\n"); + goto out; + } + + if (list->num == 0) { + av_log(c, AV_LOG_ERROR, "No cameras found.\n"); + dc1394_camera_free_list(list); goto out; } From fb91850fe11f9e727b405a92c134b07bdc277921 Mon Sep 17 00:00:00 2001 From: James Almer Date: Mon, 25 Jul 2016 15:04:42 -0300 Subject: [PATCH 22/71] avutil/frame: access avframe fields directly in get_frame_defaults() The accessors are needed only from outside libavutil. Reviewed-by: Michael Niedermayer Signed-off-by: James Almer --- libavutil/frame.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libavutil/frame.c b/libavutil/frame.c index d5c7c9f32f940..662c20d124f19 100644 --- a/libavutil/frame.c +++ b/libavutil/frame.c @@ -101,10 +101,10 @@ static void get_frame_defaults(AVFrame *frame) frame->pts = frame->pkt_dts = frame->pkt_pts = AV_NOPTS_VALUE; - av_frame_set_best_effort_timestamp(frame, AV_NOPTS_VALUE); - av_frame_set_pkt_duration (frame, 0); - av_frame_set_pkt_pos (frame, -1); - av_frame_set_pkt_size (frame, -1); + frame->best_effort_timestamp = AV_NOPTS_VALUE; + frame->pkt_duration = 0; + frame->pkt_pos = -1; + frame->pkt_size = -1; frame->key_frame = 1; frame->sample_aspect_ratio = (AVRational){ 0, 1 }; frame->format = -1; /* unknown */ From dc151d138c9e7e59acdffb7bea11ab6dcea3b380 Mon Sep 17 00:00:00 2001 From: Dmitry Vagin Date: Fri, 22 Jul 2016 08:52:00 +0300 Subject: [PATCH 23/71] ffprobe: add missing PROGRAM_STREAM_TAGS case ffprobe did not show tags with only '-show_entries programs' Signed-off-by: Michael Niedermayer --- ffprobe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ffprobe.c b/ffprobe.c index b9c37603848bc..a49be6a3f83d2 100644 --- a/ffprobe.c +++ b/ffprobe.c @@ -3277,6 +3277,7 @@ int main(int argc, char **argv) SET_DO_SHOW(FRAME_TAGS, frame_tags); SET_DO_SHOW(PROGRAM_TAGS, program_tags); SET_DO_SHOW(STREAM_TAGS, stream_tags); + SET_DO_SHOW(PROGRAM_STREAM_TAGS, stream_tags); SET_DO_SHOW(PACKET_TAGS, packet_tags); if (do_bitexact && (do_show_program_version || do_show_library_versions)) { From be04c4aa0029bef68503c26428af7074befedda9 Mon Sep 17 00:00:00 2001 From: James Almer Date: Tue, 26 Jul 2016 15:22:32 -0300 Subject: [PATCH 24/71] avformt/matroskaenc: undo an accidental revert by commit 5d48e4ea Commit 5d48e4eafa6c4559683892b8638d10508125f3cf accidentally reverted changes made to matroskaenc by commit 989a614b707dcff8abdffe28dc24ec64a83b2837. Signed-off-by: James Almer --- libavformat/matroskaenc.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index 833e77d2b55c8..3648d4945306e 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -1561,20 +1561,23 @@ static int mkv_write_header(AVFormatContext *s) if ((tag = av_dict_get(s->metadata, "title", NULL, 0))) put_ebml_string(pb, MATROSKA_ID_TITLE, tag->value); if (!(s->flags & AVFMT_FLAG_BITEXACT)) { - uint32_t segment_uid[4]; - AVLFG lfg; - - av_lfg_init(&lfg, av_get_random_seed()); - - for (i = 0; i < 4; i++) - segment_uid[i] = av_lfg_get(&lfg); - put_ebml_string(pb, MATROSKA_ID_MUXINGAPP, LIBAVFORMAT_IDENT); if ((tag = av_dict_get(s->metadata, "encoding_tool", NULL, 0))) put_ebml_string(pb, MATROSKA_ID_WRITINGAPP, tag->value); else put_ebml_string(pb, MATROSKA_ID_WRITINGAPP, LIBAVFORMAT_IDENT); - put_ebml_binary(pb, MATROSKA_ID_SEGMENTUID, segment_uid, 16); + + if (mkv->mode != MODE_WEBM) { + uint32_t segment_uid[4]; + AVLFG lfg; + + av_lfg_init(&lfg, av_get_random_seed()); + + for (i = 0; i < 4; i++) + segment_uid[i] = av_lfg_get(&lfg); + + put_ebml_binary(pb, MATROSKA_ID_SEGMENTUID, segment_uid, 16); + } } else { const char *ident = "Lavf"; put_ebml_string(pb, MATROSKA_ID_MUXINGAPP , ident); From e85d38c20a8893cb59d7c86f74481f2497882196 Mon Sep 17 00:00:00 2001 From: Luca Barbato Date: Wed, 22 Jun 2016 06:36:31 +0200 Subject: [PATCH 25/71] librtmp: Avoid an infiniloop setting connection arguments The exit condition was missing. Signed-off-by: Timothy Gu --- libavformat/librtmp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libavformat/librtmp.c b/libavformat/librtmp.c index 0fea675b38749..146df660acfe7 100644 --- a/libavformat/librtmp.c +++ b/libavformat/librtmp.c @@ -193,6 +193,8 @@ static int rtmp_open(URLContext *s, const char *uri, int flags) if (sep) p = sep + 1; + else + break; } } if (ctx->playpath) { From c6e900e9258ab51714ae02136f6bbbb018277303 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20B=C5=93sch?= Date: Tue, 26 Jul 2016 21:22:22 +0200 Subject: [PATCH 26/71] lavfi/curves: fix meaningless const int returned value Spotted-by: James Almer --- libavfilter/vf_curves.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libavfilter/vf_curves.c b/libavfilter/vf_curves.c index 64e4fa46dbdc4..fef9a0efbb148 100644 --- a/libavfilter/vf_curves.c +++ b/libavfilter/vf_curves.c @@ -334,8 +334,8 @@ static inline int interpolate(void *log_ctx, uint16_t *y, } #define DECLARE_INTERPOLATE_FUNC(nbits) \ -static const int interpolate##nbits(void *log_ctx, uint16_t *y, \ - const struct keypoint *points) \ +static int interpolate##nbits(void *log_ctx, uint16_t *y, \ + const struct keypoint *points) \ { \ return interpolate(log_ctx, y, points, nbits); \ } From 726501a34ea4bf2222ca8e856ba6cf107b48465f Mon Sep 17 00:00:00 2001 From: "Ronald S. Bultje" Date: Wed, 13 Jul 2016 12:37:21 -0400 Subject: [PATCH 27/71] vp9: add 32x32 idct AVX2 implementation. About 1.8x speedup compared to AVX version for full IDCT. Other sub-IDCT scenarios also see speedups. Full --bench output for idct_32x32_add_{bpp}_${subidct}_${opt} (50k cycles): nop: 16.5 vp9_inv_dct_dct_32x32_add_8_1_c: 2284.4 vp9_inv_dct_dct_32x32_add_8_1_sse2: 145.0 vp9_inv_dct_dct_32x32_add_8_1_ssse3: 137.4 vp9_inv_dct_dct_32x32_add_8_1_avx: 137.1 vp9_inv_dct_dct_32x32_add_8_1_avx2: 73.2 vp9_inv_dct_dct_32x32_add_8_2_c: 14680.8 vp9_inv_dct_dct_32x32_add_8_2_sse2: 2617.2 vp9_inv_dct_dct_32x32_add_8_2_ssse3: 982.9 vp9_inv_dct_dct_32x32_add_8_2_avx: 958.5 vp9_inv_dct_dct_32x32_add_8_2_avx2: 704.2 vp9_inv_dct_dct_32x32_add_8_4_c: 14443.1 vp9_inv_dct_dct_32x32_add_8_4_sse2: 2717.1 vp9_inv_dct_dct_32x32_add_8_4_ssse3: 965.7 vp9_inv_dct_dct_32x32_add_8_4_avx: 1000.7 vp9_inv_dct_dct_32x32_add_8_4_avx2: 717.1 vp9_inv_dct_dct_32x32_add_8_8_c: 14436.4 vp9_inv_dct_dct_32x32_add_8_8_sse2: 2671.8 vp9_inv_dct_dct_32x32_add_8_8_ssse3: 1038.5 vp9_inv_dct_dct_32x32_add_8_8_avx: 983.0 vp9_inv_dct_dct_32x32_add_8_8_avx2: 729.4 vp9_inv_dct_dct_32x32_add_8_16_c: 14614.7 vp9_inv_dct_dct_32x32_add_8_16_sse2: 2701.7 vp9_inv_dct_dct_32x32_add_8_16_ssse3: 1334.4 vp9_inv_dct_dct_32x32_add_8_16_avx: 1276.7 vp9_inv_dct_dct_32x32_add_8_16_avx2: 719.5 vp9_inv_dct_dct_32x32_add_8_32_c: 14363.6 vp9_inv_dct_dct_32x32_add_8_32_sse2: 2575.6 vp9_inv_dct_dct_32x32_add_8_32_ssse3: 2633.9 vp9_inv_dct_dct_32x32_add_8_32_avx: 2539.6 vp9_inv_dct_dct_32x32_add_8_32_avx2: 1395.0 --- libavcodec/x86/vp9dsp_init.c | 2 + libavcodec/x86/vp9itxfm.asm | 228 ++++++++++++++++++++++++++++++++++- 2 files changed, 224 insertions(+), 6 deletions(-) diff --git a/libavcodec/x86/vp9dsp_init.c b/libavcodec/x86/vp9dsp_init.c index 6fa63ae0ec69c..10751e58364d5 100644 --- a/libavcodec/x86/vp9dsp_init.c +++ b/libavcodec/x86/vp9dsp_init.c @@ -115,6 +115,7 @@ itxfm_func(idct, idct, 32, ssse3); itxfm_func(idct, idct, 32, avx); itxfm_func(iwht, iwht, 4, mmx); itxfm_func(idct, idct, 16, avx2); +itxfm_func(idct, idct, 32, avx2); #undef itxfm_func #undef itxfm_funcs @@ -384,6 +385,7 @@ av_cold void ff_vp9dsp_init_x86(VP9DSPContext *dsp, int bpp, int bitexact) if (ARCH_X86_64) { #if ARCH_X86_64 && HAVE_AVX2_EXTERNAL dsp->itxfm_add[TX_16X16][DCT_DCT] = ff_vp9_idct_idct_16x16_add_avx2; + dsp->itxfm_add[TX_32X32][DCT_DCT] = ff_vp9_idct_idct_32x32_add_avx2; init_subpel3_32_64(0, put, 8, avx2); init_subpel3_32_64(1, avg, 8, avx2); #endif diff --git a/libavcodec/x86/vp9itxfm.asm b/libavcodec/x86/vp9itxfm.asm index 7308b57ed02d4..57d6d353bd86d 100644 --- a/libavcodec/x86/vp9itxfm.asm +++ b/libavcodec/x86/vp9itxfm.asm @@ -1539,13 +1539,12 @@ cglobal vp9_idct_idct_16x16_add, 4, 4, 16, dst, stride, block, eob jg .idctfull ; dc-only - movd xm0, [blockq] mova m1, [pw_11585x2] + vpbroadcastw m0, [blockq] pmulhrsw m0, m1 pmulhrsw m0, m1 - vpbroadcastw m0, xm0 - pmulhrsw m0, [pw_512] pxor m5, m5 + pmulhrsw m0, [pw_512] movd [blockq], xm5 DEFINE_ARGS dst, stride, stride3, cnt @@ -1993,7 +1992,12 @@ IADST16_FN iadst, IADST16, iadst, IADST16, avx ;--------------------------------------------------------------------------------------------- %macro VP9_IDCT32_1D 2-3 32 ; src, pass, nnzc -%assign %%str 16*%2*%2 +%if %2 == 1 +%assign %%str mmsize +%else +%assign %%str 64 +%endif + ; first do t0-15, this can be done identical to idct16x16 VP9_IDCT16_1D_START %1, %3/2, 64*2, tmpq, 2*%%str, 1 @@ -2288,17 +2292,125 @@ IADST16_FN iadst, IADST16, iadst, IADST16, avx mova m3, [tmpq+20*%%str] ; t5 mova m13, [tmpq+24*%%str] ; t6 - SUMSUB_BA w, 6, 8, 10 + SUMSUB_BA w, 6, 8, 10 mova [tmpq+ 3*%%str], m8 ; t15 - mova m10, [tmpq+28*%%str] ; t7 SUMSUB_BA w, 0, 9, 8 SUMSUB_BA w, 15, 12, 8 SUMSUB_BA w, 14, 11, 8 SUMSUB_BA w, 1, 2, 8 SUMSUB_BA w, 7, 3, 8 SUMSUB_BA w, 5, 13, 8 + mova m10, [tmpq+28*%%str] ; t7 SUMSUB_BA w, 4, 10, 8 +%if cpuflag(avx2) + ; the "shitty" about this idct is that the final pass does the outermost + ; interleave sumsubs (t0/31, t1/30, etc) but the tN for the 16x16 need + ; to be sequential, which means I need to load/store half of the sumsub + ; intermediates back to/from memory to get a 16x16 transpose going... + ; This would be easier if we had more (e.g. 32) YMM regs here. + mova [tmpq+ 7*%%str], m9 + mova [tmpq+11*%%str], m12 + mova [tmpq+15*%%str], m11 + mova [tmpq+19*%%str], m2 + mova [tmpq+23*%%str], m3 + mova [tmpq+27*%%str], m13 + mova [tmpq+31*%%str], m10 + mova [tmpq+12*%%str], m5 + + mova m13, [tmpq+30*%%str] ; t8 + mova m12, [tmpq+26*%%str] ; t9 + mova m11, [tmpq+22*%%str] ; t10 + mova m10, [tmpq+18*%%str] ; t11 + mova m9, [tmpq+17*%%str] ; t20 + mova m8, [tmpq+ 1*%%str] ; t21 + mova m3, [tmpq+25*%%str] ; t22 + mova m2, [tmpq+ 5*%%str] ; t23 + + SUMSUB_BA w, 9, 10, 5 + SUMSUB_BA w, 8, 11, 5 + SUMSUB_BA w, 3, 12, 5 + SUMSUB_BA w, 2, 13, 5 + mova [tmpq+ 1*%%str], m10 + mova [tmpq+ 5*%%str], m11 + mova [tmpq+17*%%str], m12 + mova [tmpq+25*%%str], m13 + + mova m13, [tmpq+14*%%str] ; t12 + mova m12, [tmpq+10*%%str] ; t13 + mova m11, [tmpq+ 9*%%str] ; t18 + mova m10, [tmpq+13*%%str] ; t19 + + SUMSUB_BA w, 11, 12, 5 + SUMSUB_BA w, 10, 13, 5 + mova [tmpq+ 9*%%str], m13 + mova [tmpq+13*%%str], m12 + mova [tmpq+10*%%str], m10 + mova [tmpq+14*%%str], m11 + mova m13, [tmpq+ 6*%%str] ; t14 + mova m12, [tmpq+ 2*%%str] ; t15 + mova m11, [tmpq+21*%%str] ; t16 + mova m10, [tmpq+29*%%str] ; t17 + SUMSUB_BA w, 11, 12, 5 + SUMSUB_BA w, 10, 13, 5 + mova [tmpq+21*%%str], m12 + mova [tmpq+29*%%str], m13 + mova m12, [tmpq+10*%%str] + mova m13, [tmpq+14*%%str] + + TRANSPOSE16x16W 6, 0, 15, 14, 1, 7, 5, 4, \ + 2, 3, 8, 9, 12, 13, 10, 11, \ + [tmpq+12*%%str], [tmpq+ 8*%%str], 1 + mova [tmpq+ 0*%%str], m6 + mova [tmpq+ 2*%%str], m0 + mova [tmpq+ 4*%%str], m15 + mova [tmpq+ 6*%%str], m14 + mova [tmpq+10*%%str], m7 + mova [tmpq+12*%%str], m5 + mova [tmpq+14*%%str], m4 + mova [tmpq+16*%%str], m2 + mova [tmpq+18*%%str], m3 + mova [tmpq+20*%%str], m8 + mova [tmpq+22*%%str], m9 + mova [tmpq+24*%%str], m12 + mova [tmpq+26*%%str], m13 + mova [tmpq+28*%%str], m10 + mova [tmpq+30*%%str], m11 + + mova m0, [tmpq+21*%%str] + mova m1, [tmpq+29*%%str] + mova m2, [tmpq+13*%%str] + mova m3, [tmpq+ 9*%%str] + mova m4, [tmpq+ 1*%%str] + mova m5, [tmpq+ 5*%%str] + mova m7, [tmpq+25*%%str] + mova m8, [tmpq+31*%%str] + mova m9, [tmpq+27*%%str] + mova m10, [tmpq+23*%%str] + mova m11, [tmpq+19*%%str] + mova m12, [tmpq+15*%%str] + mova m13, [tmpq+11*%%str] + mova m14, [tmpq+ 7*%%str] + mova m15, [tmpq+ 3*%%str] + TRANSPOSE16x16W 0, 1, 2, 3, 4, 5, 6, 7, \ + 8, 9, 10, 11, 12, 13, 14, 15, \ + [tmpq+17*%%str], [tmpq+ 9*%%str], 1 + mova [tmpq+ 1*%%str], m0 + mova [tmpq+ 3*%%str], m1 + mova [tmpq+ 5*%%str], m2 + mova [tmpq+ 7*%%str], m3 + mova [tmpq+11*%%str], m5 + mova [tmpq+13*%%str], m6 + mova [tmpq+15*%%str], m7 + mova [tmpq+17*%%str], m8 + mova [tmpq+19*%%str], m9 + mova [tmpq+21*%%str], m10 + mova [tmpq+23*%%str], m11 + mova [tmpq+25*%%str], m12 + mova [tmpq+27*%%str], m13 + mova [tmpq+29*%%str], m14 + mova [tmpq+31*%%str], m15 +%else ; !avx2 TRANSPOSE8x8W 6, 0, 15, 14, 1, 7, 5, 4, 8 mova [tmpq+ 0*%%str], m6 mova [tmpq+ 4*%%str], m0 @@ -2367,6 +2479,7 @@ IADST16_FN iadst, IADST16, iadst, IADST16, avx mova [tmpq+22*%%str], m13 mova [tmpq+26*%%str], m14 mova [tmpq+30*%%str], m15 +%endif ; avx2 %else mova m2, [tmpq+24*%%str] ; t6 mova m3, [tmpq+28*%%str] ; t7 @@ -2815,3 +2928,106 @@ cglobal vp9_idct_idct_32x32_add, 0, 6 + ARCH_X86_64 * 3, 16, 2048, dst, stride, VP9_IDCT_IDCT_32x32_ADD_XMM sse2 VP9_IDCT_IDCT_32x32_ADD_XMM ssse3 VP9_IDCT_IDCT_32x32_ADD_XMM avx + +; this is almost identical to VP9_STORE_2X, but it does two rows +; for slightly improved interleaving, and it omits vpermq since the +; input is DC so all values are identical +%macro VP9_STORE_YMM_DC_2X2 6 ; reg, tmp1, tmp2, tmp3, tmp4, zero + mova m%2, [dstq] + mova m%4, [dstq+strideq] + punpckhbw m%3, m%2, m%6 + punpcklbw m%2, m%6 + punpckhbw m%5, m%4, m%6 + punpcklbw m%4, m%6 + paddw m%3, m%1 + paddw m%2, m%1 + paddw m%5, m%1 + paddw m%4, m%1 + packuswb m%2, m%3 + packuswb m%4, m%5 + mova [dstq+strideq*0], m%2 + mova [dstq+strideq*1], m%4 +%endmacro + +%if ARCH_X86_64 && HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +cglobal vp9_idct_idct_32x32_add, 4, 9, 16, 2048, dst, stride, block, eob + cmp eobd, 135 + jg .idctfull + cmp eobd, 1 + jg .idct16x16 + + ; dc-only case + mova m1, [pw_11585x2] + vpbroadcastw m0, [blockq] + pmulhrsw m0, m1 + pmulhrsw m0, m1 + pxor m5, m5 + pmulhrsw m0, [pw_512] + movd [blockq], xm5 + + DEFINE_ARGS dst, stride, cnt + mov cntd, 16 +.loop_dc: + VP9_STORE_YMM_DC_2X2 0, 1, 2, 3, 4, 5 + lea dstq, [dstq+2*strideq] + dec cntd + jg .loop_dc + RET + + DEFINE_ARGS dst_bak, stride, block, cnt, dst, stride30, dst_end, stride2, tmp +.idct16x16: + mov tmpq, rsp + VP9_IDCT32_1D blockq, 1, 16 + + mov stride30q, strideq ; stride + lea stride2q, [strideq*2] ; stride*2 + shl stride30q, 5 ; stride*32 + mov cntd, 2 + sub stride30q, stride2q ; stride*30 +.loop2_16x16: + mov dstq, dst_bakq + lea dst_endq, [dstq+stride30q] + VP9_IDCT32_1D tmpq, 2, 16 + add dst_bakq, 16 + add tmpq, 32 + dec cntd + jg .loop2_16x16 + + ; at the end of the loop, m1 should still be zero + ; use that to zero out block coefficients + ZERO_BLOCK blockq, 64, 16, m1 + RET + +.idctfull: + mov cntd, 2 + mov tmpq, rsp +.loop1_full: + VP9_IDCT32_1D blockq, 1 + add blockq, 32 + add tmpq, 1024 + dec cntd + jg .loop1_full + + sub blockq, 64 + + mov stride30q, strideq ; stride + lea stride2q, [strideq*2] ; stride*2 + shl stride30q, 5 ; stride*32 + mov cntd, 2 + mov tmpq, rsp + sub stride30q, stride2q ; stride*30 +.loop2_full: + mov dstq, dst_bakq + lea dst_endq, [dstq+stride30q] + VP9_IDCT32_1D tmpq, 2 + add dst_bakq, 16 + add tmpq, 32 + dec cntd + jg .loop2_full + + ; at the end of the loop, m1 should still be zero + ; use that to zero out block coefficients + ZERO_BLOCK blockq, 64, 32, m1 + RET +%endif From 7ca422bb1b8f80f8412a229454a8ac6bd9655ae8 Mon Sep 17 00:00:00 2001 From: "Ronald S. Bultje" Date: Tue, 19 Jul 2016 12:06:32 -0400 Subject: [PATCH 28/71] vp9: add mxext versions of the single-block (w=4,npx=8) h/v loopfilters. Each takes about 0.5% of runtime in my profiles, and they didn't have any SIMD yet so far (we only had simd for npx=16 double-block versions). --- libavcodec/x86/vp9dsp_init.c | 3 + libavcodec/x86/vp9lpf.asm | 149 +++++++++++++++++++++++------------ 2 files changed, 103 insertions(+), 49 deletions(-) diff --git a/libavcodec/x86/vp9dsp_init.c b/libavcodec/x86/vp9dsp_init.c index 10751e58364d5..359d38e480412 100644 --- a/libavcodec/x86/vp9dsp_init.c +++ b/libavcodec/x86/vp9dsp_init.c @@ -126,6 +126,7 @@ void ff_vp9_loop_filter_v_##size1##_##size2##_##opt(uint8_t *dst, ptrdiff_t stri void ff_vp9_loop_filter_h_##size1##_##size2##_##opt(uint8_t *dst, ptrdiff_t stride, \ int E, int I, int H) +lpf_funcs(4, 8, mmxext); lpf_funcs(16, 16, sse2); lpf_funcs(16, 16, ssse3); lpf_funcs(16, 16, avx); @@ -281,6 +282,8 @@ av_cold void ff_vp9dsp_init_x86(VP9DSPContext *dsp, int bpp, int bitexact) } if (EXTERNAL_MMXEXT(cpu_flags)) { + dsp->loop_filter_8[0][0] = ff_vp9_loop_filter_h_4_8_mmxext; + dsp->loop_filter_8[0][1] = ff_vp9_loop_filter_v_4_8_mmxext; init_subpel2(4, 0, 4, put, 8, mmxext); init_subpel2(4, 1, 4, avg, 8, mmxext); init_fpel_func(4, 1, 4, avg, _8, mmxext); diff --git a/libavcodec/x86/vp9lpf.asm b/libavcodec/x86/vp9lpf.asm index 2c4fe214da62e..56bba4d11356f 100644 --- a/libavcodec/x86/vp9lpf.asm +++ b/libavcodec/x86/vp9lpf.asm @@ -52,7 +52,7 @@ mask_mix48: times 8 db 0x00 SECTION .text %macro SCRATCH 3 -%if ARCH_X86_64 +%ifdef m8 SWAP %1, %2 %else mova [%3], m%1 @@ -60,7 +60,7 @@ SECTION .text %endmacro %macro UNSCRATCH 3 -%if ARCH_X86_64 +%ifdef m8 SWAP %1, %2 %else mova m%1, [%3] @@ -69,7 +69,7 @@ SECTION .text ; %1 = abs(%2-%3) %macro ABSSUB 4 ; dst, src1 (RO), src2 (RO), tmp -%if ARCH_X86_64 +%ifdef m8 psubusb %1, %3, %2 psubusb %4, %2, %3 %else @@ -102,7 +102,7 @@ SECTION .text %endmacro %macro UNPACK 4 -%if ARCH_X86_64 +%ifdef m8 punpck%1bw %2, %3, %4 %else mova %2, %3 @@ -334,22 +334,24 @@ SECTION .text %endmacro %macro DEFINE_TRANSPOSED_P7_TO_Q7 0-1 0 -%define P3 rsp + 0 + %1 -%define P2 rsp + 16 + %1 -%define P1 rsp + 32 + %1 -%define P0 rsp + 48 + %1 -%define Q0 rsp + 64 + %1 -%define Q1 rsp + 80 + %1 -%define Q2 rsp + 96 + %1 -%define Q3 rsp + 112 + %1 -%define P7 rsp + 128 + %1 -%define P6 rsp + 144 + %1 -%define P5 rsp + 160 + %1 -%define P4 rsp + 176 + %1 -%define Q4 rsp + 192 + %1 -%define Q5 rsp + 208 + %1 -%define Q6 rsp + 224 + %1 -%define Q7 rsp + 240 + %1 +%define P3 rsp + 0*mmsize + %1 +%define P2 rsp + 1*mmsize + %1 +%define P1 rsp + 2*mmsize + %1 +%define P0 rsp + 3*mmsize + %1 +%define Q0 rsp + 4*mmsize + %1 +%define Q1 rsp + 5*mmsize + %1 +%define Q2 rsp + 6*mmsize + %1 +%define Q3 rsp + 7*mmsize + %1 +%if mmsize == 16 +%define P7 rsp + 8*mmsize + %1 +%define P6 rsp + 9*mmsize + %1 +%define P5 rsp + 10*mmsize + %1 +%define P4 rsp + 11*mmsize + %1 +%define Q4 rsp + 12*mmsize + %1 +%define Q5 rsp + 13*mmsize + %1 +%define Q6 rsp + 14*mmsize + %1 +%define Q7 rsp + 15*mmsize + %1 +%endif %endmacro ; ..............AB -> AAAAAAAABBBBBBBB @@ -365,12 +367,12 @@ SECTION .text %macro LOOPFILTER 5 ; %1=v/h %2=size1 %3+%4=stack, %5=32bit stack only %if UNIX64 -cglobal vp9_loop_filter_%1_%2_16, 5, 9, 16, %3 + %4, dst, stride, E, I, H, mstride, dst2, stride3, mstride3 +cglobal vp9_loop_filter_%1_%2_ %+ mmsize, 5, 9, 16, %3 + %4, dst, stride, E, I, H, mstride, dst2, stride3, mstride3 %else %if WIN64 -cglobal vp9_loop_filter_%1_%2_16, 4, 8, 16, %3 + %4, dst, stride, E, I, mstride, dst2, stride3, mstride3 +cglobal vp9_loop_filter_%1_%2_ %+ mmsize, 4, 8, 16, %3 + %4, dst, stride, E, I, mstride, dst2, stride3, mstride3 %else -cglobal vp9_loop_filter_%1_%2_16, 2, 6, 16, %3 + %4 + %5, dst, stride, mstride, dst2, stride3, mstride3 +cglobal vp9_loop_filter_%1_%2_ %+ mmsize, 2, 6, 16, %3 + %4 + %5, dst, stride, mstride, dst2, stride3, mstride3 %define Ed dword r2m %define Id dword r3m %endif @@ -384,18 +386,22 @@ cglobal vp9_loop_filter_%1_%2_16, 2, 6, 16, %3 + %4 + %5, dst, stride, mstride, lea mstride3q, [mstrideq*3] %ifidn %1, h -%if %2 > 16 +%if %2 != 16 +%if mmsize == 16 %define movx movh +%else +%define movx mova +%endif lea dstq, [dstq + 4*strideq - 4] %else %define movx movu lea dstq, [dstq + 4*strideq - 8] ; go from top center (h pos) to center left (v pos) %endif - lea dst2q, [dstq + 8*strideq] %else lea dstq, [dstq + 4*mstrideq] - lea dst2q, [dstq + 8*strideq] %endif + ; FIXME we shouldn't need two dts registers if mmsize == 8 + lea dst2q, [dstq + 8*strideq] DEFINE_REAL_P7_TO_Q7 @@ -406,11 +412,11 @@ cglobal vp9_loop_filter_%1_%2_16, 2, 6, 16, %3 + %4 + %5, dst, stride, mstride, movx m3, [P4] movx m4, [P3] movx m5, [P2] -%if ARCH_X86_64 || %2 != 16 +%if (ARCH_X86_64 && mmsize == 16) || %2 > 16 movx m6, [P1] %endif movx m7, [P0] -%if ARCH_X86_64 +%ifdef m8 movx m8, [Q0] movx m9, [Q1] movx m10, [Q2] @@ -502,7 +508,7 @@ cglobal vp9_loop_filter_%1_%2_16, 2, 6, 16, %3 + %4 + %5, dst, stride, mstride, movhps [Q5], m6 movhps [Q7], m7 DEFINE_TRANSPOSED_P7_TO_Q7 -%else ; %2 == 44/48/84/88 +%elif %2 > 16 ; %2 == 44/48/84/88 punpcklbw m0, m1 punpcklbw m2, m3 punpcklbw m4, m5 @@ -529,12 +535,31 @@ cglobal vp9_loop_filter_%1_%2_16, 2, 6, 16, %3 + %4 + %5, dst, stride, mstride, mova [Q1], m5 mova [Q2], m7 mova [Q3], m3 +%else ; %2 == 4 || %2 == 8 + SBUTTERFLY bw, 0, 1, 6 + SBUTTERFLY bw, 2, 3, 6 + SBUTTERFLY bw, 4, 5, 6 + mova [rsp+4*mmsize], m5 + mova m6, [P1] + SBUTTERFLY bw, 6, 7, 5 + DEFINE_TRANSPOSED_P7_TO_Q7 + TRANSPOSE4x4W 0, 2, 4, 6, 5 + mova [P3], m0 + mova [P2], m2 + mova [P1], m4 + mova [P0], m6 + mova m5, [rsp+4*mmsize] + TRANSPOSE4x4W 1, 3, 5, 7, 0 + mova [Q0], m1 + mova [Q1], m3 + mova [Q2], m5 + mova [Q3], m7 %endif ; %2 %endif ; x86-32/64 %endif ; %1 == h ; calc fm mask -%if %2 == 16 +%if %2 == 16 || mmsize == 8 %if cpuflag(ssse3) pxor m0, m0 %endif @@ -552,7 +577,7 @@ cglobal vp9_loop_filter_%1_%2_16, 2, 6, 16, %3 + %4 + %5, dst, stride, mstride, mova m0, [pb_80] pxor m2, m0 pxor m3, m0 -%if ARCH_X86_64 +%ifdef m8 %ifidn %1, v mova m8, [P3] mova m9, [P2] @@ -613,10 +638,10 @@ cglobal vp9_loop_filter_%1_%2_16, 2, 6, 16, %3 + %4 + %5, dst, stride, mstride, ; (m3: fm, m8..15: p3 p2 p1 p0 q0 q1 q2 q3) ; calc flat8in (if not 44_16) and hev masks -%if %2 != 44 +%if %2 != 44 && %2 != 4 mova m6, [pb_81] ; [1 1 1 1 ...] ^ 0x80 ABSSUB_GT m2, rp3, rp0, m6, m5 ; abs(p3 - p0) <= 1 -%if ARCH_X86_64 +%ifdef m8 mova m8, [pb_80] %define rb80 m8 %else @@ -655,8 +680,15 @@ cglobal vp9_loop_filter_%1_%2_16, 2, 6, 16, %3 + %4 + %5, dst, stride, mstride, %endif %else mova m6, [pb_80] +%if %2 == 44 movd m7, Hd SPLATB_MIX m7 +%else +%if cpuflag(ssse3) + pxor m0, m0 +%endif + SPLATB_REG m7, H, m0 ; H H H H ... +%endif pxor m7, m6 ABSSUB m4, rp1, rp0, m1 ; abs(p1 - p0) pxor m4, m6 @@ -670,7 +702,7 @@ cglobal vp9_loop_filter_%1_%2_16, 2, 6, 16, %3 + %4 + %5, dst, stride, mstride, %if %2 == 16 ; (m0: hev, m2: flat8in, m3: fm, m6: pb_81, m9..15: p2 p1 p0 q0 q1 q2 q3) ; calc flat8out mask -%if ARCH_X86_64 +%ifdef m8 mova m8, [P7] mova m9, [P6] %define rp7 m8 @@ -682,7 +714,7 @@ cglobal vp9_loop_filter_%1_%2_16, 2, 6, 16, %3 + %4 + %5, dst, stride, mstride, ABSSUB_GT m1, rp7, rp0, m6, m5 ; abs(p7 - p0) <= 1 ABSSUB_GT m7, rp6, rp0, m6, m5 ; abs(p6 - p0) <= 1 por m1, m7 -%if ARCH_X86_64 +%ifdef m8 mova m8, [P5] mova m9, [P4] %define rp5 m8 @@ -695,7 +727,7 @@ cglobal vp9_loop_filter_%1_%2_16, 2, 6, 16, %3 + %4 + %5, dst, stride, mstride, por m1, m7 ABSSUB_GT m7, rp4, rp0, m6, m5 ; abs(p4 - p0) <= 1 por m1, m7 -%if ARCH_X86_64 +%ifdef m8 mova m14, [Q4] mova m15, [Q5] %define rq4 m14 @@ -708,7 +740,7 @@ cglobal vp9_loop_filter_%1_%2_16, 2, 6, 16, %3 + %4 + %5, dst, stride, mstride, por m1, m7 ABSSUB_GT m7, rq5, rq0, m6, m5 ; abs(q5 - q0) <= 1 por m1, m7 -%if ARCH_X86_64 +%ifdef m8 mova m14, [Q6] mova m15, [Q7] %define rq6 m14 @@ -738,7 +770,7 @@ cglobal vp9_loop_filter_%1_%2_16, 2, 6, 16, %3 + %4 + %5, dst, stride, mstride, ; (m0: hev, [m1: flat8out], [m2: flat8in], m3: fm, m8..15: p5 p4 p1 p0 q0 q1 q6 q7) ; filter2() -%if %2 != 44 +%if %2 != 44 && %2 != 4 mova m6, [pb_80] ; already in m6 if 44_16 SCRATCH 2, 15, rsp+%3+%4 %if %2 == 16 @@ -756,7 +788,7 @@ cglobal vp9_loop_filter_%1_%2_16, 2, 6, 16, %3 + %4 + %5, dst, stride, mstride, paddsb m4, m2 ; 3*(q0 - p0) + (p1 - q1) paddsb m6, m4, [pb_4] ; m6: f1 = clip(f + 4, 127) paddsb m4, [pb_3] ; m4: f2 = clip(f + 3, 127) -%if ARCH_X86_64 +%ifdef m8 mova m14, [pb_10] ; will be reused in filter4() %define rb10 m14 %else @@ -765,8 +797,8 @@ cglobal vp9_loop_filter_%1_%2_16, 2, 6, 16, %3 + %4 + %5, dst, stride, mstride, SRSHIFT3B_2X m6, m4, rb10, m7 ; f1 and f2 sign byte shift by 3 SIGN_SUB m7, rq0, m6, m5 ; m7 = q0 - f1 SIGN_ADD m1, rp0, m4, m5 ; m1 = p0 + f2 -%if %2 != 44 -%if ARCH_X86_64 +%if %2 != 44 && %2 != 4 +%ifdef m8 pandn m6, m15, m3 ; ~mask(in) & mask(fm) %else mova m6, [rsp+%3+%4] @@ -787,8 +819,8 @@ cglobal vp9_loop_filter_%1_%2_16, 2, 6, 16, %3 + %4 + %5, dst, stride, mstride, paddsb m6, m2, [pb_4] ; m6: f1 = clip(f + 4, 127) paddsb m2, [pb_3] ; m2: f2 = clip(f + 3, 127) SRSHIFT3B_2X m6, m2, rb10, m4 ; f1 and f2 sign byte shift by 3 -%if %2 != 44 -%if ARCH_X86_64 +%if %2 != 44 && %2 != 4 +%ifdef m8 pandn m5, m15, m3 ; ~mask(in) & mask(fm) %else mova m5, [rsp+%3+%4] @@ -815,26 +847,26 @@ cglobal vp9_loop_filter_%1_%2_16, 2, 6, 16, %3 + %4 + %5, dst, stride, mstride, mova [P1], m1 mova [Q1], m4 -%if %2 != 44 +%if %2 != 44 && %2 != 4 UNSCRATCH 2, 15, rsp+%3+%4 %endif ; ([m1: flat8out], m2: flat8in, m3: fm, m10..13: p1 p0 q0 q1) ; filter6() -%if %2 != 44 +%if %2 != 44 && %2 != 4 pxor m0, m0 %if %2 > 16 pand m3, m2 %else pand m2, m3 ; mask(fm) & mask(in) -%if ARCH_X86_64 +%ifdef m8 pandn m3, m8, m2 ; ~mask(out) & (mask(fm) & mask(in)) %else mova m3, [rsp+%3+%4+16] pandn m3, m2 %endif %endif -%if ARCH_X86_64 +%ifdef m8 mova m14, [P3] mova m9, [Q3] %define rp3 m14 @@ -882,7 +914,7 @@ cglobal vp9_loop_filter_%1_%2_16, 2, 6, 16, %3 + %4 + %5, dst, stride, mstride, pand m1, m2 ; mask(out) & (mask(fm) & mask(in)) mova m2, [P7] mova m3, [P6] -%if ARCH_X86_64 +%ifdef m8 mova m8, [P5] mova m9, [P4] %define rp5 m8 @@ -1008,7 +1040,7 @@ cglobal vp9_loop_filter_%1_%2_16, 2, 6, 16, %3 + %4 + %5, dst, stride, mstride, movhps [Q5], m6 movhps [Q7], m7 %endif -%elif %2 == 44 +%elif %2 == 44 || %2 == 4 SWAP 0, 1 ; m0 = p1 SWAP 1, 7 ; m1 = p0 SWAP 2, 5 ; m2 = q0 @@ -1018,6 +1050,7 @@ cglobal vp9_loop_filter_%1_%2_16, 2, 6, 16, %3 + %4 + %5, dst, stride, mstride, SBUTTERFLY bw, 2, 3, 4 SBUTTERFLY wd, 0, 2, 4 SBUTTERFLY wd, 1, 3, 4 +%if mmsize == 16 movd [P7], m0 movd [P3], m2 movd [Q0], m1 @@ -1046,6 +1079,20 @@ cglobal vp9_loop_filter_%1_%2_16, 2, 6, 16, %3 + %4 + %5, dst, stride, mstride, movd [P0], m2 movd [Q3], m1 movd [Q7], m3 +%else + movd [P7], m0 + movd [P5], m2 + movd [P3], m1 + movd [P1], m3 + psrlq m0, 32 + psrlq m2, 32 + psrlq m1, 32 + psrlq m3, 32 + movd [P6], m0 + movd [P4], m2 + movd [P2], m1 + movd [P0], m3 +%endif %else ; the following code do a transpose of 8 full lines to 16 half ; lines (high part). It is inlined to avoid the need of a staging area @@ -1137,3 +1184,7 @@ LPF_16_VH_ALL_OPTS 44, 0, 128, 0 LPF_16_VH_ALL_OPTS 48, 256, 128, 16 LPF_16_VH_ALL_OPTS 84, 256, 128, 16 LPF_16_VH_ALL_OPTS 88, 256, 128, 16 + +INIT_MMX mmxext +LOOPFILTER v, 4, 0, 0, 0 +LOOPFILTER h, 4, 0, 64, 0 From a4edaa0270587adf4c429c79837810d5261a906a Mon Sep 17 00:00:00 2001 From: "Ronald S. Bultje" Date: Tue, 19 Jul 2016 15:37:46 -0400 Subject: [PATCH 29/71] vp9: add mxext versions of the single-block (w=8,npx=8) h/v loopfilters. Each takes about 0.1% of runtime in my profiles, and they didn't have any SIMD yet so far (we only had simd for npx=16 double-block versions). --- libavcodec/x86/vp9dsp_init.c | 3 ++ libavcodec/x86/vp9lpf.asm | 99 ++++++++++++++++++++++-------------- 2 files changed, 63 insertions(+), 39 deletions(-) diff --git a/libavcodec/x86/vp9dsp_init.c b/libavcodec/x86/vp9dsp_init.c index 359d38e480412..cc781a009bb51 100644 --- a/libavcodec/x86/vp9dsp_init.c +++ b/libavcodec/x86/vp9dsp_init.c @@ -127,6 +127,7 @@ void ff_vp9_loop_filter_h_##size1##_##size2##_##opt(uint8_t *dst, ptrdiff_t stri int E, int I, int H) lpf_funcs(4, 8, mmxext); +lpf_funcs(8, 8, mmxext); lpf_funcs(16, 16, sse2); lpf_funcs(16, 16, ssse3); lpf_funcs(16, 16, avx); @@ -284,6 +285,8 @@ av_cold void ff_vp9dsp_init_x86(VP9DSPContext *dsp, int bpp, int bitexact) if (EXTERNAL_MMXEXT(cpu_flags)) { dsp->loop_filter_8[0][0] = ff_vp9_loop_filter_h_4_8_mmxext; dsp->loop_filter_8[0][1] = ff_vp9_loop_filter_v_4_8_mmxext; + dsp->loop_filter_8[1][0] = ff_vp9_loop_filter_h_8_8_mmxext; + dsp->loop_filter_8[1][1] = ff_vp9_loop_filter_v_8_8_mmxext; init_subpel2(4, 0, 4, put, 8, mmxext); init_subpel2(4, 1, 4, avg, 8, mmxext); init_fpel_func(4, 1, 4, avg, _8, mmxext); diff --git a/libavcodec/x86/vp9lpf.asm b/libavcodec/x86/vp9lpf.asm index 56bba4d11356f..4e7ede22351e9 100644 --- a/libavcodec/x86/vp9lpf.asm +++ b/libavcodec/x86/vp9lpf.asm @@ -112,27 +112,27 @@ SECTION .text %macro FILTER_SUBx2_ADDx2 11 ; %1=dst %2=h/l %3=cache %4=stack_off %5=sub1 %6=sub2 %7=add1 ; %8=add2 %9=rshift, [unpack], [unpack_is_mem_on_x86_32] - psubw %3, [rsp+%4+%5*32] - psubw %3, [rsp+%4+%6*32] - paddw %3, [rsp+%4+%7*32] + psubw %3, [rsp+%4+%5*mmsize*2] + psubw %3, [rsp+%4+%6*mmsize*2] + paddw %3, [rsp+%4+%7*mmsize*2] %ifnidn %10, "" %if %11 == 0 punpck%2bw %1, %10, m0 %else UNPACK %2, %1, %10, m0 %endif - mova [rsp+%4+%8*32], %1 + mova [rsp+%4+%8*mmsize*2], %1 paddw %3, %1 %else - paddw %3, [rsp+%4+%8*32] + paddw %3, [rsp+%4+%8*mmsize*2] %endif psraw %1, %3, %9 %endmacro ; FIXME interleave l/h better (for instruction pairing) %macro FILTER_INIT 9 ; tmp1, tmp2, cacheL, cacheH, dstp, stack_off, filterid, mask, source - FILTER%7_INIT %1, l, %3, %6 + 0 - FILTER%7_INIT %2, h, %4, %6 + 16 + FILTER%7_INIT %1, l, %3, %6 + 0 + FILTER%7_INIT %2, h, %4, %6 + mmsize packuswb %1, %2 MASK_APPLY %1, %9, %8, %2 mova %5, %1 @@ -147,8 +147,8 @@ SECTION .text mova %14, %15 %endif %endif - FILTER_SUBx2_ADDx2 %1, l, %3, %6 + 0, %7, %8, %9, %10, %11, %14, %16 - FILTER_SUBx2_ADDx2 %2, h, %4, %6 + 16, %7, %8, %9, %10, %11, %14, %16 + FILTER_SUBx2_ADDx2 %1, l, %3, %6 + 0, %7, %8, %9, %10, %11, %14, %16 + FILTER_SUBx2_ADDx2 %2, h, %4, %6 + mmsize, %7, %8, %9, %10, %11, %14, %16 packuswb %1, %2 %ifnidn %13, "" MASK_APPLY %1, %13, %12, %2 @@ -195,21 +195,21 @@ SECTION .text %macro FILTER6_INIT 4 ; %1=dst %2=h/l %3=cache, %4=stack_off UNPACK %2, %1, rp3, m0 ; p3: B->W - mova [rsp+%4+0*32], %1 + mova [rsp+%4+0*mmsize*2], %1 paddw %3, %1, %1 ; p3*2 paddw %3, %1 ; p3*3 punpck%2bw %1, m1, m0 ; p2: B->W - mova [rsp+%4+1*32], %1 + mova [rsp+%4+1*mmsize*2], %1 paddw %3, %1 ; p3*3 + p2 paddw %3, %1 ; p3*3 + p2*2 UNPACK %2, %1, rp1, m0 ; p1: B->W - mova [rsp+%4+2*32], %1 + mova [rsp+%4+2*mmsize*2], %1 paddw %3, %1 ; p3*3 + p2*2 + p1 UNPACK %2, %1, rp0, m0 ; p0: B->W - mova [rsp+%4+3*32], %1 + mova [rsp+%4+3*mmsize*2], %1 paddw %3, %1 ; p3*3 + p2*2 + p1 + p0 UNPACK %2, %1, rq0, m0 ; q0: B->W - mova [rsp+%4+4*32], %1 + mova [rsp+%4+4*mmsize*2], %1 paddw %3, %1 ; p3*3 + p2*2 + p1 + p0 + q0 paddw %3, [pw_4] ; p3*3 + p2*2 + p1 + p0 + q0 + 4 psraw %1, %3, 3 ; (p3*3 + p2*2 + p1 + p0 + q0 + 4) >> 3 @@ -217,24 +217,24 @@ SECTION .text %macro FILTER14_INIT 4 ; %1=dst %2=h/l %3=cache, %4=stack_off punpck%2bw %1, m2, m0 ; p7: B->W - mova [rsp+%4+ 8*32], %1 + mova [rsp+%4+ 8*mmsize*2], %1 psllw %3, %1, 3 ; p7*8 psubw %3, %1 ; p7*7 punpck%2bw %1, m3, m0 ; p6: B->W - mova [rsp+%4+ 9*32], %1 + mova [rsp+%4+ 9*mmsize*2], %1 paddw %3, %1 ; p7*7 + p6 paddw %3, %1 ; p7*7 + p6*2 UNPACK %2, %1, rp5, m0 ; p5: B->W - mova [rsp+%4+10*32], %1 + mova [rsp+%4+10*mmsize*2], %1 paddw %3, %1 ; p7*7 + p6*2 + p5 UNPACK %2, %1, rp4, m0 ; p4: B->W - mova [rsp+%4+11*32], %1 + mova [rsp+%4+11*mmsize*2], %1 paddw %3, %1 ; p7*7 + p6*2 + p5 + p4 - paddw %3, [rsp+%4+ 0*32] ; p7*7 + p6*2 + p5 + p4 + p3 - paddw %3, [rsp+%4+ 1*32] ; p7*7 + p6*2 + p5 + .. + p2 - paddw %3, [rsp+%4+ 2*32] ; p7*7 + p6*2 + p5 + .. + p1 - paddw %3, [rsp+%4+ 3*32] ; p7*7 + p6*2 + p5 + .. + p0 - paddw %3, [rsp+%4+ 4*32] ; p7*7 + p6*2 + p5 + .. + p0 + q0 + paddw %3, [rsp+%4+ 0*mmsize*2] ; p7*7 + p6*2 + p5 + p4 + p3 + paddw %3, [rsp+%4+ 1*mmsize*2] ; p7*7 + p6*2 + p5 + .. + p2 + paddw %3, [rsp+%4+ 2*mmsize*2] ; p7*7 + p6*2 + p5 + .. + p1 + paddw %3, [rsp+%4+ 3*mmsize*2] ; p7*7 + p6*2 + p5 + .. + p0 + paddw %3, [rsp+%4+ 4*mmsize*2] ; p7*7 + p6*2 + p5 + .. + p0 + q0 paddw %3, [pw_8] ; p7*7 + p6*2 + p5 + .. + p0 + q0 + 8 psraw %1, %3, 4 ; (p7*7 + p6*2 + p5 + .. + p0 + q0 + 8) >> 4 %endmacro @@ -365,14 +365,19 @@ SECTION .text %endif %endmacro -%macro LOOPFILTER 5 ; %1=v/h %2=size1 %3+%4=stack, %5=32bit stack only +%macro LOOPFILTER 5 ; %1=v/h %2=size1 %3+%4=stack, %5=mmx/32bit stack only +%assign %%ext 0 +%if ARCH_X86_32 || mmsize == 8 +%assign %%ext %5 +%endif + %if UNIX64 -cglobal vp9_loop_filter_%1_%2_ %+ mmsize, 5, 9, 16, %3 + %4, dst, stride, E, I, H, mstride, dst2, stride3, mstride3 +cglobal vp9_loop_filter_%1_%2_ %+ mmsize, 5, 9, 16, %3 + %4 + %%ext, dst, stride, E, I, H, mstride, dst2, stride3, mstride3 %else %if WIN64 -cglobal vp9_loop_filter_%1_%2_ %+ mmsize, 4, 8, 16, %3 + %4, dst, stride, E, I, mstride, dst2, stride3, mstride3 +cglobal vp9_loop_filter_%1_%2_ %+ mmsize, 4, 8, 16, %3 + %4 + %%ext, dst, stride, E, I, mstride, dst2, stride3, mstride3 %else -cglobal vp9_loop_filter_%1_%2_ %+ mmsize, 2, 6, 16, %3 + %4 + %5, dst, stride, mstride, dst2, stride3, mstride3 +cglobal vp9_loop_filter_%1_%2_ %+ mmsize, 2, 6, 16, %3 + %4 + %%ext, dst, stride, mstride, dst2, stride3, mstride3 %define Ed dword r2m %define Id dword r3m %endif @@ -650,7 +655,7 @@ cglobal vp9_loop_filter_%1_%2_ %+ mmsize, 2, 6, 16, %3 + %4 + %5, dst, stride, m ABSSUB_GT m1, rp2, rp0, m6, m5, rb80 ; abs(p2 - p0) <= 1 por m2, m1 ABSSUB m4, rp1, rp0, m5 ; abs(p1 - p0) -%if %2 == 16 +%if %2 <= 16 %if cpuflag(ssse3) pxor m0, m0 %endif @@ -855,7 +860,7 @@ cglobal vp9_loop_filter_%1_%2_ %+ mmsize, 2, 6, 16, %3 + %4 + %5, dst, stride, m ; filter6() %if %2 != 44 && %2 != 4 pxor m0, m0 -%if %2 > 16 +%if %2 != 16 pand m3, m2 %else pand m2, m3 ; mask(fm) & mask(in) @@ -1102,12 +1107,12 @@ cglobal vp9_loop_filter_%1_%2_ %+ mmsize, 2, 6, 16, %3 + %4 + %5, dst, stride, m mova m3, [P0] mova m4, [Q0] mova m5, [Q1] -%if ARCH_X86_64 +%ifdef m8 mova m6, [Q2] %endif mova m7, [Q3] DEFINE_REAL_P7_TO_Q7 -%if ARCH_X86_64 +%ifdef m8 SBUTTERFLY bw, 0, 1, 8 SBUTTERFLY bw, 2, 3, 8 SBUTTERFLY bw, 4, 5, 8 @@ -1122,27 +1127,32 @@ cglobal vp9_loop_filter_%1_%2_ %+ mmsize, 2, 6, 16, %3 + %4 + %5, dst, stride, m SBUTTERFLY dq, 3, 7, 8 %else SBUTTERFLY bw, 0, 1, 6 - mova [rsp+64], m1 - mova m6, [rsp+96] + mova [rsp+mmsize*4], m1 + mova m6, [rsp+mmsize*6] SBUTTERFLY bw, 2, 3, 1 SBUTTERFLY bw, 4, 5, 1 SBUTTERFLY bw, 6, 7, 1 SBUTTERFLY wd, 0, 2, 1 - mova [rsp+96], m2 - mova m1, [rsp+64] + mova [rsp+mmsize*6], m2 + mova m1, [rsp+mmsize*4] SBUTTERFLY wd, 1, 3, 2 SBUTTERFLY wd, 4, 6, 2 SBUTTERFLY wd, 5, 7, 2 SBUTTERFLY dq, 0, 4, 2 SBUTTERFLY dq, 1, 5, 2 +%if mmsize == 16 movh [Q0], m1 movhps [Q1], m1 - mova m2, [rsp+96] +%else + mova [P3], m1 +%endif + mova m2, [rsp+mmsize*6] SBUTTERFLY dq, 2, 6, 1 SBUTTERFLY dq, 3, 7, 1 %endif SWAP 3, 6 SWAP 1, 4 +%if mmsize == 16 movh [P7], m0 movhps [P6], m0 movh [P5], m1 @@ -1151,7 +1161,7 @@ cglobal vp9_loop_filter_%1_%2_ %+ mmsize, 2, 6, 16, %3 + %4 + %5, dst, stride, m movhps [P2], m2 movh [P1], m3 movhps [P0], m3 -%if ARCH_X86_64 +%ifdef m8 movh [Q0], m4 movhps [Q1], m4 %endif @@ -1161,6 +1171,15 @@ cglobal vp9_loop_filter_%1_%2_ %+ mmsize, 2, 6, 16, %3 + %4 + %5, dst, stride, m movhps [Q5], m6 movh [Q6], m7 movhps [Q7], m7 +%else + mova [P7], m0 + mova [P6], m1 + mova [P5], m2 + mova [P4], m3 + mova [P2], m5 + mova [P1], m6 + mova [P0], m7 +%endif %endif %endif @@ -1186,5 +1205,7 @@ LPF_16_VH_ALL_OPTS 84, 256, 128, 16 LPF_16_VH_ALL_OPTS 88, 256, 128, 16 INIT_MMX mmxext -LOOPFILTER v, 4, 0, 0, 0 -LOOPFILTER h, 4, 0, 64, 0 +LOOPFILTER v, 4, 0, 0, 0 +LOOPFILTER h, 4, 0, 64, 0 +LOOPFILTER v, 8, 128, 0, 8 +LOOPFILTER h, 8, 128, 64, 8 From c2fcf4fa0b121c96301b58b53997ab906360ff32 Mon Sep 17 00:00:00 2001 From: Josh de Kock Date: Fri, 22 Jul 2016 16:09:06 +0100 Subject: [PATCH 30/71] avdev/jack: remove duplicated dispatch macros The macros were moved to compat/dispatch_semaphore/semaphore.h after a libav merge, and were never removed from jack.c --- libavdevice/jack.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/libavdevice/jack.c b/libavdevice/jack.c index 34e21527a74fd..076078ce6de7c 100644 --- a/libavdevice/jack.c +++ b/libavdevice/jack.c @@ -35,16 +35,6 @@ #include "timefilter.h" #include "avdevice.h" -#if HAVE_DISPATCH_DISPATCH_H -#include -#define sem_t dispatch_semaphore_t -#define sem_init(psem,x,val) *psem = dispatch_semaphore_create(val) -#define sem_post(psem) dispatch_semaphore_signal(*psem) -#define sem_wait(psem) dispatch_semaphore_wait(*psem, DISPATCH_TIME_FOREVER) -#define sem_timedwait(psem, val) dispatch_semaphore_wait(*psem, dispatch_walltime(val, 0)) -#define sem_destroy(psem) dispatch_release(*psem) -#endif - /** * Size of the internal FIFO buffers as a number of audio packets */ From 461073e8091456c91842a43a44bb6cb98164d610 Mon Sep 17 00:00:00 2001 From: dericed Date: Tue, 7 Jun 2016 19:53:40 -0400 Subject: [PATCH 31/71] ffprobe.xsd: add missing timecode attribute to frameSideDataType Signed-off-by: Michael Niedermayer --- doc/ffprobe.xsd | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/ffprobe.xsd b/doc/ffprobe.xsd index c7d5101965ac2..757de12e8ccf3 100644 --- a/doc/ffprobe.xsd +++ b/doc/ffprobe.xsd @@ -129,6 +129,7 @@ + From 54a0a52be100d36291084f92b7d6aee1a4960acb Mon Sep 17 00:00:00 2001 From: James Almer Date: Tue, 26 Jul 2016 22:16:21 -0300 Subject: [PATCH 32/71] checkasm/vp9dsp: use declare_func_emms in check_loopfilter Fixes checkasm failures on mmxext functions Signed-off-by: James Almer --- tests/checkasm/vp9dsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/checkasm/vp9dsp.c b/tests/checkasm/vp9dsp.c index 931f7882b5b31..441041c2b0ef4 100644 --- a/tests/checkasm/vp9dsp.c +++ b/tests/checkasm/vp9dsp.c @@ -448,7 +448,7 @@ static void check_loopfilter(void) static const char *const dir_name[2] = { "h", "v" }; static const int E[2] = { 20, 28 }, I[2] = { 10, 16 }; static const int H[2] = { 7, 11 }, F[2] = { 1, 1 }; - declare_func(void, uint8_t *dst, ptrdiff_t stride, int E, int I, int H); + declare_func_emms(AV_CPU_FLAG_MMX | AV_CPU_FLAG_MMXEXT, void, uint8_t *dst, ptrdiff_t stride, int E, int I, int H); for (bit_depth = 8; bit_depth <= 12; bit_depth += 2) { ff_vp9dsp_init(&dsp, bit_depth, 0); From c5d326f551b0312ff581bf1df35b21d956e01523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Fri, 24 Jun 2016 00:58:17 +0300 Subject: [PATCH 33/71] Add an OpenH264 decoder wrapper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is cherrypicked from libav, from commits 82b7525173f20702a8cbc26ebedbf4b69b8fecec and d0b1e6049b06eeeeca146ece4d2f199c5dba1565. Signed-off-by: Martin Storsjö --- Changelog | 1 + configure | 2 + doc/general.texi | 9 +- libavcodec/Makefile | 3 +- libavcodec/allcodecs.c | 2 +- libavcodec/libopenh264.c | 62 +++++++++ libavcodec/libopenh264.h | 39 ++++++ libavcodec/libopenh264dec.c | 243 ++++++++++++++++++++++++++++++++++++ libavcodec/libopenh264enc.c | 48 ++----- libavcodec/version.h | 2 +- 10 files changed, 366 insertions(+), 45 deletions(-) create mode 100644 libavcodec/libopenh264.c create mode 100644 libavcodec/libopenh264.h create mode 100644 libavcodec/libopenh264dec.c diff --git a/Changelog b/Changelog index 479f1648c09de..7f536db30baaf 100644 --- a/Changelog +++ b/Changelog @@ -10,6 +10,7 @@ version : - curves filter doesn't automatically insert points at x=0 and x=1 anymore - 16-bit support in curves filter - 16-bit support in selectivecolor filter +- OpenH264 decoder wrapper version 3.1: diff --git a/configure b/configure index 1b41303e74c4b..9f5b31f5f2ed9 100755 --- a/configure +++ b/configure @@ -2771,6 +2771,8 @@ libopencore_amrnb_decoder_deps="libopencore_amrnb" libopencore_amrnb_encoder_deps="libopencore_amrnb" libopencore_amrnb_encoder_select="audio_frame_queue" libopencore_amrwb_decoder_deps="libopencore_amrwb" +libopenh264_decoder_deps="libopenh264" +libopenh264_decoder_select="h264_mp4toannexb_bsf" libopenh264_encoder_deps="libopenh264" libopenjpeg_decoder_deps="libopenjpeg" libopenjpeg_encoder_deps="libopenjpeg" diff --git a/doc/general.texi b/doc/general.texi index 7823dc13cf787..6b5975c6d488e 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -103,12 +103,19 @@ enable it. @section OpenH264 -FFmpeg can make use of the OpenH264 library for H.264 encoding. +FFmpeg can make use of the OpenH264 library for H.264 encoding and decoding. Go to @url{http://www.openh264.org/} and follow the instructions for installing the library. Then pass @code{--enable-libopenh264} to configure to enable it. +For decoding, this library is much more limited than the built-in decoder +in libavcodec; currently, this library lacks support for decoding B-frames +and some other main/high profile features. (It currently only supports +constrained baseline profile and CABAC.) Using it is mostly useful for +testing and for taking advantage of Cisco's patent portfolio license +(@url{http://www.openh264.org/BINARY_LICENSE.txt}). + @section x264 FFmpeg can make use of the x264 library for H.264 encoding. diff --git a/libavcodec/Makefile b/libavcodec/Makefile index a548e02597f6c..3def3ad1f8293 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -868,7 +868,8 @@ OBJS-$(CONFIG_LIBMP3LAME_ENCODER) += libmp3lame.o mpegaudiodata.o mpegau OBJS-$(CONFIG_LIBOPENCORE_AMRNB_DECODER) += libopencore-amr.o OBJS-$(CONFIG_LIBOPENCORE_AMRNB_ENCODER) += libopencore-amr.o OBJS-$(CONFIG_LIBOPENCORE_AMRWB_DECODER) += libopencore-amr.o -OBJS-$(CONFIG_LIBOPENH264_ENCODER) += libopenh264enc.o +OBJS-$(CONFIG_LIBOPENH264_DECODER) += libopenh264dec.o libopenh264.o +OBJS-$(CONFIG_LIBOPENH264_ENCODER) += libopenh264enc.o libopenh264.o OBJS-$(CONFIG_LIBOPENJPEG_DECODER) += libopenjpegdec.o OBJS-$(CONFIG_LIBOPENJPEG_ENCODER) += libopenjpegenc.o OBJS-$(CONFIG_LIBOPUS_DECODER) += libopusdec.o libopus.o \ diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 951e199f2e8d9..a1ae61fece4bd 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -623,7 +623,7 @@ void avcodec_register_all(void) /* external libraries, that shouldn't be used by default if one of the * above is available */ - REGISTER_ENCODER(LIBOPENH264, libopenh264); + REGISTER_ENCDEC (LIBOPENH264, libopenh264); REGISTER_DECODER(H264_CUVID, h264_cuvid); REGISTER_ENCODER(H264_NVENC, h264_nvenc); REGISTER_ENCODER(H264_OMX, h264_omx); diff --git a/libavcodec/libopenh264.c b/libavcodec/libopenh264.c new file mode 100644 index 0000000000000..59c61a3a4c802 --- /dev/null +++ b/libavcodec/libopenh264.c @@ -0,0 +1,62 @@ +/* + * OpenH264 shared utils + * Copyright (C) 2014 Martin Storsjo + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include "libavutil/log.h" + +#include "libopenh264.h" + +// Convert libopenh264 log level to equivalent ffmpeg log level. +static int libopenh264_to_ffmpeg_log_level(int libopenh264_log_level) +{ + if (libopenh264_log_level >= WELS_LOG_DETAIL) return AV_LOG_TRACE; + else if (libopenh264_log_level >= WELS_LOG_DEBUG) return AV_LOG_DEBUG; + else if (libopenh264_log_level >= WELS_LOG_INFO) return AV_LOG_VERBOSE; + else if (libopenh264_log_level >= WELS_LOG_WARNING) return AV_LOG_WARNING; + else if (libopenh264_log_level >= WELS_LOG_ERROR) return AV_LOG_ERROR; + else return AV_LOG_QUIET; +} + +void ff_libopenh264_trace_callback(void *ctx, int level, const char *msg) +{ + // The message will be logged only if the requested EQUIVALENT ffmpeg log level is + // less than or equal to the current ffmpeg log level. + int equiv_ffmpeg_log_level = libopenh264_to_ffmpeg_log_level(level); + av_log(ctx, equiv_ffmpeg_log_level, "%s\n", msg); +} + +int ff_libopenh264_check_version(void *logctx) +{ + // Mingw GCC < 4.7 on x86_32 uses an incorrect/buggy ABI for the WelsGetCodecVersion + // function (for functions returning larger structs), thus skip the check in those + // configurations. +#if !defined(_WIN32) || !defined(__GNUC__) || !ARCH_X86_32 || AV_GCC_VERSION_AT_LEAST(4, 7) + OpenH264Version libver = WelsGetCodecVersion(); + if (memcmp(&libver, &g_stCodecVersion, sizeof(libver))) { + av_log(logctx, AV_LOG_ERROR, "Incorrect library version loaded\n"); + return AVERROR(EINVAL); + } +#endif + return 0; +} diff --git a/libavcodec/libopenh264.h b/libavcodec/libopenh264.h new file mode 100644 index 0000000000000..dbb9c5d429eff --- /dev/null +++ b/libavcodec/libopenh264.h @@ -0,0 +1,39 @@ +/* + * OpenH264 shared utils + * Copyright (C) 2014 Martin Storsjo + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_LIBOPENH264_H +#define AVCODEC_LIBOPENH264_H + +#define OPENH264_VER_AT_LEAST(maj, min) \ + ((OPENH264_MAJOR > (maj)) || \ + (OPENH264_MAJOR == (maj) && OPENH264_MINOR >= (min))) + +// This function will be provided to the libopenh264 library. The function will be called +// when libopenh264 wants to log a message (error, warning, info, etc.). The signature for +// this function (defined in .../codec/api/svc/codec_api.h) is: +// +// typedef void (*WelsTraceCallback) (void* ctx, int level, const char* string); + +void ff_libopenh264_trace_callback(void *ctx, int level, const char *msg); + +int ff_libopenh264_check_version(void *logctx); + +#endif /* AVCODEC_LIBOPENH264_H */ diff --git a/libavcodec/libopenh264dec.c b/libavcodec/libopenh264dec.c new file mode 100644 index 0000000000000..f642082182a5a --- /dev/null +++ b/libavcodec/libopenh264dec.c @@ -0,0 +1,243 @@ +/* + * OpenH264 video decoder + * Copyright (C) 2016 Martin Storsjo + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "libavutil/common.h" +#include "libavutil/fifo.h" +#include "libavutil/imgutils.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/mathematics.h" +#include "libavutil/opt.h" + +#include "avcodec.h" +#include "internal.h" +#include "libopenh264.h" + +typedef struct SVCContext { + ISVCDecoder *decoder; + AVBSFContext *bsf; + AVFifoBuffer *packet_fifo; + AVPacket pkt_filtered; +} SVCContext; + +static av_cold int svc_decode_close(AVCodecContext *avctx) +{ + SVCContext *s = avctx->priv_data; + AVPacket pkt; + + if (s->decoder) + WelsDestroyDecoder(s->decoder); + + while (s->packet_fifo && av_fifo_size(s->packet_fifo) >= sizeof(pkt)) { + av_fifo_generic_read(s->packet_fifo, &pkt, sizeof(pkt), NULL); + av_packet_unref(&pkt); + } + + av_bsf_free(&s->bsf); + av_packet_unref(&s->pkt_filtered); + av_fifo_free(s->packet_fifo); + + return 0; +} + +static av_cold int svc_decode_init(AVCodecContext *avctx) +{ + SVCContext *s = avctx->priv_data; + SDecodingParam param = { 0 }; + int err; + int log_level; + WelsTraceCallback callback_function; + + if ((err = ff_libopenh264_check_version(avctx)) < 0) + return err; + + s->packet_fifo = av_fifo_alloc(sizeof(AVPacket)); + if (!s->packet_fifo) { + err = AVERROR(ENOMEM); + goto fail; + } + + if (WelsCreateDecoder(&s->decoder)) { + av_log(avctx, AV_LOG_ERROR, "Unable to create decoder\n"); + err = AVERROR_UNKNOWN; + goto fail; + } + + // Pass all libopenh264 messages to our callback, to allow ourselves to filter them. + log_level = WELS_LOG_DETAIL; + callback_function = ff_libopenh264_trace_callback; + (*s->decoder)->SetOption(s->decoder, DECODER_OPTION_TRACE_LEVEL, &log_level); + (*s->decoder)->SetOption(s->decoder, DECODER_OPTION_TRACE_CALLBACK, (void *)&callback_function); + (*s->decoder)->SetOption(s->decoder, DECODER_OPTION_TRACE_CALLBACK_CONTEXT, (void *)&avctx); + + param.eOutputColorFormat = videoFormatI420; + param.eEcActiveIdc = ERROR_CON_DISABLE; + param.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_DEFAULT; + + if ((*s->decoder)->Initialize(s->decoder, ¶m) != cmResultSuccess) { + av_log(avctx, AV_LOG_ERROR, "Initialize failed\n"); + err = AVERROR_UNKNOWN; + goto fail; + } + + avctx->pix_fmt = AV_PIX_FMT_YUV420P; + +fail: + return err; +} + +static int init_bsf(AVCodecContext *avctx) +{ + SVCContext *s = avctx->priv_data; + const AVBitStreamFilter *filter; + int ret; + + if (s->bsf) + return 0; + + // If the input stream already is annex b, this BSF only passes the + // packets through unchanged. + filter = av_bsf_get_by_name("h264_mp4toannexb"); + if (!filter) + return AVERROR_BUG; + + ret = av_bsf_alloc(filter, &s->bsf); + if (ret < 0) + return ret; + + ret = avcodec_parameters_from_context(s->bsf->par_in, avctx); + if (ret < 0) + return ret; + + s->bsf->time_base_in = avctx->time_base; + + ret = av_bsf_init(s->bsf); + if (ret < 0) + return ret; + + return ret; +} + +static int svc_decode_frame(AVCodecContext *avctx, void *data, + int *got_frame, AVPacket *avpkt) +{ + SVCContext *s = avctx->priv_data; + SBufferInfo info = { 0 }; + uint8_t* ptrs[3]; + int linesize[3]; + AVFrame *avframe = data; + int ret; + DECODING_STATE state; + + if ((ret = init_bsf(avctx)) < 0) + return ret; + + if (avpkt->size) { + AVPacket input_ref = { 0 }; + if (av_fifo_space(s->packet_fifo) < sizeof(input_ref)) { + ret = av_fifo_realloc2(s->packet_fifo, + av_fifo_size(s->packet_fifo) + sizeof(input_ref)); + if (ret < 0) + return ret; + } + + ret = av_packet_ref(&input_ref, avpkt); + if (ret < 0) + return ret; + av_fifo_generic_write(s->packet_fifo, &input_ref, sizeof(input_ref), NULL); + } + + while (!*got_frame) { + /* prepare the input data -- convert to Annex B if needed */ + if (s->pkt_filtered.size <= 0) { + AVPacket input_ref; + + /* no more data */ + if (av_fifo_size(s->packet_fifo) < sizeof(AVPacket)) + return avpkt->size ? avpkt->size : 0; + + av_packet_unref(&s->pkt_filtered); + + av_fifo_generic_read(s->packet_fifo, &input_ref, sizeof(input_ref), NULL); + ret = av_bsf_send_packet(s->bsf, &input_ref); + if (ret < 0) { + av_packet_unref(&input_ref); + return ret; + } + + ret = av_bsf_receive_packet(s->bsf, &s->pkt_filtered); + if (ret < 0) + av_packet_move_ref(&s->pkt_filtered, &input_ref); + else + av_packet_unref(&input_ref); + } + + state = (*s->decoder)->DecodeFrame2(s->decoder, s->pkt_filtered.data, s->pkt_filtered.size, ptrs, &info); + s->pkt_filtered.size = 0; + if (state != dsErrorFree) { + av_log(avctx, AV_LOG_ERROR, "DecodeFrame2 failed\n"); + return AVERROR_UNKNOWN; + } + if (info.iBufferStatus != 1) { + av_log(avctx, AV_LOG_DEBUG, "No frame produced\n"); + continue; + } + + ret = ff_set_dimensions(avctx, info.UsrData.sSystemBuffer.iWidth, info.UsrData.sSystemBuffer.iHeight); + if (ret < 0) + return ret; + // The decoder doesn't (currently) support decoding into a user + // provided buffer, so do a copy instead. + if (ff_get_buffer(avctx, avframe, 0) < 0) { + av_log(avctx, AV_LOG_ERROR, "Unable to allocate buffer\n"); + return AVERROR(ENOMEM); + } + + linesize[0] = info.UsrData.sSystemBuffer.iStride[0]; + linesize[1] = linesize[2] = info.UsrData.sSystemBuffer.iStride[1]; + av_image_copy(avframe->data, avframe->linesize, (const uint8_t **) ptrs, linesize, avctx->pix_fmt, avctx->width, avctx->height); + + avframe->pts = s->pkt_filtered.pts; + avframe->pkt_dts = s->pkt_filtered.dts; + avframe->pkt_pts = s->pkt_filtered.pts; + + *got_frame = 1; + } + return avpkt->size; +} + +AVCodec ff_libopenh264_decoder = { + .name = "libopenh264", + .long_name = NULL_IF_CONFIG_SMALL("OpenH264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_H264, + .priv_data_size = sizeof(SVCContext), + .init = svc_decode_init, + .decode = svc_decode_frame, + .close = svc_decode_close, + // The decoder doesn't currently support B-frames, and the decoder's API + // doesn't support reordering/delay, but the BSF could incur delay. + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS | FF_CODEC_CAP_INIT_THREADSAFE | + FF_CODEC_CAP_INIT_CLEANUP, +}; diff --git a/libavcodec/libopenh264enc.c b/libavcodec/libopenh264enc.c index 24bc228ad92db..d27fc4143a9b1 100644 --- a/libavcodec/libopenh264enc.c +++ b/libavcodec/libopenh264enc.c @@ -31,6 +31,7 @@ #include "avcodec.h" #include "internal.h" +#include "libopenh264.h" typedef struct SVCContext { const AVClass *av_class; @@ -44,10 +45,6 @@ typedef struct SVCContext { int cabac; } SVCContext; -#define OPENH264_VER_AT_LEAST(maj, min) \ - ((OPENH264_MAJOR > (maj)) || \ - (OPENH264_MAJOR == (maj) && OPENH264_MINOR >= (min))) - #define OFFSET(x) offsetof(SVCContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { @@ -68,31 +65,6 @@ static const AVClass class = { "libopenh264enc", av_default_item_name, options, LIBAVUTIL_VERSION_INT }; -// Convert libopenh264 log level to equivalent ffmpeg log level. -static int libopenh264_to_ffmpeg_log_level(int libopenh264_log_level) -{ - if (libopenh264_log_level >= WELS_LOG_DETAIL) return AV_LOG_TRACE; - else if (libopenh264_log_level >= WELS_LOG_DEBUG) return AV_LOG_DEBUG; - else if (libopenh264_log_level >= WELS_LOG_INFO) return AV_LOG_VERBOSE; - else if (libopenh264_log_level >= WELS_LOG_WARNING) return AV_LOG_WARNING; - else if (libopenh264_log_level >= WELS_LOG_ERROR) return AV_LOG_ERROR; - else return AV_LOG_QUIET; -} - -// This function will be provided to the libopenh264 library. The function will be called -// when libopenh264 wants to log a message (error, warning, info, etc.). The signature for -// this function (defined in .../codec/api/svc/codec_api.h) is: -// -// typedef void (*WelsTraceCallback) (void* ctx, int level, const char* string); - -static void libopenh264_trace_callback(void *ctx, int level, const char *msg) -{ - // The message will be logged only if the requested EQUIVALENT ffmpeg log level is - // less than or equal to the current ffmpeg log level. - int equiv_ffmpeg_log_level = libopenh264_to_ffmpeg_log_level(level); - av_log(ctx, equiv_ffmpeg_log_level, "%s\n", msg); -} - static av_cold int svc_encode_close(AVCodecContext *avctx) { SVCContext *s = avctx->priv_data; @@ -108,21 +80,15 @@ static av_cold int svc_encode_init(AVCodecContext *avctx) { SVCContext *s = avctx->priv_data; SEncParamExt param = { 0 }; - int err = AVERROR_UNKNOWN; + int err; int log_level; WelsTraceCallback callback_function; AVCPBProperties *props; - // Mingw GCC < 4.7 on x86_32 uses an incorrect/buggy ABI for the WelsGetCodecVersion - // function (for functions returning larger structs), thus skip the check in those - // configurations. -#if !defined(_WIN32) || !defined(__GNUC__) || !ARCH_X86_32 || AV_GCC_VERSION_AT_LEAST(4, 7) - OpenH264Version libver = WelsGetCodecVersion(); - if (memcmp(&libver, &g_stCodecVersion, sizeof(libver))) { - av_log(avctx, AV_LOG_ERROR, "Incorrect library version loaded\n"); - return AVERROR(EINVAL); - } -#endif + if ((err = ff_libopenh264_check_version(avctx)) < 0) + return err; + // Use a default error for multiple error paths below + err = AVERROR_UNKNOWN; if (WelsCreateSVCEncoder(&s->encoder)) { av_log(avctx, AV_LOG_ERROR, "Unable to create encoder\n"); @@ -134,7 +100,7 @@ static av_cold int svc_encode_init(AVCodecContext *avctx) (*s->encoder)->SetOption(s->encoder, ENCODER_OPTION_TRACE_LEVEL, &log_level); // Set the logging callback function to one that uses av_log() (see implementation above). - callback_function = (WelsTraceCallback) libopenh264_trace_callback; + callback_function = (WelsTraceCallback) ff_libopenh264_trace_callback; (*s->encoder)->SetOption(s->encoder, ENCODER_OPTION_TRACE_CALLBACK, (void *)&callback_function); // Set the AVCodecContext as the libopenh264 callback context so that it can be passed to av_log(). diff --git a/libavcodec/version.h b/libavcodec/version.h index f5883160001c1..4ded1ee05f682 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -28,7 +28,7 @@ #include "libavutil/version.h" #define LIBAVCODEC_VERSION_MAJOR 57 -#define LIBAVCODEC_VERSION_MINOR 50 +#define LIBAVCODEC_VERSION_MINOR 51 #define LIBAVCODEC_VERSION_MICRO 100 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ From 293676c476733e81d7b596736add6cd510eb6960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Fri, 8 Jul 2016 23:21:41 +0300 Subject: [PATCH 34/71] libopenh264: Support building with the 1.6 release MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes trac issue #5417. This is cherry-picked from libav commit d825b1a5306576dcd0553b7d0d24a3a46ad92864. Signed-off-by: Martin Storsjö --- libavcodec/libopenh264dec.c | 2 ++ libavcodec/libopenh264enc.c | 26 ++++++++++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/libavcodec/libopenh264dec.c b/libavcodec/libopenh264dec.c index f642082182a5a..6af60af434c52 100644 --- a/libavcodec/libopenh264dec.c +++ b/libavcodec/libopenh264dec.c @@ -90,7 +90,9 @@ static av_cold int svc_decode_init(AVCodecContext *avctx) (*s->decoder)->SetOption(s->decoder, DECODER_OPTION_TRACE_CALLBACK, (void *)&callback_function); (*s->decoder)->SetOption(s->decoder, DECODER_OPTION_TRACE_CALLBACK_CONTEXT, (void *)&avctx); +#if !OPENH264_VER_AT_LEAST(1, 6) param.eOutputColorFormat = videoFormatI420; +#endif param.eEcActiveIdc = ERROR_CON_DISABLE; param.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_DEFAULT; diff --git a/libavcodec/libopenh264enc.c b/libavcodec/libopenh264enc.c index d27fc4143a9b1..07af31d2ccb05 100644 --- a/libavcodec/libopenh264enc.c +++ b/libavcodec/libopenh264enc.c @@ -33,6 +33,10 @@ #include "internal.h" #include "libopenh264.h" +#if !OPENH264_VER_AT_LEAST(1, 6) +#define SM_SIZELIMITED_SLICE SM_DYN_SLICE +#endif + typedef struct SVCContext { const AVClass *av_class; ISVCEncoder *encoder; @@ -48,11 +52,20 @@ typedef struct SVCContext { #define OFFSET(x) offsetof(SVCContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { +#if OPENH264_VER_AT_LEAST(1, 6) + { "slice_mode", "set slice mode", OFFSET(slice_mode), AV_OPT_TYPE_INT, { .i64 = SM_FIXEDSLCNUM_SLICE }, SM_SINGLE_SLICE, SM_RESERVED, VE, "slice_mode" }, +#else { "slice_mode", "set slice mode", OFFSET(slice_mode), AV_OPT_TYPE_INT, { .i64 = SM_AUTO_SLICE }, SM_SINGLE_SLICE, SM_RESERVED, VE, "slice_mode" }, +#endif { "fixed", "a fixed number of slices", 0, AV_OPT_TYPE_CONST, { .i64 = SM_FIXEDSLCNUM_SLICE }, 0, 0, VE, "slice_mode" }, +#if OPENH264_VER_AT_LEAST(1, 6) + { "dyn", "Size limited (compatibility name)", 0, AV_OPT_TYPE_CONST, { .i64 = SM_SIZELIMITED_SLICE }, 0, 0, VE, "slice_mode" }, + { "sizelimited", "Size limited", 0, AV_OPT_TYPE_CONST, { .i64 = SM_SIZELIMITED_SLICE }, 0, 0, VE, "slice_mode" }, +#else { "rowmb", "one slice per row of macroblocks", 0, AV_OPT_TYPE_CONST, { .i64 = SM_ROWMB_SLICE }, 0, 0, VE, "slice_mode" }, { "auto", "automatic number of slices according to number of threads", 0, AV_OPT_TYPE_CONST, { .i64 = SM_AUTO_SLICE }, 0, 0, VE, "slice_mode" }, { "dyn", "Dynamic slicing", 0, AV_OPT_TYPE_CONST, { .i64 = SM_DYN_SLICE }, 0, 0, VE, "slice_mode" }, +#endif { "loopfilter", "enable loop filter", OFFSET(loopfilter), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, VE }, { "profile", "set profile restrictions", OFFSET(profile), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, VE }, { "max_nal_size", "set maximum NAL size in bytes", OFFSET(max_nal_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, @@ -159,15 +172,24 @@ FF_ENABLE_DEPRECATION_WARNINGS s->slice_mode = SM_FIXEDSLCNUM_SLICE; if (s->max_nal_size) - s->slice_mode = SM_DYN_SLICE; + s->slice_mode = SM_SIZELIMITED_SLICE; +#if OPENH264_VER_AT_LEAST(1, 6) + param.sSpatialLayers[0].sSliceArgument.uiSliceMode = s->slice_mode; + param.sSpatialLayers[0].sSliceArgument.uiSliceNum = avctx->slices; +#else param.sSpatialLayers[0].sSliceCfg.uiSliceMode = s->slice_mode; param.sSpatialLayers[0].sSliceCfg.sSliceArgument.uiSliceNum = avctx->slices; +#endif - if (s->slice_mode == SM_DYN_SLICE) { + if (s->slice_mode == SM_SIZELIMITED_SLICE) { if (s->max_nal_size){ param.uiMaxNalSize = s->max_nal_size; +#if OPENH264_VER_AT_LEAST(1, 6) + param.sSpatialLayers[0].sSliceArgument.uiSliceSizeConstraint = s->max_nal_size; +#else param.sSpatialLayers[0].sSliceCfg.sSliceArgument.uiSliceSizeConstraint = s->max_nal_size; +#endif } else { av_log(avctx, AV_LOG_ERROR, "Invalid -max_nal_size, " "specify a valid max_nal_size to use -slice_mode dyn\n"); From 376d8fb2c5742e6718323d6a69479c6ee68dd75b Mon Sep 17 00:00:00 2001 From: Matthieu Bouron Date: Fri, 1 Jul 2016 09:59:13 +0200 Subject: [PATCH 35/71] lavc/ffjni: replace ff_jni_{attach,detach} with ff_jni_get_env If a JNI environment is not already attached to the thread where the MediaCodec calls are made the current implementation will attach / detach an environment for each MediaCodec call wasting some CPU time. ff_jni_get_env replaces ff_jni_{attach,detach} by permanently attaching an environment (if it is not already the case) to the current thread. The environment will be automatically detached at the thread destruction using a pthread_key callback. Saves around 5% of CPU time (out of 20%) while decoding a stream with MediaCodec. --- libavcodec/ffjni.c | 43 ++++--- libavcodec/ffjni.h | 15 +-- libavcodec/mediacodec.c | 14 +-- libavcodec/mediacodec_surface.c | 14 +-- libavcodec/mediacodec_wrapper.c | 200 +++++++------------------------- 5 files changed, 74 insertions(+), 212 deletions(-) diff --git a/libavcodec/ffjni.c b/libavcodec/ffjni.c index 82ee5d32ae760..13eabb00337b9 100644 --- a/libavcodec/ffjni.c +++ b/libavcodec/ffjni.c @@ -31,25 +31,42 @@ #include "jni.h" #include "ffjni.h" -static JavaVM *java_vm = NULL; +static JavaVM *java_vm; +static pthread_key_t current_env; +static pthread_once_t once = PTHREAD_ONCE_INIT; static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; -JNIEnv *ff_jni_attach_env(int *attached, void *log_ctx) +static void jni_detach_env(void *data) +{ + if (java_vm) { + (*java_vm)->DetachCurrentThread(java_vm); + } +} + +static void jni_create_pthread_key(void) +{ + pthread_key_create(¤t_env, jni_detach_env); +} + +JNIEnv *ff_jni_get_env(void *log_ctx) { int ret = 0; JNIEnv *env = NULL; - *attached = 0; - pthread_mutex_lock(&lock); if (java_vm == NULL) { java_vm = av_jni_get_java_vm(log_ctx); } - pthread_mutex_unlock(&lock); if (!java_vm) { av_log(log_ctx, AV_LOG_ERROR, "No Java virtual machine has been registered\n"); - return NULL; + goto done; + } + + pthread_once(&once, jni_create_pthread_key); + + if ((env = pthread_getspecific(current_env)) != NULL) { + goto done; } ret = (*java_vm)->GetEnv(java_vm, (void **)&env, JNI_VERSION_1_6); @@ -59,7 +76,7 @@ JNIEnv *ff_jni_attach_env(int *attached, void *log_ctx) av_log(log_ctx, AV_LOG_ERROR, "Failed to attach the JNI environment to the current thread\n"); env = NULL; } else { - *attached = 1; + pthread_setspecific(current_env, env); } break; case JNI_OK: @@ -72,19 +89,11 @@ JNIEnv *ff_jni_attach_env(int *attached, void *log_ctx) break; } +done: + pthread_mutex_unlock(&lock); return env; } -int ff_jni_detach_env(void *log_ctx) -{ - if (java_vm == NULL) { - av_log(log_ctx, AV_LOG_ERROR, "No Java virtual machine has been registered\n"); - return AVERROR(EINVAL); - } - - return (*java_vm)->DetachCurrentThread(java_vm); -} - char *ff_jni_jstring_to_utf_chars(JNIEnv *env, jstring string, void *log_ctx) { char *ret = NULL; diff --git a/libavcodec/ffjni.h b/libavcodec/ffjni.h index 990c7b9c3f437..6027bac0ab12d 100644 --- a/libavcodec/ffjni.h +++ b/libavcodec/ffjni.h @@ -26,7 +26,10 @@ #include /* - * Attach a JNI environment to the current thread. + * Attach permanently a JNI environment to the current thread and retrieve it. + * + * If successfully attached, the JNI environment will automatically be detached + * at thread destruction. * * @param attached pointer to an integer that will be set to 1 if the * environment has been attached to the current thread or 0 if it is @@ -34,15 +37,7 @@ * @param log_ctx context used for logging, can be NULL * @return the JNI environment on success, NULL otherwise */ -JNIEnv *ff_jni_attach_env(int *attached, void *log_ctx); - -/* - * Detach the JNI environment from the current thread. - * - * @param log_ctx context used for logging, can be NULL - * @return 0 on success, < 0 otherwise - */ -int ff_jni_detach_env(void *log_ctx); +JNIEnv *ff_jni_get_env(void *log_ctx); /* * Convert a jstring to its utf characters equivalent. diff --git a/libavcodec/mediacodec.c b/libavcodec/mediacodec.c index 5b79798a87b49..cd8766f3b19ab 100644 --- a/libavcodec/mediacodec.c +++ b/libavcodec/mediacodec.c @@ -43,9 +43,8 @@ int av_mediacodec_default_init(AVCodecContext *avctx, AVMediaCodecContext *ctx, { int ret = 0; JNIEnv *env = NULL; - int attached = 0; - env = ff_jni_attach_env(&attached, avctx); + env = ff_jni_get_env(avctx); if (!env) { return AVERROR_EXTERNAL; } @@ -58,17 +57,12 @@ int av_mediacodec_default_init(AVCodecContext *avctx, AVMediaCodecContext *ctx, ret = AVERROR_EXTERNAL; } - if (attached) { - ff_jni_detach_env(avctx); - } - return ret; } void av_mediacodec_default_free(AVCodecContext *avctx) { JNIEnv *env = NULL; - int attached = 0; AVMediaCodecContext *ctx = avctx->hwaccel_context; @@ -76,7 +70,7 @@ void av_mediacodec_default_free(AVCodecContext *avctx) return; } - env = ff_jni_attach_env(&attached, avctx); + env = ff_jni_get_env(avctx); if (!env) { return; } @@ -86,10 +80,6 @@ void av_mediacodec_default_free(AVCodecContext *avctx) ctx->surface = NULL; } - if (attached) { - ff_jni_detach_env(avctx); - } - av_freep(&avctx->hwaccel_context); } diff --git a/libavcodec/mediacodec_surface.c b/libavcodec/mediacodec_surface.c index 903ebe4d8b237..aada1ecebe04a 100644 --- a/libavcodec/mediacodec_surface.c +++ b/libavcodec/mediacodec_surface.c @@ -27,40 +27,30 @@ void *ff_mediacodec_surface_ref(void *surface, void *log_ctx) { - int attached = 0; JNIEnv *env = NULL; void *reference = NULL; - env = ff_jni_attach_env(&attached, log_ctx); + env = ff_jni_get_env(log_ctx); if (!env) { return NULL; } reference = (*env)->NewGlobalRef(env, surface); - if (attached) { - ff_jni_detach_env(log_ctx); - } - return reference; } int ff_mediacodec_surface_unref(void *surface, void *log_ctx) { - int attached = 0; JNIEnv *env = NULL; - env = ff_jni_attach_env(&attached, log_ctx); + env = ff_jni_get_env(log_ctx); if (!env) { return AVERROR_EXTERNAL; } (*env)->DeleteGlobalRef(env, surface); - if (attached) { - ff_jni_detach_env(log_ctx); - } - return 0; } diff --git a/libavcodec/mediacodec_wrapper.c b/libavcodec/mediacodec_wrapper.c index cd933d6417b98..36f38bb97a295 100644 --- a/libavcodec/mediacodec_wrapper.c +++ b/libavcodec/mediacodec_wrapper.c @@ -283,36 +283,28 @@ struct FFAMediaCodec { int has_get_i_o_buffer; }; -#define JNI_ATTACH_ENV_OR_RETURN(env, attached, log_ctx, ret) do { \ - (env) = ff_jni_attach_env(attached, log_ctx); \ +#define JNI_GET_ENV_OR_RETURN(env, log_ctx, ret) do { \ + (env) = ff_jni_get_env(log_ctx); \ if (!(env)) { \ return ret; \ } \ } while (0) -#define JNI_ATTACH_ENV_OR_RETURN_VOID(env, attached, log_ctx) do { \ - (env) = ff_jni_attach_env(attached, log_ctx); \ +#define JNI_GET_ENV_OR_RETURN_VOID(env, log_ctx) do { \ + (env) = ff_jni_get_env(log_ctx); \ if (!(env)) { \ return; \ } \ } while (0) -#define JNI_DETACH_ENV(attached, log_ctx) do { \ - if (attached) \ - ff_jni_detach_env(log_ctx); \ -} while (0) - - - int ff_AMediaCodecProfile_getProfileFromAVCodecContext(AVCodecContext *avctx) { int ret = -1; - int attached = 0; JNIEnv *env = NULL; struct JNIAMediaCodecListFields jfields = { 0 }; - JNI_ATTACH_ENV_OR_RETURN(env, &attached, avctx, -1); + JNI_GET_ENV_OR_RETURN(env, avctx, -1); if (ff_jni_init_jfields(env, &jfields, jni_amediacodeclist_mapping, 0, avctx) < 0) { goto done; @@ -362,8 +354,6 @@ int ff_AMediaCodecProfile_getProfileFromAVCodecContext(AVCodecContext *avctx) done: ff_jni_reset_jfields(env, &jfields, jni_amediacodeclist_mapping, 0, avctx); - JNI_DETACH_ENV(attached, avctx); - return ret; } @@ -376,7 +366,6 @@ char *ff_AMediaCodecList_getCodecNameByType(const char *mime, int profile, int e char *name = NULL; char *supported_type = NULL; - int attached = 0; JNIEnv *env = NULL; struct JNIAMediaCodecListFields jfields = { 0 }; struct JNIAMediaFormatFields mediaformat_jfields = { 0 }; @@ -393,7 +382,7 @@ char *ff_AMediaCodecList_getCodecNameByType(const char *mime, int profile, int e jobject profile_level = NULL; jobjectArray profile_levels = NULL; - JNI_ATTACH_ENV_OR_RETURN(env, &attached, log_ctx, NULL); + JNI_GET_ENV_OR_RETURN(env, log_ctx, NULL); if ((ret = ff_jni_init_jfields(env, &jfields, jni_amediacodeclist_mapping, 0, log_ctx)) < 0) { goto done; @@ -588,8 +577,6 @@ char *ff_AMediaCodecList_getCodecNameByType(const char *mime, int profile, int e ff_jni_reset_jfields(env, &jfields, jni_amediacodeclist_mapping, 0, log_ctx); ff_jni_reset_jfields(env, &mediaformat_jfields, jni_amediaformat_mapping, 0, log_ctx); - JNI_DETACH_ENV(attached, log_ctx); - if (!found_codec) { av_freep(&name); } @@ -599,7 +586,6 @@ char *ff_AMediaCodecList_getCodecNameByType(const char *mime, int profile, int e FFAMediaFormat *ff_AMediaFormat_new(void) { - int attached = 0; JNIEnv *env = NULL; FFAMediaFormat *format = NULL; @@ -609,7 +595,7 @@ FFAMediaFormat *ff_AMediaFormat_new(void) } format->class = &amediaformat_class; - env = ff_jni_attach_env(&attached, format); + env = ff_jni_get_env(format); if (!env) { av_freep(&format); return NULL; @@ -629,14 +615,10 @@ FFAMediaFormat *ff_AMediaFormat_new(void) goto fail; } - JNI_DETACH_ENV(attached, format); - return format; fail: ff_jni_reset_jfields(env, &format->jfields, jni_amediaformat_mapping, 1, format); - JNI_DETACH_ENV(attached, format); - av_freep(&format); return NULL; @@ -644,7 +626,6 @@ FFAMediaFormat *ff_AMediaFormat_new(void) static FFAMediaFormat *ff_AMediaFormat_newFromObject(void *object) { - int attached = 0; JNIEnv *env = NULL; FFAMediaFormat *format = NULL; @@ -654,7 +635,7 @@ static FFAMediaFormat *ff_AMediaFormat_newFromObject(void *object) } format->class = &amediaformat_class; - env = ff_jni_attach_env(&attached, format); + env = ff_jni_get_env(format); if (!env) { av_freep(&format); return NULL; @@ -669,14 +650,10 @@ static FFAMediaFormat *ff_AMediaFormat_newFromObject(void *object) goto fail; } - JNI_DETACH_ENV(attached, format); - return format; fail: ff_jni_reset_jfields(env, &format->jfields, jni_amediaformat_mapping, 1, format); - JNI_DETACH_ENV(attached, format); - av_freep(&format); return NULL; @@ -686,22 +663,19 @@ int ff_AMediaFormat_delete(FFAMediaFormat* format) { int ret = 0; - int attached = 0; JNIEnv *env = NULL; if (!format) { return 0; } - JNI_ATTACH_ENV_OR_RETURN(env, &attached, format, AVERROR_EXTERNAL); + JNI_GET_ENV_OR_RETURN(env, format, AVERROR_EXTERNAL); (*env)->DeleteGlobalRef(env, format->object); format->object = NULL; ff_jni_reset_jfields(env, &format->jfields, jni_amediaformat_mapping, 1, format); - JNI_DETACH_ENV(attached, format); - av_freep(&format); return ret; @@ -711,13 +685,12 @@ char* ff_AMediaFormat_toString(FFAMediaFormat* format) { char *ret = NULL; - int attached = 0; JNIEnv *env = NULL; jstring description = NULL; av_assert0(format != NULL); - JNI_ATTACH_ENV_OR_RETURN(env, &attached, format, NULL); + JNI_GET_ENV_OR_RETURN(env, format, NULL); description = (*env)->CallObjectMethod(env, format->object, format->jfields.to_string_id); if (ff_jni_exception_check(env, 1, NULL) < 0) { @@ -726,13 +699,10 @@ char* ff_AMediaFormat_toString(FFAMediaFormat* format) ret = ff_jni_jstring_to_utf_chars(env, description, format); fail: - if (description) { (*env)->DeleteLocalRef(env, description); } - JNI_DETACH_ENV(attached, format); - return ret; } @@ -740,13 +710,12 @@ int ff_AMediaFormat_getInt32(FFAMediaFormat* format, const char *name, int32_t * { int ret = 1; - int attached = 0; JNIEnv *env = NULL; jstring key = NULL; av_assert0(format != NULL); - JNI_ATTACH_ENV_OR_RETURN(env, &attached, format, 0); + JNI_GET_ENV_OR_RETURN(env, format, 0); key = ff_jni_utf_chars_to_jstring(env, name, format); if (!key) { @@ -766,8 +735,6 @@ int ff_AMediaFormat_getInt32(FFAMediaFormat* format, const char *name, int32_t * (*env)->DeleteLocalRef(env, key); } - JNI_DETACH_ENV(attached, format); - return ret; } @@ -775,13 +742,12 @@ int ff_AMediaFormat_getInt64(FFAMediaFormat* format, const char *name, int64_t * { int ret = 1; - int attached = 0; JNIEnv *env = NULL; jstring key = NULL; av_assert0(format != NULL); - JNI_ATTACH_ENV_OR_RETURN(env, &attached, format, 0); + JNI_GET_ENV_OR_RETURN(env, format, 0); key = ff_jni_utf_chars_to_jstring(env, name, format); if (!key) { @@ -801,8 +767,6 @@ int ff_AMediaFormat_getInt64(FFAMediaFormat* format, const char *name, int64_t * (*env)->DeleteLocalRef(env, key); } - JNI_DETACH_ENV(attached, format); - return ret; } @@ -810,13 +774,12 @@ int ff_AMediaFormat_getFloat(FFAMediaFormat* format, const char *name, float *ou { int ret = 1; - int attached = 0; JNIEnv *env = NULL; jstring key = NULL; av_assert0(format != NULL); - JNI_ATTACH_ENV_OR_RETURN(env, &attached, format, 0); + JNI_GET_ENV_OR_RETURN(env, format, 0); key = ff_jni_utf_chars_to_jstring(env, name, format); if (!key) { @@ -836,8 +799,6 @@ int ff_AMediaFormat_getFloat(FFAMediaFormat* format, const char *name, float *ou (*env)->DeleteLocalRef(env, key); } - JNI_DETACH_ENV(attached, format); - return ret; } @@ -845,14 +806,13 @@ int ff_AMediaFormat_getBuffer(FFAMediaFormat* format, const char *name, void** d { int ret = 1; - int attached = 0; JNIEnv *env = NULL; jstring key = NULL; jobject result = NULL; av_assert0(format != NULL); - JNI_ATTACH_ENV_OR_RETURN(env, &attached, format, 0); + JNI_GET_ENV_OR_RETURN(env, format, 0); key = ff_jni_utf_chars_to_jstring(env, name, format); if (!key) { @@ -890,8 +850,6 @@ int ff_AMediaFormat_getBuffer(FFAMediaFormat* format, const char *name, void** d (*env)->DeleteLocalRef(env, result); } - JNI_DETACH_ENV(attached, format); - return ret; } @@ -899,14 +857,13 @@ int ff_AMediaFormat_getString(FFAMediaFormat* format, const char *name, const ch { int ret = 1; - int attached = 0; JNIEnv *env = NULL; jstring key = NULL; jstring result = NULL; av_assert0(format != NULL); - JNI_ATTACH_ENV_OR_RETURN(env, &attached, format, 0); + JNI_GET_ENV_OR_RETURN(env, format, 0); key = ff_jni_utf_chars_to_jstring(env, name, format); if (!key) { @@ -936,20 +893,17 @@ int ff_AMediaFormat_getString(FFAMediaFormat* format, const char *name, const ch (*env)->DeleteLocalRef(env, result); } - JNI_DETACH_ENV(attached, format); - return ret; } void ff_AMediaFormat_setInt32(FFAMediaFormat* format, const char* name, int32_t value) { - int attached = 0; JNIEnv *env = NULL; jstring key = NULL; av_assert0(format != NULL); - JNI_ATTACH_ENV_OR_RETURN_VOID(env, &attached, format); + JNI_GET_ENV_OR_RETURN_VOID(env, format); key = ff_jni_utf_chars_to_jstring(env, name, format); if (!key) { @@ -965,19 +919,16 @@ void ff_AMediaFormat_setInt32(FFAMediaFormat* format, const char* name, int32_t if (key) { (*env)->DeleteLocalRef(env, key); } - - JNI_DETACH_ENV(attached, format); } void ff_AMediaFormat_setInt64(FFAMediaFormat* format, const char* name, int64_t value) { - int attached = 0; JNIEnv *env = NULL; jstring key = NULL; av_assert0(format != NULL); - JNI_ATTACH_ENV_OR_RETURN_VOID(env, &attached, format); + JNI_GET_ENV_OR_RETURN_VOID(env, format); key = ff_jni_utf_chars_to_jstring(env, name, format); if (!key) { @@ -993,19 +944,16 @@ void ff_AMediaFormat_setInt64(FFAMediaFormat* format, const char* name, int64_t if (key) { (*env)->DeleteLocalRef(env, key); } - - JNI_DETACH_ENV(attached, NULL); } void ff_AMediaFormat_setFloat(FFAMediaFormat* format, const char* name, float value) { - int attached = 0; JNIEnv *env = NULL; jstring key = NULL; av_assert0(format != NULL); - JNI_ATTACH_ENV_OR_RETURN_VOID(env, &attached, format); + JNI_GET_ENV_OR_RETURN_VOID(env, format); key = ff_jni_utf_chars_to_jstring(env, name, format); if (!key) { @@ -1021,20 +969,17 @@ void ff_AMediaFormat_setFloat(FFAMediaFormat* format, const char* name, float va if (key) { (*env)->DeleteLocalRef(env, key); } - - JNI_DETACH_ENV(attached, NULL); } void ff_AMediaFormat_setString(FFAMediaFormat* format, const char* name, const char* value) { - int attached = 0; JNIEnv *env = NULL; jstring key = NULL; jstring string = NULL; av_assert0(format != NULL); - JNI_ATTACH_ENV_OR_RETURN_VOID(env, &attached, format); + JNI_GET_ENV_OR_RETURN_VOID(env, format); key = ff_jni_utf_chars_to_jstring(env, name, format); if (!key) { @@ -1059,13 +1004,10 @@ void ff_AMediaFormat_setString(FFAMediaFormat* format, const char* name, const c if (string) { (*env)->DeleteLocalRef(env, string); } - - JNI_DETACH_ENV(attached, format); } void ff_AMediaFormat_setBuffer(FFAMediaFormat* format, const char* name, void* data, size_t size) { - int attached = 0; JNIEnv *env = NULL; jstring key = NULL; jobject buffer = NULL; @@ -1073,7 +1015,7 @@ void ff_AMediaFormat_setBuffer(FFAMediaFormat* format, const char* name, void* d av_assert0(format != NULL); - JNI_ATTACH_ENV_OR_RETURN_VOID(env, &attached, format); + JNI_GET_ENV_OR_RETURN_VOID(env, format); key = ff_jni_utf_chars_to_jstring(env, name, format); if (!key) { @@ -1109,17 +1051,14 @@ void ff_AMediaFormat_setBuffer(FFAMediaFormat* format, const char* name, void* d if (buffer) { (*env)->DeleteLocalRef(env, buffer); } - - JNI_DETACH_ENV(attached, format); } static int codec_init_static_fields(FFAMediaCodec *codec) { int ret = 0; - int attached = 0; JNIEnv *env = NULL; - JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL); + JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL); codec->INFO_TRY_AGAIN_LATER = (*env)->GetStaticIntField(env, codec->jfields.mediacodec_class, codec->jfields.info_try_again_later_id); if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) { @@ -1164,14 +1103,12 @@ static int codec_init_static_fields(FFAMediaCodec *codec) } fail: - JNI_DETACH_ENV(attached, NULL); return ret; } FFAMediaCodec* ff_AMediaCodec_createCodecByName(const char *name) { - int attached = 0; JNIEnv *env = NULL; FFAMediaCodec *codec = NULL; jstring codec_name = NULL; @@ -1182,7 +1119,7 @@ FFAMediaCodec* ff_AMediaCodec_createCodecByName(const char *name) } codec->class = &amediacodec_class; - env = ff_jni_attach_env(&attached, codec); + env = ff_jni_get_env(codec); if (!env) { av_freep(&codec); return NULL; @@ -1215,8 +1152,6 @@ FFAMediaCodec* ff_AMediaCodec_createCodecByName(const char *name) codec->has_get_i_o_buffer = 1; } - JNI_DETACH_ENV(attached, codec); - return codec; fail: ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec); @@ -1225,8 +1160,6 @@ FFAMediaCodec* ff_AMediaCodec_createCodecByName(const char *name) (*env)->DeleteLocalRef(env, codec_name); } - JNI_DETACH_ENV(attached, codec); - av_freep(&codec); return NULL; @@ -1234,7 +1167,6 @@ FFAMediaCodec* ff_AMediaCodec_createCodecByName(const char *name) FFAMediaCodec* ff_AMediaCodec_createDecoderByType(const char *mime) { - int attached = 0; JNIEnv *env = NULL; FFAMediaCodec *codec = NULL; jstring mime_type = NULL; @@ -1245,7 +1177,7 @@ FFAMediaCodec* ff_AMediaCodec_createDecoderByType(const char *mime) } codec->class = &amediacodec_class; - env = ff_jni_attach_env(&attached, codec); + env = ff_jni_get_env(codec); if (!env) { av_freep(&codec); return NULL; @@ -1278,8 +1210,6 @@ FFAMediaCodec* ff_AMediaCodec_createDecoderByType(const char *mime) codec->has_get_i_o_buffer = 1; } - JNI_DETACH_ENV(attached, codec); - return codec; fail: ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec); @@ -1288,8 +1218,6 @@ FFAMediaCodec* ff_AMediaCodec_createDecoderByType(const char *mime) (*env)->DeleteLocalRef(env, mime_type); } - JNI_DETACH_ENV(attached, codec); - av_freep(&codec); return NULL; @@ -1297,7 +1225,6 @@ FFAMediaCodec* ff_AMediaCodec_createDecoderByType(const char *mime) FFAMediaCodec* ff_AMediaCodec_createEncoderByType(const char *mime) { - int attached = 0; JNIEnv *env = NULL; FFAMediaCodec *codec = NULL; jstring mime_type = NULL; @@ -1308,7 +1235,7 @@ FFAMediaCodec* ff_AMediaCodec_createEncoderByType(const char *mime) } codec->class = &amediacodec_class; - env = ff_jni_attach_env(&attached, codec); + env = ff_jni_get_env(codec); if (!env) { av_freep(&codec); return NULL; @@ -1341,8 +1268,6 @@ FFAMediaCodec* ff_AMediaCodec_createEncoderByType(const char *mime) codec->has_get_i_o_buffer = 1; } - JNI_DETACH_ENV(attached, NULL); - return codec; fail: ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec); @@ -1351,8 +1276,6 @@ FFAMediaCodec* ff_AMediaCodec_createEncoderByType(const char *mime) (*env)->DeleteLocalRef(env, mime_type); } - JNI_DETACH_ENV(attached, codec); - av_freep(&codec); return NULL; @@ -1362,14 +1285,13 @@ int ff_AMediaCodec_delete(FFAMediaCodec* codec) { int ret = 0; - int attached = 0; JNIEnv *env = NULL; if (!codec) { return 0; } - JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL); + JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL); (*env)->CallVoidMethod(env, codec->object, codec->jfields.release_id); if (ff_jni_exception_check(env, 1, codec) < 0) { @@ -1381,8 +1303,6 @@ int ff_AMediaCodec_delete(FFAMediaCodec* codec) ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec); - JNI_DETACH_ENV(attached, codec); - av_freep(&codec); return ret; @@ -1391,11 +1311,10 @@ int ff_AMediaCodec_delete(FFAMediaCodec* codec) char *ff_AMediaCodec_getName(FFAMediaCodec *codec) { char *ret = NULL; - int attached = 0; JNIEnv *env = NULL; jobject *name = NULL; - JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, NULL); + JNI_GET_ENV_OR_RETURN(env, codec, NULL); name = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_name_id); if (ff_jni_exception_check(env, 1, codec) < 0) { @@ -1405,18 +1324,15 @@ char *ff_AMediaCodec_getName(FFAMediaCodec *codec) ret = ff_jni_jstring_to_utf_chars(env, name, codec); fail: - JNI_DETACH_ENV(attached, NULL); - return ret; } int ff_AMediaCodec_configure(FFAMediaCodec* codec, const FFAMediaFormat* format, void* surface, void *crypto, uint32_t flags) { int ret = 0; - int attached = 0; JNIEnv *env = NULL; - JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL); + JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL); (*env)->CallVoidMethod(env, codec->object, codec->jfields.configure_id, format->object, surface, NULL, flags); if (ff_jni_exception_check(env, 1, codec) < 0) { @@ -1425,18 +1341,15 @@ int ff_AMediaCodec_configure(FFAMediaCodec* codec, const FFAMediaFormat* format, } fail: - JNI_DETACH_ENV(attached, NULL); - return ret; } int ff_AMediaCodec_start(FFAMediaCodec* codec) { int ret = 0; - int attached = 0; JNIEnv *env = NULL; - JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL); + JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL); (*env)->CallVoidMethod(env, codec->object, codec->jfields.start_id); if (ff_jni_exception_check(env, 1, codec) < 0) { @@ -1445,18 +1358,15 @@ int ff_AMediaCodec_start(FFAMediaCodec* codec) } fail: - JNI_DETACH_ENV(attached, codec); - return ret; } int ff_AMediaCodec_stop(FFAMediaCodec* codec) { int ret = 0; - int attached = 0; JNIEnv *env = NULL; - JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL); + JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL); (*env)->CallVoidMethod(env, codec->object, codec->jfields.stop_id); if (ff_jni_exception_check(env, 1, codec) < 0) { @@ -1465,18 +1375,15 @@ int ff_AMediaCodec_stop(FFAMediaCodec* codec) } fail: - JNI_DETACH_ENV(attached, codec); - return ret; } int ff_AMediaCodec_flush(FFAMediaCodec* codec) { int ret = 0; - int attached = 0; JNIEnv *env = NULL; - JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL); + JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL); (*env)->CallVoidMethod(env, codec->object, codec->jfields.flush_id); if (ff_jni_exception_check(env, 1, codec) < 0) { @@ -1485,18 +1392,15 @@ int ff_AMediaCodec_flush(FFAMediaCodec* codec) } fail: - JNI_DETACH_ENV(attached, codec); - return ret; } int ff_AMediaCodec_releaseOutputBuffer(FFAMediaCodec* codec, size_t idx, int render) { int ret = 0; - int attached = 0; JNIEnv *env = NULL; - JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL); + JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL); (*env)->CallVoidMethod(env, codec->object, codec->jfields.release_output_buffer_id, idx, render); if (ff_jni_exception_check(env, 1, codec) < 0) { @@ -1505,18 +1409,15 @@ int ff_AMediaCodec_releaseOutputBuffer(FFAMediaCodec* codec, size_t idx, int ren } fail: - JNI_DETACH_ENV(attached, codec); - return ret; } int ff_AMediaCodec_releaseOutputBufferAtTime(FFAMediaCodec *codec, size_t idx, int64_t timestampNs) { int ret = 0; - int attached = 0; JNIEnv *env = NULL; - JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL); + JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL); (*env)->CallVoidMethod(env, codec->object, codec->jfields.release_output_buffer_at_time_id, idx, timestampNs); if (ff_jni_exception_check(env, 1, codec) < 0) { @@ -1525,18 +1426,15 @@ int ff_AMediaCodec_releaseOutputBufferAtTime(FFAMediaCodec *codec, size_t idx, i } fail: - JNI_DETACH_ENV(attached, codec); - return ret; } ssize_t ff_AMediaCodec_dequeueInputBuffer(FFAMediaCodec* codec, int64_t timeoutUs) { int ret = 0; - int attached = 0; JNIEnv *env = NULL; - JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL); + JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL); ret = (*env)->CallIntMethod(env, codec->object, codec->jfields.dequeue_input_buffer_id, timeoutUs); if (ff_jni_exception_check(env, 1, codec) < 0) { @@ -1545,18 +1443,15 @@ ssize_t ff_AMediaCodec_dequeueInputBuffer(FFAMediaCodec* codec, int64_t timeoutU } fail: - JNI_DETACH_ENV(attached, codec); - return ret; } int ff_AMediaCodec_queueInputBuffer(FFAMediaCodec* codec, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags) { int ret = 0; - int attached = 0; JNIEnv *env = NULL; - JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL); + JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL); (*env)->CallVoidMethod(env, codec->object, codec->jfields.queue_input_buffer_id, idx, offset, size, time, flags); if ((ret = ff_jni_exception_check(env, 1, codec)) < 0) { @@ -1565,20 +1460,17 @@ int ff_AMediaCodec_queueInputBuffer(FFAMediaCodec* codec, size_t idx, off_t offs } fail: - JNI_DETACH_ENV(attached, codec); - return ret; } ssize_t ff_AMediaCodec_dequeueOutputBuffer(FFAMediaCodec* codec, FFAMediaCodecBufferInfo *info, int64_t timeoutUs) { int ret = 0; - int attached = 0; JNIEnv *env = NULL; jobject mediainfo = NULL; - JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, AVERROR_EXTERNAL); + JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL); mediainfo = (*env)->NewObject(env, codec->jfields.mediainfo_class, codec->jfields.init_id); if (ff_jni_exception_check(env, 1, codec) < 0) { @@ -1620,20 +1512,17 @@ ssize_t ff_AMediaCodec_dequeueOutputBuffer(FFAMediaCodec* codec, FFAMediaCodecBu (*env)->DeleteLocalRef(env, mediainfo); } - JNI_DETACH_ENV(attached, NULL); - return ret; } uint8_t* ff_AMediaCodec_getInputBuffer(FFAMediaCodec* codec, size_t idx, size_t *out_size) { uint8_t *ret = NULL; - int attached = 0; JNIEnv *env = NULL; jobject buffer = NULL; - JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, NULL); + JNI_GET_ENV_OR_RETURN(env, codec, NULL); if (codec->has_get_i_o_buffer) { buffer = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_input_buffer_id, idx); @@ -1666,20 +1555,17 @@ uint8_t* ff_AMediaCodec_getInputBuffer(FFAMediaCodec* codec, size_t idx, size_t (*env)->DeleteLocalRef(env, buffer); } - JNI_DETACH_ENV(attached, codec); - return ret; } uint8_t* ff_AMediaCodec_getOutputBuffer(FFAMediaCodec* codec, size_t idx, size_t *out_size) { uint8_t *ret = NULL; - int attached = 0; JNIEnv *env = NULL; jobject buffer = NULL; - JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, NULL); + JNI_GET_ENV_OR_RETURN(env, codec, NULL); if (codec->has_get_i_o_buffer) { buffer = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_output_buffer_id, idx); @@ -1712,20 +1598,17 @@ uint8_t* ff_AMediaCodec_getOutputBuffer(FFAMediaCodec* codec, size_t idx, size_t (*env)->DeleteLocalRef(env, buffer); } - JNI_DETACH_ENV(attached, codec); - return ret; } FFAMediaFormat* ff_AMediaCodec_getOutputFormat(FFAMediaCodec* codec) { FFAMediaFormat *ret = NULL; - int attached = 0; JNIEnv *env = NULL; jobject mediaformat = NULL; - JNI_ATTACH_ENV_OR_RETURN(env, &attached, codec, NULL); + JNI_GET_ENV_OR_RETURN(env, codec, NULL); mediaformat = (*env)->CallObjectMethod(env, codec->object, codec->jfields.get_output_format_id); if (ff_jni_exception_check(env, 1, codec) < 0) { @@ -1738,8 +1621,6 @@ FFAMediaFormat* ff_AMediaCodec_getOutputFormat(FFAMediaCodec* codec) (*env)->DeleteLocalRef(env, mediaformat); } - JNI_DETACH_ENV(attached, codec); - return ret; } @@ -1784,10 +1665,9 @@ int ff_AMediaCodec_cleanOutputBuffers(FFAMediaCodec *codec) if (!codec->has_get_i_o_buffer) { if (codec->output_buffers) { - int attached = 0; JNIEnv *env = NULL; - env = ff_jni_attach_env(&attached, codec); + env = ff_jni_get_env(codec); if (!env) { ret = AVERROR_EXTERNAL; goto fail; @@ -1795,8 +1675,6 @@ int ff_AMediaCodec_cleanOutputBuffers(FFAMediaCodec *codec) (*env)->DeleteGlobalRef(env, codec->output_buffers); codec->output_buffers = NULL; - - JNI_DETACH_ENV(attached, codec); } } From f8ce1e828299695997b832cb8d2d6b0d8f1f53ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20B=C5=93sch?= Date: Wed, 27 Jul 2016 17:24:48 +0200 Subject: [PATCH 36/71] lavc/h264_slice: adjust a few line breaks to reduce diff with Libav --- libavcodec/h264_slice.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index befea2aea14fa..f68dfc7ba8e02 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -374,6 +374,7 @@ int ff_h264_update_thread_context(AVCodecContext *dst, return err; } } + /* copy block_offset since frame_start may not be called */ memcpy(h->block_offset, h1->block_offset, sizeof(h->block_offset)); } @@ -1380,7 +1381,6 @@ static int h264_slice_header_parse(H264Context *h, H264SliceContext *sl, sl->pps_id); return AVERROR_INVALIDDATA; } - pps = (const PPS*)h->ps.pps_list[sl->pps_id]->data; if (!h->ps.sps_list[pps->sps_id]) { @@ -1388,7 +1388,6 @@ static int h264_slice_header_parse(H264Context *h, H264SliceContext *sl, "non-existing SPS %u referenced\n", pps->sps_id); return AVERROR_INVALIDDATA; } - sps = (const SPS*)h->ps.sps_list[pps->sps_id]->data; frame_num = get_bits(&sl->gb, sps->log2_max_frame_num); @@ -1413,7 +1412,6 @@ static int h264_slice_header_parse(H264Context *h, H264SliceContext *sl, return -1; } field_pic_flag = get_bits1(&sl->gb); - if (field_pic_flag) { bottom_field_flag = get_bits1(&sl->gb); picture_structure = PICT_TOP_FIELD + bottom_field_flag; @@ -1421,7 +1419,6 @@ static int h264_slice_header_parse(H264Context *h, H264SliceContext *sl, picture_structure = PICT_FRAME; } } - sl->picture_structure = picture_structure; sl->mb_field_decoding_flag = picture_structure != PICT_FRAME; From cd141e71bd3441ac9b7b720b934b7d4d85a75355 Mon Sep 17 00:00:00 2001 From: Xinzheng Zhang Date: Wed, 27 Jul 2016 12:21:24 +0800 Subject: [PATCH 37/71] avformat/flvdec: splitting add_keyframes_index() out from parse_keyframes_index() Signed-off-by: Michael Niedermayer --- libavformat/flvdec.c | 76 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 16 deletions(-) diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c index 2bf1e059e1cbe..633cad0f88a99 100644 --- a/libavformat/flvdec.c +++ b/libavformat/flvdec.c @@ -61,6 +61,11 @@ typedef struct FLVContext { int broken_sizes; int sum_flv_tag_size; + + int last_keyframe_stream_index; + int keyframe_count; + int64_t *keyframe_times; + int64_t *keyframe_filepositions; } FLVContext; static int probe(AVProbeData *p, int live) @@ -92,6 +97,35 @@ static int live_flv_probe(AVProbeData *p) return probe(p, 1); } +static void add_keyframes_index(AVFormatContext *s) +{ + FLVContext *flv = s->priv_data; + AVStream *stream = NULL; + unsigned int i = 0; + + if (flv->last_keyframe_stream_index < 0) { + av_log(s, AV_LOG_DEBUG, "keyframe stream hasn't been created\n"); + return; + } + + av_assert0(flv->last_keyframe_stream_index <= s->nb_streams); + stream = s->streams[flv->last_keyframe_stream_index]; + + if (stream->nb_index_entries == 0) { + for (i = 0; i < flv->keyframe_count; i++) { + av_add_index_entry(stream, flv->keyframe_filepositions[i], + flv->keyframe_times[i] * 1000, 0, 0, AVINDEX_KEYFRAME); + } + } else + av_log(s, AV_LOG_WARNING, "Skipping duplicate index\n"); + + if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { + av_freep(&flv->keyframe_times); + av_freep(&flv->keyframe_filepositions); + flv->keyframe_count = 0; + } +} + static AVStream *create_stream(AVFormatContext *s, int codec_type) { AVStream *st = avformat_new_stream(s, NULL); @@ -305,8 +339,7 @@ static int amf_get_string(AVIOContext *ioc, char *buffer, int buffsize) return length; } -static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, - AVStream *vstream, int64_t max_pos) +static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, int64_t max_pos) { FLVContext *flv = s->priv_data; unsigned int timeslen = 0, fileposlen = 0, i; @@ -316,10 +349,12 @@ static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, int ret = AVERROR(ENOSYS); int64_t initial_pos = avio_tell(ioc); - if (vstream->nb_index_entries>0) { - av_log(s, AV_LOG_WARNING, "Skipping duplicate index\n"); + if (flv->keyframe_count > 0) { + av_log(s, AV_LOG_DEBUG, "keyframes have been paresed\n"); return 0; } + av_assert0(!flv->keyframe_times); + av_assert0(!flv->keyframe_filepositions); if (s->flags & AVFMT_FLAG_IGNIDX) return 0; @@ -368,15 +403,17 @@ static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, } if (timeslen == fileposlen && fileposlen>1 && max_pos <= filepositions[0]) { - for (i = 0; i < fileposlen; i++) { - av_add_index_entry(vstream, filepositions[i], times[i] * 1000, - 0, 0, AVINDEX_KEYFRAME); - if (i < 2) { - flv->validate_index[i].pos = filepositions[i]; - flv->validate_index[i].dts = times[i] * 1000; - flv->validate_count = i + 1; - } + for (i = 0; i < FFMIN(2,fileposlen); i++) { + flv->validate_index[i].pos = filepositions[i]; + flv->validate_index[i].dts = times[i] * 1000; + flv->validate_count = i + 1; } + flv->keyframe_times = times; + flv->keyframe_filepositions = filepositions; + flv->keyframe_count = timeslen; + times = NULL; + filepositions = NULL; + add_keyframes_index(s); } else { invalid: av_log(s, AV_LOG_WARNING, "Invalid keyframes object, skipping.\n"); @@ -421,10 +458,9 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, if ((vstream || astream) && key && ioc->seekable && !strcmp(KEYFRAMES_TAG, key) && depth == 1) - if (parse_keyframes_index(s, ioc, vstream ? vstream : astream, + if (parse_keyframes_index(s, ioc, max_pos) < 0) av_log(s, AV_LOG_ERROR, "Keyframe index parsing failed\n"); - while (avio_tell(ioc) < max_pos - 2 && amf_get_string(ioc, str_val, sizeof(str_val)) > 0) if (amf_parse_object(s, astream, vstream, str_val, max_pos, @@ -574,6 +610,7 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, static int flv_read_metabody(AVFormatContext *s, int64_t next_pos) { + FLVContext *flv = s->priv_data; AMFDataType type; AVStream *stream, *astream, *vstream; AVStream av_unused *dstream; @@ -612,10 +649,14 @@ static int flv_read_metabody(AVFormatContext *s, int64_t next_pos) // the lookup every time it is called. for (i = 0; i < s->nb_streams; i++) { stream = s->streams[i]; - if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) + if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { vstream = stream; - else if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) + flv->last_keyframe_stream_index = i; + } else if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { astream = stream; + if (flv->last_keyframe_stream_index == -1) + flv->last_keyframe_stream_index = i; + } else if (stream->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) dstream = stream; } @@ -643,6 +684,7 @@ static int flv_read_header(AVFormatContext *s) s->start_time = 0; flv->sum_flv_tag_size = 0; + flv->last_keyframe_stream_index = -1; return 0; } @@ -653,6 +695,8 @@ static int flv_read_close(AVFormatContext *s) FLVContext *flv = s->priv_data; for (i=0; inew_extradata[i]); + av_freep(&flv->keyframe_times); + av_freep(&flv->keyframe_filepositions); return 0; } From ad14aab3b4f88cdb6c2a3f8877c578e5a8042f1d Mon Sep 17 00:00:00 2001 From: Xinzheng Zhang Date: Wed, 27 Jul 2016 12:21:25 +0800 Subject: [PATCH 38/71] avformat/flvdec: parse keyframe before a\v stream was created add_keyframes_index() when stream created or keyframe parsed Signed-off-by: Michael Niedermayer --- libavformat/flvdec.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c index 633cad0f88a99..0afeba58baf1f 100644 --- a/libavformat/flvdec.c +++ b/libavformat/flvdec.c @@ -128,6 +128,7 @@ static void add_keyframes_index(AVFormatContext *s) static AVStream *create_stream(AVFormatContext *s, int codec_type) { + FLVContext *flv = s->priv_data; AVStream *st = avformat_new_stream(s, NULL); if (!st) return NULL; @@ -138,6 +139,8 @@ static AVStream *create_stream(AVFormatContext *s, int codec_type) s->ctx_flags &= ~AVFMTCTX_NOHEADER; avpriv_set_pts_info(st, 32, 1, 1000); /* 32 bit pts in ms */ + flv->last_keyframe_stream_index = s->nb_streams - 1; + add_keyframes_index(s); return st; } @@ -413,7 +416,6 @@ static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, int64_t m flv->keyframe_count = timeslen; times = NULL; filepositions = NULL; - add_keyframes_index(s); } else { invalid: av_log(s, AV_LOG_WARNING, "Invalid keyframes object, skipping.\n"); @@ -455,12 +457,14 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, } break; case AMF_DATA_TYPE_OBJECT: - if ((vstream || astream) && key && + if (key && ioc->seekable && !strcmp(KEYFRAMES_TAG, key) && depth == 1) if (parse_keyframes_index(s, ioc, max_pos) < 0) av_log(s, AV_LOG_ERROR, "Keyframe index parsing failed\n"); + else + add_keyframes_index(s); while (avio_tell(ioc) < max_pos - 2 && amf_get_string(ioc, str_val, sizeof(str_val)) > 0) if (amf_parse_object(s, astream, vstream, str_val, max_pos, From 8385e1718ee1fed107ec911d0b17fed3f7d74c71 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer Date: Wed, 27 Jul 2016 18:22:41 +0200 Subject: [PATCH 39/71] avcodec/h264_slice: Make setup_finished check cover more cases --- libavcodec/h264_slice.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index 1fe89c3c49f99..e1de971059a41 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -1560,12 +1560,15 @@ int ff_h264_decode_slice_header(H264Context *h, H264SliceContext *sl, if (ret < 0) return ret; + if (sl->first_mb_addr == 0 || !h->current_slice) { + if (h->setup_finished) { + av_log(h->avctx, AV_LOG_ERROR, "Too many fields\n"); + return AVERROR_INVALIDDATA; + } + } + if (sl->first_mb_addr == 0) { // FIXME better field boundary detection if (h->current_slice) { - if (h->setup_finished) { - av_log(h->avctx, AV_LOG_ERROR, "Too many fields\n"); - return AVERROR_INVALIDDATA; - } if (h->max_contexts > 1) { if (!h->single_decode_warning) { av_log(h->avctx, AV_LOG_WARNING, "Cannot decode multiple access units as slice threads\n"); From bfe9155aee1c8d0226b839204f21e231dcd01edd Mon Sep 17 00:00:00 2001 From: Burt P Date: Thu, 14 Jul 2016 12:54:34 -0500 Subject: [PATCH 40/71] fate: Add HDCD filter tests for false positive and error detection Signed-off-by: Burt P Signed-off-by: Michael Niedermayer --- tests/fate-run.sh | 3 ++- tests/fate/filter-audio.mak | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/tests/fate-run.sh b/tests/fate-run.sh index c89869503379d..5841b0c413b6b 100755 --- a/tests/fate-run.sh +++ b/tests/fate-run.sh @@ -328,13 +328,14 @@ if [ $err -gt 128 ]; then test "${sig}" = "${sig%[!A-Za-z]*}" || unset sig fi -if test -e "$ref" || test $cmp = "oneline" ; then +if test -e "$ref" || test $cmp = "oneline" || test $cmp = "grep" ; then case $cmp in diff) diff -u -b "$ref" "$outfile" >$cmpfile ;; rawdiff)diff -u "$ref" "$outfile" >$cmpfile ;; oneoff) oneoff "$ref" "$outfile" >$cmpfile ;; stddev) stddev "$ref" "$outfile" >$cmpfile ;; oneline)oneline "$ref" "$outfile" >$cmpfile ;; + grep) grep "$ref" "$errfile" >$cmpfile ;; null) cat "$outfile" >$cmpfile ;; esac cmperr=$? diff --git a/tests/fate/filter-audio.mak b/tests/fate/filter-audio.mak index 32787a764c5e3..f71fb52b51d31 100644 --- a/tests/fate/filter-audio.mak +++ b/tests/fate/filter-audio.mak @@ -219,6 +219,18 @@ fate-filter-hdcd: CMD = md5 -i $(SRC) -af hdcd -f s24le fate-filter-hdcd: CMP = oneline fate-filter-hdcd: REF = 5db465a58d2fd0d06ca944b883b33476 +FATE_AFILTER_SAMPLES-$(call FILTERDEMDECENCMUX, HDCD, FLAC, FLAC, PCM_S24LE, PCM_S24LE) += fate-filter-hdcd-false-positive +fate-filter-hdcd-false-positive: SRC = $(TARGET_SAMPLES)/filter/hdcd-false-positive.flac +fate-filter-hdcd-false-positive: CMD = md5 -i $(SRC) -af hdcd -f s24le +fate-filter-hdcd-false-positive: CMP = grep +fate-filter-hdcd-false-positive: REF = HDCD detected: no + +FATE_AFILTER_SAMPLES-$(call FILTERDEMDECENCMUX, HDCD, FLAC, FLAC, PCM_S24LE, PCM_S24LE) += fate-filter-hdcd-detect-errors +fate-filter-hdcd-detect-errors: SRC = $(TARGET_SAMPLES)/filter/hdcd-encoding-errors.flac +fate-filter-hdcd-detect-errors: CMD = md5 -i $(SRC) -af hdcd -f s24le +fate-filter-hdcd-detect-errors: CMP = grep +fate-filter-hdcd-detect-errors: REF = detectable errors: [1-9] + FATE_AFILTER-yes += fate-filter-formats fate-filter-formats: libavfilter/tests/formats$(EXESUF) fate-filter-formats: CMD = run libavfilter/tests/formats From 91854b8ef644207925cdc5d0dda1b130335d89f1 Mon Sep 17 00:00:00 2001 From: Burt P Date: Sat, 23 Jul 2016 21:26:48 -0500 Subject: [PATCH 41/71] af_hdcd: Improve HDCD detection HDCD is now only considered detected if a valid packet is active in both channels simultaneously. Signed-off-by: Burt P Signed-off-by: Michael Niedermayer --- libavfilter/af_hdcd.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libavfilter/af_hdcd.c b/libavfilter/af_hdcd.c index 6f0db71b850be..f68a1050fc935 100644 --- a/libavfilter/af_hdcd.c +++ b/libavfilter/af_hdcd.c @@ -1097,6 +1097,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) const int16_t *in_data; int32_t *out_data; int n, c; + int detect; out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { @@ -1112,19 +1113,22 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) out_data[n] = in_data[n]; } + detect = 0; s->det_errors = 0; for (c = 0; c < inlink->channels; c++) { hdcd_state_t *state = &s->state[c]; hdcd_process(state, out_data + c, in->nb_samples, out->channels); - + if (state->sustain) detect++; s->uses_peak_extend |= !!state->count_peak_extend; s->uses_transient_filter |= !!state->count_transient_filter; s->max_gain_adjustment = FFMIN(s->max_gain_adjustment, GAINTOFLOAT(state->max_gain)); - s->hdcd_detected |= state->code_counterB || state->code_counterA; s->det_errors += state->code_counterA_almost + state->code_counterB_checkfails + state->code_counterC_unmatched; } + /* HDCD is detected if a valid packet is active in all (both) + * channels at the same time. */ + if (detect == inlink->channels) s->hdcd_detected = 1; av_frame_free(&in); return ff_filter_frame(outlink, out); From c7ba34b6ea377d21e890e0f8ce30fae70d2e224f Mon Sep 17 00:00:00 2001 From: Burt P Date: Sat, 23 Jul 2016 21:26:49 -0500 Subject: [PATCH 42/71] af_hdcd: more comments in state struct Add some comments describing the fields in hdcd_state_t. Signed-off-by: Burt P Signed-off-by: Michael Niedermayer --- libavfilter/af_hdcd.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/libavfilter/af_hdcd.c b/libavfilter/af_hdcd.c index f68a1050fc935..72560db073baf 100644 --- a/libavfilter/af_hdcd.c +++ b/libavfilter/af_hdcd.c @@ -818,20 +818,28 @@ static const int32_t gaintab[] = { typedef struct { uint64_t window; - unsigned char readahead, arg, control; - int running_gain; - unsigned sustain, sustain_reset; - int code_counterA; - int code_counterA_almost; /* looks like an A code, but a bit expected to be 0 is 1 */ - int code_counterB; + unsigned char readahead; + + /* arg is set when a packet prefix is found. + * control is the active control code, where + * bit 0-3: target_gain, 4-bit (3.1) fixed-point value + * bit 4 : peak_extend + * bit 5 : transient_filter + * bit 6,7: always zero */ + unsigned char arg, control; + unsigned sustain, sustain_reset; /* code detect timer */ + + int running_gain; /* 11-bit (3.8) fixed point, extended from target_gain */ + + /* counters */ + int code_counterA; /* 8-bit format packet */ + int code_counterA_almost; /* looks like an A code, but a bit expected to be 0 is 1 */ + int code_counterB; /* 16-bit format packet, 8-bit code, 8-bit XOR of code */ int code_counterB_checkfails; /* looks like a B code, but doesn't pass the XOR check */ - int code_counterC; - int code_counterC_unmatched; /* told to look for a code, but didn't find one */ - - /* For user information/stats, pulled up into HDCDContext - * by filter_frame() */ - int count_peak_extend; - int count_transient_filter; + int code_counterC; /* packet prefix was found, expect a code */ + int code_counterC_unmatched; /* told to look for a code, but didn't find one */ + int count_peak_extend; /* valid packets where peak_extend was enabled */ + int count_transient_filter; /* valid packets where filter was detected */ /* target_gain is a 4-bit (3.1) fixed-point value, always * negative, but stored positive. * The 16 possible values range from -7.5 to 0.0 dB in From c26305f6aec005db39e04e628f6294635ddebaad Mon Sep 17 00:00:00 2001 From: Burt P Date: Sun, 24 Jul 2016 11:15:22 -0500 Subject: [PATCH 43/71] af_hdcd: Add counter for cdt expirations Adds a counter for when the "code detect timer" expired without finding a valid packet. Signed-off-by: Burt P Signed-off-by: Michael Niedermayer --- libavfilter/af_hdcd.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/libavfilter/af_hdcd.c b/libavfilter/af_hdcd.c index 72560db073baf..f265ed936bf95 100644 --- a/libavfilter/af_hdcd.c +++ b/libavfilter/af_hdcd.c @@ -846,6 +846,7 @@ typedef struct { * steps of 0.5, but no value below -6.0 dB should appear. */ int gain_counts[16]; /* for cursiosity, mostly */ int max_gain; + int count_sustain_expired; /* occurences of code detect timer expiring without detecting a code */ AVFilterContext *fctx; /* filter context for logging errors */ } hdcd_state_t; @@ -895,6 +896,8 @@ static void hdcd_reset(hdcd_state_t *state, unsigned rate) state->count_transient_filter = 0; for(i = 0; i < 16; i++) state->gain_counts[i] = 0; state->max_gain = 0; + + state->count_sustain_expired = 0; } /* update the user info/counters */ @@ -978,8 +981,11 @@ static int hdcd_integrate(hdcd_state_t *state, int *flag, const int32_t *samples static int hdcd_scan(hdcd_state_t *state, const int32_t *samples, int max, int stride) { + int cdt_active = 0; + /* code detect timer */ int result; if (state->sustain > 0) { + cdt_active = 1; if (state->sustain <= max) { state->control = 0; max = state->sustain; @@ -992,11 +998,15 @@ static int hdcd_scan(hdcd_state_t *state, const int32_t *samples, int max, int s int consumed = hdcd_integrate(state, &flag, samples, max - result, stride); result += consumed; if (flag > 0) { + /* reset timer if code detected in channel */ state->sustain = state->sustain_reset; break; } samples += consumed * stride; } + /* code detect timer expired */ + if (cdt_active && state->sustain == 0) + state->count_sustain_expired++; return result; } @@ -1198,12 +1208,13 @@ static av_cold void uninit(AVFilterContext *ctx) hdcd_state_t *state = &s->state[i]; av_log(ctx, AV_LOG_VERBOSE, "Channel %d: counter A: %d, B: %d, C: %d\n", i, state->code_counterA, state->code_counterB, state->code_counterC); - av_log(ctx, AV_LOG_VERBOSE, "Channel %d: pe: %d, tf: %d, almost_A: %d, checkfail_B: %d, unmatched_C: %d\n", i, + av_log(ctx, AV_LOG_VERBOSE, "Channel %d: pe: %d, tf: %d, almost_A: %d, checkfail_B: %d, unmatched_C: %d, cdt_expired: %d\n", i, state->count_peak_extend, state->count_transient_filter, state->code_counterA_almost, state->code_counterB_checkfails, - state->code_counterC_unmatched); + state->code_counterC_unmatched, + state->count_sustain_expired); for (j = 0; j <= state->max_gain; j++) { av_log(ctx, AV_LOG_VERBOSE, "Channel %d: tg %0.1f: %d\n", i, GAINTOFLOAT(j), state->gain_counts[j]); } From 60873bf992eab1d3bad8dd0fd11336363d44854d Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Tue, 26 Jul 2016 13:23:43 +0300 Subject: [PATCH 44/71] avformat/utils: Fix find_stream_info not considering the extradata it found Commit 9200514ad8717c6 ("lavf: replace AVStream.codec with AVStream.codecpar") merged in commit 6f69f7a8bf6a0d01 changed avformat_find_stream_info() to put the extradata it got from st->parser->parser->split() to st->internal->avctx instead of st->codec (extradata in st->internal->avctx will be later copied to st->codecpar). However, in the same function, the "is stream ready?" check was changed to check for extradata in st->codecpar instead of st->codec, even though st->codecpar is not yet updated at that point. Extradata retrieved from split() is therefore not considered anymore, and avformat_find_stream_info() will therefore needlessly continue probing in some cases. Fix that by checking for the extradata at st->internal->avctx where it is actually put. --- libavformat/utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavformat/utils.c b/libavformat/utils.c index e5a99ff4ad0c1..5a902ea8b0b14 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -3432,7 +3432,7 @@ FF_ENABLE_DEPRECATION_WARNINGS break; } if (st->parser && st->parser->parser->split && - !st->codecpar->extradata) + !st->internal->avctx->extradata) break; if (st->first_dts == AV_NOPTS_VALUE && !(ic->iformat->flags & AVFMT_NOTIMESTAMPS) && From 9cb30f7a880578e995becbd8bf9ffb69788e09a2 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Tue, 26 Jul 2016 15:18:40 +0300 Subject: [PATCH 45/71] avformat/hls: Fix regression with ranged media segments Commit 81306fd4bdf ("hls: eliminate ffurl_* usage", merged in d0fc5de3a6) changed the hls demuxer to use AVIOContext instead of URLContext for its HTTP requests. HLS demuxer uses the "offset" option of the http demuxer, requesting the initial file offset for the I/O (http URLProtocol uses the "Range:" HTTP header to try to accommodate that). However, the code in libavformat/aviobuf.c seems to be doing its own accounting for the current file offset (AVIOContext.pos), with the assumption that the initial offset is always zero. HLS demuxer does an explicit seek after open_url to account for cases where the "offset" was not effective (due to the URL being a local file or the HTTP server not obeying it), which should be a no-op in case the file offset is already at that position. However, since aviobuf.c code thinks the starting offset is 0, this doesn't work properly. This breaks retrieval of ranged media segments. To fix the regression, just drop the seek call from the HLS demuxer when the HTTP(S) protocol is used. --- libavformat/hls.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index b962d67abce58..66f4550411c30 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -590,7 +590,7 @@ static void update_options(char **dest, const char *name, void *src) } static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, - AVDictionary *opts, AVDictionary *opts2) + AVDictionary *opts, AVDictionary *opts2, int *is_http) { HLSContext *c = s->priv_data; AVDictionary *tmp = NULL; @@ -631,6 +631,9 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, av_dict_free(&tmp); + if (is_http) + *is_http = av_strstart(proto_name, "http", NULL); + return ret; } @@ -1072,6 +1075,7 @@ static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg) { AVDictionary *opts = NULL; int ret; + int is_http = 0; // broker prior HTTP options that should be consistent across requests av_dict_set(&opts, "user-agent", c->user_agent, 0); @@ -1091,13 +1095,13 @@ static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg) seg->url, seg->url_offset, pls->index); if (seg->key_type == KEY_NONE) { - ret = open_url(pls->parent, &pls->input, seg->url, c->avio_opts, opts); + ret = open_url(pls->parent, &pls->input, seg->url, c->avio_opts, opts, &is_http); } else if (seg->key_type == KEY_AES_128) { AVDictionary *opts2 = NULL; char iv[33], key[33], url[MAX_URL_SIZE]; if (strcmp(seg->key, pls->key_url)) { AVIOContext *pb; - if (open_url(pls->parent, &pb, seg->key, c->avio_opts, opts) == 0) { + if (open_url(pls->parent, &pb, seg->key, c->avio_opts, opts, NULL) == 0) { ret = avio_read(pb, pls->key, sizeof(pls->key)); if (ret != sizeof(pls->key)) { av_log(NULL, AV_LOG_ERROR, "Unable to read key file %s\n", @@ -1122,7 +1126,7 @@ static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg) av_dict_set(&opts2, "key", key, 0); av_dict_set(&opts2, "iv", iv, 0); - ret = open_url(pls->parent, &pls->input, url, opts2, opts); + ret = open_url(pls->parent, &pls->input, url, opts2, opts, &is_http); av_dict_free(&opts2); @@ -1140,8 +1144,15 @@ static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg) /* Seek to the requested position. If this was a HTTP request, the offset * should already be where want it to, but this allows e.g. local testing - * without a HTTP server. */ - if (ret == 0 && seg->key_type == KEY_NONE && seg->url_offset) { + * without a HTTP server. + * + * This is not done for HTTP at all as avio_seek() does internal bookkeeping + * of file offset which is out-of-sync with the actual offset when "offset" + * AVOption is used with http protocol, causing the seek to not be a no-op + * as would be expected. Wrong offset received from the server will not be + * noticed without the call, though. + */ + if (ret == 0 && !is_http && seg->key_type == KEY_NONE && seg->url_offset) { int64_t seekret = avio_seek(pls->input, seg->url_offset, SEEK_SET); if (seekret < 0) { av_log(pls->parent, AV_LOG_ERROR, "Unable to seek to offset %"PRId64" of HLS segment '%s'\n", seg->url_offset, seg->url); From 4d85069e5dff37e4a9904767242b47e14cf62a9c Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Wed, 27 Jul 2016 22:52:44 +0300 Subject: [PATCH 46/71] avformat/hls: Sync starting segment across variants on live streams This will avoid a large time difference between variants in the most common case. --- libavformat/hls.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index 66f4550411c30..88402c2284099 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -1520,6 +1520,7 @@ static int hls_read_header(AVFormatContext *s) void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb; HLSContext *c = s->priv_data; int ret = 0, i, j, stream_offset = 0; + int highest_cur_seq_no = 0; c->ctx = s; c->interrupt_callback = &s->interrupt_callback; @@ -1594,6 +1595,17 @@ static int hls_read_header(AVFormatContext *s) add_renditions_to_variant(c, var, AVMEDIA_TYPE_SUBTITLE, var->subtitles_group); } + /* Select the starting segments */ + for (i = 0; i < c->n_playlists; i++) { + struct playlist *pls = c->playlists[i]; + + if (pls->n_segments == 0) + continue; + + pls->cur_seq_no = select_cur_seq_no(c, pls); + highest_cur_seq_no = FFMAX(highest_cur_seq_no, pls->cur_seq_no); + } + /* Open the demuxer for each playlist */ for (i = 0; i < c->n_playlists; i++) { struct playlist *pls = c->playlists[i]; @@ -1610,7 +1622,18 @@ static int hls_read_header(AVFormatContext *s) pls->index = i; pls->needed = 1; pls->parent = s; - pls->cur_seq_no = select_cur_seq_no(c, pls); + + /* + * If this is a live stream and this playlist looks like it is one segment + * behind, try to sync it up so that every substream starts at the same + * time position (so e.g. avformat_find_stream_info() will see packets from + * all active streams within the first few seconds). This is not very generic, + * though, as the sequence numbers are technically independent. + */ + if (!pls->finished && pls->cur_seq_no == highest_cur_seq_no - 1 && + highest_cur_seq_no < pls->start_seq_no + pls->n_segments) { + pls->cur_seq_no = highest_cur_seq_no; + } pls->read_buffer = av_malloc(INITIAL_BUFFER_SIZE); if (!pls->read_buffer){ From 9884f17e343b37aef442fafa05bd0113cdf47087 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Wed, 27 Jul 2016 23:29:16 +0300 Subject: [PATCH 47/71] avformat/hls: Use an array instead of stream offset for stream mapping This will be useful when the amount of streams per subdemuxer is not known at hls_read_header time in a following commit. --- libavformat/hls.c | 59 ++++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index 88402c2284099..59f5e38f9f0c4 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -98,7 +98,11 @@ struct playlist { int index; AVFormatContext *ctx; AVPacket pkt; - int stream_offset; + + /* main demuxer streams associated with this playlist + * indexed by the subdemuxer stream indexes */ + AVStream **main_streams; + int n_main_streams; int finished; enum PlaylistType type; @@ -239,6 +243,7 @@ static void free_playlist_list(HLSContext *c) struct playlist *pls = c->playlists[i]; free_segment_list(pls); free_init_section_list(pls); + av_freep(&pls->main_streams); av_freep(&pls->renditions); av_freep(&pls->id3_buf); av_dict_free(&pls->id3_initial); @@ -1248,13 +1253,13 @@ static int read_data(void *opaque, uint8_t *buf, int buf_size) /* Check that the playlist is still needed before opening a new * segment. */ - if (v->ctx && v->ctx->nb_streams && - v->parent->nb_streams >= v->stream_offset + v->ctx->nb_streams) { + if (v->ctx && v->ctx->nb_streams) { v->needed = 0; - for (i = v->stream_offset; i < v->stream_offset + v->ctx->nb_streams; - i++) { - if (v->parent->streams[i]->discard < AVDISCARD_ALL) + for (i = 0; i < v->n_main_streams; i++) { + if (v->main_streams[i]->discard < AVDISCARD_ALL) { v->needed = 1; + break; + } } } if (!v->needed) { @@ -1392,8 +1397,8 @@ static void add_metadata_from_renditions(AVFormatContext *s, struct playlist *pl int rend_idx = 0; int i; - for (i = 0; i < pls->ctx->nb_streams; i++) { - AVStream *st = s->streams[pls->stream_offset + i]; + for (i = 0; i < pls->n_main_streams; i++) { + AVStream *st = pls->main_streams[i]; if (st->codecpar->codec_type != type) continue; @@ -1519,7 +1524,7 @@ static int hls_read_header(AVFormatContext *s) { void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb; HLSContext *c = s->priv_data; - int ret = 0, i, j, stream_offset = 0; + int ret = 0, i, j; int highest_cur_seq_no = 0; c->ctx = s; @@ -1659,7 +1664,6 @@ static int hls_read_header(AVFormatContext *s) } pls->ctx->pb = &pls->pb; pls->ctx->io_open = nested_io_open; - pls->stream_offset = stream_offset; if ((ret = ff_copy_whiteblacklists(pls->ctx, s)) < 0) goto fail; @@ -1699,13 +1703,13 @@ static int hls_read_header(AVFormatContext *s) avpriv_set_pts_info(st, 33, 1, MPEG_TIME_BASE); else avpriv_set_pts_info(st, ist->pts_wrap_bits, ist->time_base.num, ist->time_base.den); + + dynarray_add(&pls->main_streams, &pls->n_main_streams, st); } add_metadata_from_renditions(s, pls, AVMEDIA_TYPE_AUDIO); add_metadata_from_renditions(s, pls, AVMEDIA_TYPE_VIDEO); add_metadata_from_renditions(s, pls, AVMEDIA_TYPE_SUBTITLE); - - stream_offset += pls->ctx->nb_streams; } /* Create a program for each variant */ @@ -1723,10 +1727,10 @@ static int hls_read_header(AVFormatContext *s) int is_shared = playlist_in_multiple_variants(c, pls); int k; - for (k = 0; k < pls->ctx->nb_streams; k++) { - struct AVStream *st = s->streams[pls->stream_offset + k]; + for (k = 0; k < pls->n_main_streams; k++) { + struct AVStream *st = pls->main_streams[k]; - av_program_add_stream_index(s, i, pls->stream_offset + k); + av_program_add_stream_index(s, i, st->index); /* Set variant_bitrate for streams unique to this variant */ if (!is_shared && v->bandwidth) @@ -1905,8 +1909,17 @@ static int hls_read_packet(AVFormatContext *s, AVPacket *pkt) /* If we got a packet, return it */ if (minplaylist >= 0) { struct playlist *pls = c->playlists[minplaylist]; + + if (pls->pkt.stream_index >= pls->n_main_streams) { + av_log(s, AV_LOG_ERROR, "stream index inconsistency: index %d, %d main streams, %d subdemuxer streams\n", + pls->pkt.stream_index, pls->n_main_streams, pls->ctx->nb_streams); + av_packet_unref(&pls->pkt); + reset_packet(&pls->pkt); + return AVERROR_BUG; + } + *pkt = pls->pkt; - pkt->stream_index += pls->stream_offset; + pkt->stream_index = pls->main_streams[pls->pkt.stream_index]->index; reset_packet(&c->playlists[minplaylist]->pkt); if (pkt->dts != AV_NOPTS_VALUE) @@ -1938,6 +1951,8 @@ static int hls_read_seek(AVFormatContext *s, int stream_index, HLSContext *c = s->priv_data; struct playlist *seek_pls = NULL; int i, seq_no; + int j; + int stream_subdemuxer_index; int64_t first_timestamp, seek_timestamp, duration; if ((flags & AVSEEK_FLAG_BYTE) || @@ -1961,10 +1976,12 @@ static int hls_read_seek(AVFormatContext *s, int stream_index, /* find the playlist with the specified stream */ for (i = 0; i < c->n_playlists; i++) { struct playlist *pls = c->playlists[i]; - if (stream_index >= pls->stream_offset && - stream_index - pls->stream_offset < pls->ctx->nb_streams) { - seek_pls = pls; - break; + for (j = 0; j < pls->n_main_streams; j++) { + if (pls->main_streams[j] == s->streams[stream_index]) { + seek_pls = pls; + stream_subdemuxer_index = j; + break; + } } } /* check if the timestamp is valid for the playlist with the @@ -1974,7 +1991,7 @@ static int hls_read_seek(AVFormatContext *s, int stream_index, /* set segment now so we do not need to search again below */ seek_pls->cur_seq_no = seq_no; - seek_pls->seek_stream_index = stream_index - seek_pls->stream_offset; + seek_pls->seek_stream_index = stream_subdemuxer_index; for (i = 0; i < c->n_playlists; i++) { /* Reset reading */ From 83db3c84fa72e8d4d864ed796438ebfb2ee4bcc3 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Thu, 28 Jul 2016 00:00:37 +0300 Subject: [PATCH 48/71] avformat/hls: Move stream propagation to a separate function Creation of main demuxer streams from subdemuxer streams is moved to update_streams_from_subdemuxer() which can be called repeatedly. There should be no functional changes. --- libavformat/hls.c | 134 ++++++++++++++++++++++++---------------------- 1 file changed, 69 insertions(+), 65 deletions(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index 59f5e38f9f0c4..35ece98bb8386 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -1348,25 +1348,6 @@ static int read_data(void *opaque, uint8_t *buf, int buf_size) goto restart; } -static int playlist_in_multiple_variants(HLSContext *c, struct playlist *pls) -{ - int variant_count = 0; - int i, j; - - for (i = 0; i < c->n_variants && variant_count < 2; i++) { - struct variant *v = c->variants[i]; - - for (j = 0; j < v->n_playlists; j++) { - if (v->playlists[j] == pls) { - variant_count++; - break; - } - } - } - - return variant_count >= 2; -} - static void add_renditions_to_variant(HLSContext *c, struct variant *var, enum AVMediaType type, const char *group_id) { @@ -1520,11 +1501,65 @@ static int nested_io_open(AVFormatContext *s, AVIOContext **pb, const char *url, return AVERROR(EPERM); } +static void add_stream_to_programs(AVFormatContext *s, struct playlist *pls, AVStream *stream) +{ + HLSContext *c = s->priv_data; + int i, j; + int bandwidth = -1; + + for (i = 0; i < c->n_variants; i++) { + struct variant *v = c->variants[i]; + + for (j = 0; j < v->n_playlists; j++) { + if (v->playlists[j] != pls) + continue; + + av_program_add_stream_index(s, i, stream->index); + + if (bandwidth < 0) + bandwidth = v->bandwidth; + else if (bandwidth != v->bandwidth) + bandwidth = -1; /* stream in multiple variants with different bandwidths */ + } + } + + if (bandwidth >= 0) + av_dict_set_int(&stream->metadata, "variant_bitrate", bandwidth, 0); +} + +/* add new subdemuxer streams to our context, if any */ +static int update_streams_from_subdemuxer(AVFormatContext *s, struct playlist *pls) +{ + while (pls->n_main_streams < pls->ctx->nb_streams) { + int ist_idx = pls->n_main_streams; + AVStream *st = avformat_new_stream(s, NULL); + AVStream *ist = pls->ctx->streams[ist_idx]; + + if (!st) + return AVERROR(ENOMEM); + + st->id = pls->index; + + avcodec_parameters_copy(st->codecpar, ist->codecpar); + + if (pls->is_id3_timestamped) /* custom timestamps via id3 */ + avpriv_set_pts_info(st, 33, 1, MPEG_TIME_BASE); + else + avpriv_set_pts_info(st, ist->pts_wrap_bits, ist->time_base.num, ist->time_base.den); + + dynarray_add(&pls->main_streams, &pls->n_main_streams, st); + + add_stream_to_programs(s, pls, st); + } + + return 0; +} + static int hls_read_header(AVFormatContext *s) { void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb; HLSContext *c = s->priv_data; - int ret = 0, i, j; + int ret = 0, i; int highest_cur_seq_no = 0; c->ctx = s; @@ -1600,6 +1635,17 @@ static int hls_read_header(AVFormatContext *s) add_renditions_to_variant(c, var, AVMEDIA_TYPE_SUBTITLE, var->subtitles_group); } + /* Create a program for each variant */ + for (i = 0; i < c->n_variants; i++) { + struct variant *v = c->variants[i]; + AVProgram *program; + + program = av_new_program(s, i); + if (!program) + goto fail; + av_dict_set_int(&program->metadata, "variant_bitrate", v->bandwidth, 0); + } + /* Select the starting segments */ for (i = 0; i < c->n_playlists; i++) { struct playlist *pls = c->playlists[i]; @@ -1688,57 +1734,15 @@ static int hls_read_header(AVFormatContext *s) av_log(s, AV_LOG_WARNING, "No expected HTTP requests have been made\n"); /* Create new AVStreams for each stream in this playlist */ - for (j = 0; j < pls->ctx->nb_streams; j++) { - AVStream *st = avformat_new_stream(s, NULL); - AVStream *ist = pls->ctx->streams[j]; - if (!st) { - ret = AVERROR(ENOMEM); - goto fail; - } - st->id = i; - - avcodec_parameters_copy(st->codecpar, pls->ctx->streams[j]->codecpar); - - if (pls->is_id3_timestamped) /* custom timestamps via id3 */ - avpriv_set_pts_info(st, 33, 1, MPEG_TIME_BASE); - else - avpriv_set_pts_info(st, ist->pts_wrap_bits, ist->time_base.num, ist->time_base.den); - - dynarray_add(&pls->main_streams, &pls->n_main_streams, st); - } + ret = update_streams_from_subdemuxer(s, pls); + if (ret < 0) + goto fail; add_metadata_from_renditions(s, pls, AVMEDIA_TYPE_AUDIO); add_metadata_from_renditions(s, pls, AVMEDIA_TYPE_VIDEO); add_metadata_from_renditions(s, pls, AVMEDIA_TYPE_SUBTITLE); } - /* Create a program for each variant */ - for (i = 0; i < c->n_variants; i++) { - struct variant *v = c->variants[i]; - AVProgram *program; - - program = av_new_program(s, i); - if (!program) - goto fail; - av_dict_set_int(&program->metadata, "variant_bitrate", v->bandwidth, 0); - - for (j = 0; j < v->n_playlists; j++) { - struct playlist *pls = v->playlists[j]; - int is_shared = playlist_in_multiple_variants(c, pls); - int k; - - for (k = 0; k < pls->n_main_streams; k++) { - struct AVStream *st = pls->main_streams[k]; - - av_program_add_stream_index(s, i, st->index); - - /* Set variant_bitrate for streams unique to this variant */ - if (!is_shared && v->bandwidth) - av_dict_set_int(&st->metadata, "variant_bitrate", v->bandwidth, 0); - } - } - } - return 0; fail: free_playlist_list(c); From 04964ac311abe670fb3b60290a330f2067544b13 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Tue, 26 Jul 2016 11:33:38 +0300 Subject: [PATCH 49/71] avformat/hls: Fix missing streams in some cases with MPEG TS HLS demuxer calls the subdemuxer avformat_find_stream_info() while overriding the subdemuxer AVFMTCTX_NOHEADER flag by clearing it. However, this prevents some streams in some MPEG TS streams from being detected properly. Simply removing the clearing of the flag would cause the inner avformat_find_stream_info() call to take longer in some cases, without a way to control it. To fix the issue, do not clear the flag but propagate it to HLS demuxer. To avoid the above-mentioned mandatory delay, the call to avformat_find_stream_info() is dropped except in the HLS ID3 timestamped case. The HLS demuxer user should be calling avformat_find_stream_info() on the HLS demuxer if it wants to find the stream info. The main streams are now created dynamically after read_header time if the subdemuxer uses AVFMTCTX_NOHEADER (mpegts). Subdemuxer avformat_find_stream_info() is still called for the HLS ID3 timestamped case as the HLS demuxer needs to know the packet durations to properly interleave ID3 timestamped streams with MPEG TS streams on sub-segment level. Fixes ticket #4930. --- libavformat/hls.c | 56 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/libavformat/hls.c b/libavformat/hls.c index 35ece98bb8386..1ad08a4d40d62 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -98,6 +98,7 @@ struct playlist { int index; AVFormatContext *ctx; AVPacket pkt; + int has_noheader_flag; /* main demuxer streams associated with this playlist * indexed by the subdemuxer stream indexes */ @@ -1555,6 +1556,27 @@ static int update_streams_from_subdemuxer(AVFormatContext *s, struct playlist *p return 0; } +static void update_noheader_flag(AVFormatContext *s) +{ + HLSContext *c = s->priv_data; + int flag_needed = 0; + int i; + + for (i = 0; i < c->n_playlists; i++) { + struct playlist *pls = c->playlists[i]; + + if (pls->has_noheader_flag) { + flag_needed = 1; + break; + } + } + + if (flag_needed) + s->ctx_flags |= AVFMTCTX_NOHEADER; + else + s->ctx_flags &= ~AVFMTCTX_NOHEADER; +} + static int hls_read_header(AVFormatContext *s) { void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb; @@ -1725,14 +1747,23 @@ static int hls_read_header(AVFormatContext *s) pls->id3_deferred_extra = NULL; } - pls->ctx->ctx_flags &= ~AVFMTCTX_NOHEADER; - ret = avformat_find_stream_info(pls->ctx, NULL); - if (ret < 0) - goto fail; - if (pls->is_id3_timestamped == -1) av_log(s, AV_LOG_WARNING, "No expected HTTP requests have been made\n"); + /* + * For ID3 timestamped raw audio streams we need to detect the packet + * durations to calculate timestamps in fill_timing_for_id3_timestamped_stream(), + * but for other streams we can rely on our user calling avformat_find_stream_info() + * on us if they want to. + */ + if (pls->is_id3_timestamped) { + ret = avformat_find_stream_info(pls->ctx, NULL); + if (ret < 0) + goto fail; + } + + pls->has_noheader_flag = !!(pls->ctx->ctx_flags & AVFMTCTX_NOHEADER); + /* Create new AVStreams for each stream in this playlist */ ret = update_streams_from_subdemuxer(s, pls); if (ret < 0) @@ -1743,6 +1774,8 @@ static int hls_read_header(AVFormatContext *s) add_metadata_from_renditions(s, pls, AVMEDIA_TYPE_SUBTITLE); } + update_noheader_flag(s); + return 0; fail: free_playlist_list(c); @@ -1914,6 +1947,19 @@ static int hls_read_packet(AVFormatContext *s, AVPacket *pkt) if (minplaylist >= 0) { struct playlist *pls = c->playlists[minplaylist]; + ret = update_streams_from_subdemuxer(s, pls); + if (ret < 0) { + av_packet_unref(&pls->pkt); + reset_packet(&pls->pkt); + return ret; + } + + /* check if noheader flag has been cleared by the subdemuxer */ + if (pls->has_noheader_flag && !(pls->ctx->ctx_flags & AVFMTCTX_NOHEADER)) { + pls->has_noheader_flag = 0; + update_noheader_flag(s); + } + if (pls->pkt.stream_index >= pls->n_main_streams) { av_log(s, AV_LOG_ERROR, "stream index inconsistency: index %d, %d main streams, %d subdemuxer streams\n", pls->pkt.stream_index, pls->n_main_streams, pls->ctx->nb_streams); From 70c1647a3501fa6182c04c9ce66f477def64a611 Mon Sep 17 00:00:00 2001 From: softworkz Date: Sun, 17 Jul 2016 04:19:41 +0200 Subject: [PATCH 50/71] avformat/matroskaenc: Write duration early during mkv_write_header (Rev #3) Rev #2: Fixes doubled header writing, checked FATE running without errors Rev #3: Fixed coding style This commit addresses the following scenario: we are using ffmpeg to transcode or remux mkv (or something else) to mkv. The result is being streamed on-the-fly to an HTML5 client (streaming starts while ffmpeg is still running). The problem here is that the client is unable to detect the duration because the duration is only written to the mkv at the end of the transcoding/remoxing process. In matroskaenc.c, the duration is only written during mkv_write_trailer but not during mkv_write_header. The approach: FFMPEG is currently putting quite some effort to estimate the durations of source streams, but in many cases the source stream durations are still left at 0 and these durations are nowhere mapped to or used for output streams. As much as I would have liked to deduct or estimate output durations based on input stream durations - I realized that this is a hard task (as Nicolas already mentioned in a previous conversation). It would involve changes to the duration calculation/estimation/deduction for input streams and propagating these durations to output streams or the output context in a correct way. So I looked for a simple and small solution with better chances to get accepted. In webmdashenc.c I found that a duration is written during write_header and this duration is taken from the streams' metadata, so I decided for a similar approach. And here's what it does: At first it is checking the duration of the AVFormatContext. In typical cases this value is not set, but: It is set in cases where the user has specified a recording_time or an end_time via the -t or -to parameters. Then it is looking for a DURATION metadata field in the metadata of the output context (AVFormatContext::metadata). This would only exist in case the user has explicitly specified a metadata DURATION value from the command line. Then it is iterating all streams looking for a "DURATION" metadata (this works unless the option "-map_metadata -1" has been specified) and determines the maximum value. The precendence is as follows: 1. Use duration of AVFormatContext - 2. Use explicitly specified metadata duration value - 3. Use maximum (mapped) metadata duration over all streams. To test this: 1. With explicit recording time: ffmpeg -i file:"src.mkv" -loglevel debug -t 01:38:36.000 -y "dest.mkv" 2. Take duration from metadata specified via command line parameters: ffmpeg -i file:"src.mkv" -loglevel debug -map_metadata -1 -metadata Duration="01:14:33.00" -y "dest.mkv" 3. Take duration from mapped input metadata: ffmpeg -i file:"src.mkv" -loglevel debug -y "dest.mkv" Regression risk: Very low IMO because it only affects the header while ffmpeg is still running. When ffmpeg completes the process, the duration is rewritten to the header with the usual value (same like without this commit). Signed-off-by: SoftWorkz Signed-off-by: Michael Niedermayer --- libavformat/matroskaenc.c | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index 3648d4945306e..f8dfa1cb72674 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -44,6 +44,7 @@ #include "libavutil/mastering_display_metadata.h" #include "libavutil/mathematics.h" #include "libavutil/opt.h" +#include "libavutil/parseutils.h" #include "libavutil/random_seed.h" #include "libavutil/rational.h" #include "libavutil/samplefmt.h" @@ -1487,6 +1488,30 @@ static int mkv_write_attachments(AVFormatContext *s) return 0; } +static int64_t get_metadata_duration(AVFormatContext *s) +{ + int i = 0; + int64_t max = 0; + int64_t us; + + AVDictionaryEntry *explicitDuration = av_dict_get(s->metadata, "DURATION", NULL, 0); + if (explicitDuration && (av_parse_time(&us, explicitDuration->value, 1) == 0) && us > 0) { + av_log(s, AV_LOG_DEBUG, "get_metadata_duration found duration in context metadata: %" PRId64 "\n", us); + return us; + } + + for (i = 0; i < s->nb_streams; i++) { + int64_t us; + AVDictionaryEntry *duration = av_dict_get(s->streams[i]->metadata, "DURATION", NULL, 0); + + if (duration && (av_parse_time(&us, duration->value, 1) == 0)) + max = FFMAX(max, us); + } + + av_log(s, AV_LOG_DEBUG, "get_metadata_duration returned: %" PRId64 "\n", max); + return max; +} + static int mkv_write_header(AVFormatContext *s) { MatroskaMuxContext *mkv = s->priv_data; @@ -1596,7 +1621,19 @@ static int mkv_write_header(AVFormatContext *s) mkv->duration = 0; mkv->duration_offset = avio_tell(pb); if (!mkv->is_live) { - put_ebml_void(pb, 11); // assumes double-precision float to be written + int64_t metadata_duration = get_metadata_duration(s); + + if (s->duration > 0) { + int64_t scaledDuration = av_rescale(s->duration, 1000, AV_TIME_BASE); + put_ebml_float(pb, MATROSKA_ID_DURATION, scaledDuration); + av_log(s, AV_LOG_DEBUG, "Write early duration from recording time = %" PRIu64 "\n", scaledDuration); + } else if (metadata_duration > 0) { + int64_t scaledDuration = av_rescale(metadata_duration, 1000, AV_TIME_BASE); + put_ebml_float(pb, MATROSKA_ID_DURATION, scaledDuration); + av_log(s, AV_LOG_DEBUG, "Write early duration from metadata = %" PRIu64 "\n", scaledDuration); + } else { + put_ebml_void(pb, 11); // assumes double-precision float to be written + } } end_ebml_master(pb, segment_info); From fb91143ef150263451b331e3e66f8ba51d9a8c8d Mon Sep 17 00:00:00 2001 From: Burt P Date: Sat, 23 Jul 2016 21:26:51 -0500 Subject: [PATCH 51/71] af_hdcd: Report PE as being intermittent or permanent The Peak Extend feature could be enabled permanently or only when needed. This is now reported. Signed-off-by: Burt P Signed-off-by: Michael Niedermayer --- libavfilter/af_hdcd.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/libavfilter/af_hdcd.c b/libavfilter/af_hdcd.c index f265ed936bf95..6f3eb1e875062 100644 --- a/libavfilter/af_hdcd.c +++ b/libavfilter/af_hdcd.c @@ -851,6 +851,18 @@ typedef struct { AVFilterContext *fctx; /* filter context for logging errors */ } hdcd_state_t; +typedef enum { + HDCD_PE_NEVER =0, + HDCD_PE_INTERMITTENT =1, + HDCD_PE_PERMANENT =2 +} hdcd_pe_t; + +const char* pe_str[] = { + "never enabled", + "enabled intermittently", + "enabled permanently" + }; + typedef struct HDCDContext { const AVClass *class; hdcd_state_t state[2]; @@ -858,7 +870,7 @@ typedef struct HDCDContext { /* User information/stats */ int hdcd_detected; int det_errors; /* detectable errors */ - int uses_peak_extend; + hdcd_pe_t peak_extend; int uses_transient_filter; /* detected, but not implemented */ float max_gain_adjustment; /* in dB, expected in the range -6.0 to 0.0 */ } HDCDContext; @@ -1115,7 +1127,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) const int16_t *in_data; int32_t *out_data; int n, c; - int detect; + int detect, packets, pe_packets; out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { @@ -1132,18 +1144,28 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) } detect = 0; + packets = 0; + pe_packets = 0; s->det_errors = 0; for (c = 0; c < inlink->channels; c++) { hdcd_state_t *state = &s->state[c]; hdcd_process(state, out_data + c, in->nb_samples, out->channels); if (state->sustain) detect++; - s->uses_peak_extend |= !!state->count_peak_extend; + packets += state->code_counterA + state->code_counterB; + pe_packets += state->count_peak_extend; s->uses_transient_filter |= !!state->count_transient_filter; s->max_gain_adjustment = FFMIN(s->max_gain_adjustment, GAINTOFLOAT(state->max_gain)); s->det_errors += state->code_counterA_almost + state->code_counterB_checkfails + state->code_counterC_unmatched; } + if (pe_packets) { + /* if every valid packet has used PE, call it permanent */ + if (packets == pe_packets) + s->peak_extend = HDCD_PE_PERMANENT; + else + s->peak_extend = HDCD_PE_INTERMITTENT; + } else s->peak_extend = HDCD_PE_NEVER; /* HDCD is detected if a valid packet is active in all (both) * channels at the same time. */ if (detect == inlink->channels) s->hdcd_detected = 1; @@ -1224,7 +1246,7 @@ static av_cold void uninit(AVFilterContext *ctx) if (s->hdcd_detected) av_log(ctx, AV_LOG_INFO, "HDCD detected: yes, peak_extend: %s, max_gain_adj: %0.1f dB, transient_filter: %s, detectable errors: %d%s\n", - (s->uses_peak_extend) ? "enabled" : "never enabled", + pe_str[s->peak_extend], s->max_gain_adjustment, (s->uses_transient_filter) ? "detected" : "not detected", s->det_errors, (s->det_errors) ? " (try -v verbose)" : "" From 4791716c1dca53a3c9e900fdb47bea9731a2b2bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20B=C5=93sch?= Date: Thu, 28 Jul 2016 09:29:20 +0200 Subject: [PATCH 52/71] lavfi/hdcd: mark pe_str as static and const --- libavfilter/af_hdcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavfilter/af_hdcd.c b/libavfilter/af_hdcd.c index 6f3eb1e875062..6b406e7abc175 100644 --- a/libavfilter/af_hdcd.c +++ b/libavfilter/af_hdcd.c @@ -857,7 +857,7 @@ typedef enum { HDCD_PE_PERMANENT =2 } hdcd_pe_t; -const char* pe_str[] = { +static const char * const pe_str[] = { "never enabled", "enabled intermittently", "enabled permanently" From 37abc8cca2565eed7e1b1ff2560774faa371eb63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20B=C5=93sch?= Date: Thu, 28 Jul 2016 09:29:45 +0200 Subject: [PATCH 53/71] lavfi/hdcd: fix style --- libavfilter/af_hdcd.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/libavfilter/af_hdcd.c b/libavfilter/af_hdcd.c index 6b406e7abc175..63ee177e4a961 100644 --- a/libavfilter/af_hdcd.c +++ b/libavfilter/af_hdcd.c @@ -852,16 +852,16 @@ typedef struct { } hdcd_state_t; typedef enum { - HDCD_PE_NEVER =0, - HDCD_PE_INTERMITTENT =1, - HDCD_PE_PERMANENT =2 + HDCD_PE_NEVER = 0, + HDCD_PE_INTERMITTENT = 1, + HDCD_PE_PERMANENT = 2, } hdcd_pe_t; static const char * const pe_str[] = { "never enabled", "enabled intermittently", "enabled permanently" - }; +}; typedef struct HDCDContext { const AVClass *class; @@ -1165,7 +1165,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) s->peak_extend = HDCD_PE_PERMANENT; else s->peak_extend = HDCD_PE_INTERMITTENT; - } else s->peak_extend = HDCD_PE_NEVER; + } else { + s->peak_extend = HDCD_PE_NEVER; + } /* HDCD is detected if a valid packet is active in all (both) * channels at the same time. */ if (detect == inlink->channels) s->hdcd_detected = 1; From d7ae4f79d364031be8a2209ee8de60c991aeb0b3 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Tue, 26 Jul 2016 13:10:27 +0200 Subject: [PATCH 54/71] avfilter/f_drawgraph: add another slide mode --- doc/filters.texi | 3 + libavfilter/f_drawgraph.c | 170 +++++++++++++++++++++++++++++++++++--- 2 files changed, 161 insertions(+), 12 deletions(-) diff --git a/doc/filters.texi b/doc/filters.texi index 5a64853666282..929cc337be404 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -6438,6 +6438,9 @@ Scroll from right to left. @item rscroll Scroll from left to right. + +@item picture +Draw single picture. @end table Default is @code{frame}. diff --git a/libavfilter/f_drawgraph.c b/libavfilter/f_drawgraph.c index 0ca0d229ed895..4c705fe851196 100644 --- a/libavfilter/f_drawgraph.c +++ b/libavfilter/f_drawgraph.c @@ -44,6 +44,9 @@ typedef struct DrawGraphContext { int x; int prev_y[4]; int first; + float *values[4]; + int values_size[4]; + int nb_values; } DrawGraphContext; #define OFFSET(x) offsetof(DrawGraphContext, x) @@ -65,11 +68,12 @@ static const AVOption drawgraph_options[] = { {"bar", "draw bars", OFFSET(mode), AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "mode"}, {"dot", "draw dots", OFFSET(mode), AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "mode"}, {"line", "draw lines", OFFSET(mode), AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "mode"}, - { "slide", "set slide mode", OFFSET(slide), AV_OPT_TYPE_INT, {.i64=0}, 0, 3, FLAGS, "slide" }, + { "slide", "set slide mode", OFFSET(slide), AV_OPT_TYPE_INT, {.i64=0}, 0, 4, FLAGS, "slide" }, {"frame", "draw new frames", OFFSET(slide), AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "slide"}, {"replace", "replace old columns with new", OFFSET(slide), AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "slide"}, {"scroll", "scroll from right to left", OFFSET(slide), AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "slide"}, {"rscroll", "scroll from left to right", OFFSET(slide), AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, FLAGS, "slide"}, + {"picture", "display graph in single frame", OFFSET(slide), AV_OPT_TYPE_CONST, {.i64=4}, 0, 0, FLAGS, "slide"}, { "size", "set graph size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str="900x256"}, 0, 0, FLAGS }, { "s", "set graph size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str="900x256"}, 0, 0, FLAGS }, { NULL } @@ -100,6 +104,18 @@ static av_cold int init(AVFilterContext *ctx) s->first = 1; + if (s->slide == 4) { + s->values[0] = av_fast_realloc(NULL, &s->values_size[0], 2000); + s->values[1] = av_fast_realloc(NULL, &s->values_size[1], 2000); + s->values[2] = av_fast_realloc(NULL, &s->values_size[2], 2000); + s->values[3] = av_fast_realloc(NULL, &s->values_size[3], 2000); + + if (!s->values[0] || !s->values[1] || + !s->values[2] || !s->values[3]) { + return AVERROR(ENOMEM); + } + } + return 0; } @@ -144,19 +160,45 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) AVFrame *out = s->out; int i; - if (!s->out || s->out->width != outlink->w || - s->out->height != outlink->h) { - av_frame_free(&s->out); - s->out = ff_get_video_buffer(outlink, outlink->w, outlink->h); - out = s->out; - if (!s->out) { - av_frame_free(&in); + if (s->slide == 4 && s->nb_values >= s->values_size[0] / sizeof(float)) { + float *ptr; + + ptr = av_fast_realloc(s->values[0], &s->values_size[0], s->values_size[0] * 2); + if (!ptr) return AVERROR(ENOMEM); - } + s->values[0] = ptr; + + ptr = av_fast_realloc(s->values[1], &s->values_size[1], s->values_size[1] * 2); + if (!ptr) + return AVERROR(ENOMEM); + s->values[1] = ptr; + + ptr = av_fast_realloc(s->values[2], &s->values_size[2], s->values_size[2] * 2); + if (!ptr) + return AVERROR(ENOMEM); + s->values[2] = ptr; - clear_image(s, out, outlink); + ptr = av_fast_realloc(s->values[3], &s->values_size[3], s->values_size[3] * 2); + if (!ptr) + return AVERROR(ENOMEM); + s->values[3] = ptr; + } + + if (s->slide != 4 || s->nb_values == 0) { + if (!s->out || s->out->width != outlink->w || + s->out->height != outlink->h) { + av_frame_free(&s->out); + s->out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + out = s->out; + if (!s->out) { + av_frame_free(&in); + return AVERROR(ENOMEM); + } + + clear_image(s, out, outlink); + } + av_frame_copy_props(out, in); } - av_frame_copy_props(out, in); metadata = av_frame_get_metadata(in); @@ -166,6 +208,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) uint32_t fg, bg; float vf; + if (s->slide == 4) + s->values[i][s->nb_values] = NAN; + e = av_dict_get(metadata, s->key[i], NULL, 0); if (!e || !e->value) continue; @@ -175,6 +220,11 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) vf = av_clipf(vf, s->min, s->max); + if (s->slide == 4) { + s->values[i][s->nb_values] = vf; + continue; + } + values[VAR_MIN] = s->min; values[VAR_MAX] = s->max; values[VAR_VAL] = vf; @@ -255,12 +305,99 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) } } + s->nb_values++; s->x++; av_frame_free(&in); + + if (s->slide == 4) + return 0; + return ff_filter_frame(outlink, av_frame_clone(s->out)); } +static int request_frame(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + DrawGraphContext *s = ctx->priv; + AVFrame *out = s->out; + int ret, i, k, step, l; + + ret = ff_request_frame(ctx->inputs[0]); + + if (s->slide == 4 && ret == AVERROR_EOF && s->nb_values > 0) { + s->x = l = 0; + step = ceil(s->nb_values / (float)s->w); + + for (k = 0; k < s->nb_values; k++) { + for (i = 0; i < 4; i++) { + double values[VAR_VARS_NB]; + int j, y, x, old; + uint32_t fg, bg; + float vf = s->values[i][k]; + + if (isnan(vf)) + continue; + + values[VAR_MIN] = s->min; + values[VAR_MAX] = s->max; + values[VAR_VAL] = vf; + + fg = av_expr_eval(s->fg_expr[i], values, NULL); + bg = AV_RN32(s->bg); + + x = s->x; + y = (outlink->h - 1) * (1 - ((vf - s->min) / (s->max - s->min))); + + switch (s->mode) { + case 0: + old = AV_RN32(out->data[0] + y * out->linesize[0] + x * 4); + for (j = y; j < outlink->h; j++) { + if (old != bg && + (AV_RN32(out->data[0] + j * out->linesize[0] + x * 4) != old) || + AV_RN32(out->data[0] + FFMIN(j+1, outlink->h - 1) * out->linesize[0] + x * 4) != old) { + draw_dot(fg, x, j, out); + break; + } + draw_dot(fg, x, j, out); + } + break; + case 1: + draw_dot(fg, x, y, out); + break; + case 2: + if (s->first) { + s->first = 0; + s->prev_y[i] = y; + } + + if (y <= s->prev_y[i]) { + for (j = y; j <= s->prev_y[i]; j++) + draw_dot(fg, x, j, out); + } else { + for (j = s->prev_y[i]; j <= y; j++) + draw_dot(fg, x, j, out); + } + s->prev_y[i] = y; + break; + } + } + + l++; + if (l >= step) { + l = 0; + s->x++; + } + } + + s->nb_values = 0; + out->pts = 0; + ret = ff_filter_frame(ctx->outputs[0], s->out); + } + + return ret; +} + static int config_output(AVFilterLink *outlink) { DrawGraphContext *s = outlink->src->priv; @@ -279,7 +416,14 @@ static av_cold void uninit(AVFilterContext *ctx) for (i = 0; i < 4; i++) av_expr_free(s->fg_expr[i]); - av_frame_free(&s->out); + + if (s->slide != 4) + av_frame_free(&s->out); + + av_freep(&s->values[0]); + av_freep(&s->values[1]); + av_freep(&s->values[2]); + av_freep(&s->values[3]); } #if CONFIG_DRAWGRAPH_FILTER @@ -300,6 +444,7 @@ static const AVFilterPad drawgraph_outputs[] = { .name = "default", .type = AVMEDIA_TYPE_VIDEO, .config_props = config_output, + .request_frame = request_frame, }, { NULL } }; @@ -337,6 +482,7 @@ static const AVFilterPad adrawgraph_outputs[] = { .name = "default", .type = AVMEDIA_TYPE_VIDEO, .config_props = config_output, + .request_frame = request_frame, }, { NULL } }; From 65b2feb890db3c1eeb8069c5313aa3e2345766ed Mon Sep 17 00:00:00 2001 From: Zhao Zhili Date: Tue, 19 Jul 2016 00:30:54 +0800 Subject: [PATCH 55/71] avutil/mem: fix memleak The original code assumes av_realloc() will free ptr if size is zero. The assumes is incorrect now. Signed-off-by: Michael Niedermayer --- libavutil/mem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavutil/mem.c b/libavutil/mem.c index 8dfaad8271068..809ec010842ce 100644 --- a/libavutil/mem.c +++ b/libavutil/mem.c @@ -179,7 +179,7 @@ void *av_realloc_f(void *ptr, size_t nelem, size_t elsize) return NULL; } r = av_realloc(ptr, size); - if (!r && size) + if (!r) av_free(ptr); return r; } From 83b9909398c6abc30e88174406d542bf781a955d Mon Sep 17 00:00:00 2001 From: Matthieu Bouron Date: Thu, 28 Jul 2016 16:10:30 +0200 Subject: [PATCH 56/71] Changelog: add entry for MediaCodec hwaccel --- Changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog b/Changelog index 7f536db30baaf..0f9b4cf6b0bbf 100644 --- a/Changelog +++ b/Changelog @@ -11,6 +11,7 @@ version : - 16-bit support in curves filter - 16-bit support in selectivecolor filter - OpenH264 decoder wrapper +- MediaCodec hwaccel version 3.1: From 08c1b6bb72e4bed711b2d082d5aaad474b302e8f Mon Sep 17 00:00:00 2001 From: Petru Rares Sincraian Date: Thu, 28 Jul 2016 19:31:55 +0200 Subject: [PATCH 57/71] fate: add test for silenceremove filter Signed-off-by: Michael Niedermayer --- tests/fate/filter-audio.mak | 4 ++++ tests/ref/fate/filter-silenceremove | 35 +++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 tests/ref/fate/filter-silenceremove diff --git a/tests/fate/filter-audio.mak b/tests/fate/filter-audio.mak index f71fb52b51d31..ed1cbb1a3163c 100644 --- a/tests/fate/filter-audio.mak +++ b/tests/fate/filter-audio.mak @@ -114,6 +114,10 @@ fate-filter-extrastereo: tests/data/asynth-44100-2.wav fate-filter-extrastereo: SRC = $(TARGET_PATH)/tests/data/asynth-44100-2.wav fate-filter-extrastereo: CMD = framecrc -i $(SRC) -aframes 20 -af extrastereo=m=2 +FATE_AFILTER_SAMPLES-$(call FILTERDEMDECENCMUX, SILENCEREMOVE, WAV, PCM_S16LE, PCM_S16LE, WAV) += fate-filter-silenceremove +fate-filter-silenceremove: SRC = $(TARGET_SAMPLES)/audio-reference/divertimenti_2ch_96kHz_s24.wav +fate-filter-silenceremove: CMD = framecrc -i $(SRC) -aframes 30 -af silenceremove=0:0:0:-1:0:-90dB + tests/data/hls-list.m3u8: TAG = GEN tests/data/hls-list.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data $(M)$(TARGET_EXEC) $(TARGET_PATH)/$< \ diff --git a/tests/ref/fate/filter-silenceremove b/tests/ref/fate/filter-silenceremove new file mode 100644 index 0000000000000..43360e8dbc5cd --- /dev/null +++ b/tests/ref/fate/filter-silenceremove @@ -0,0 +1,35 @@ +#tb 0: 1/192000 +#media_type 0: audio +#codec_id 0: pcm_s16le +#sample_rate 0: 192000 +#channel_layout 0: 3 +0, 0, 0, 1, 4, 0x00200008 +0, 1, 1, 1, 4, 0x00180006 +0, 2, 2, 1, 4, 0x001c0007 +0, 3, 3, 1, 4, 0x03250208 +0, 4, 4, 1, 4, 0x03290208 +0, 5, 5, 1, 4, 0x03230207 +0, 6, 6, 1, 4, 0x031f0206 +0, 7, 7, 1, 4, 0x03250208 +0, 8, 8, 1, 4, 0x00220009 +0, 9, 9, 1, 4, 0x00200009 +0, 10, 10, 1, 4, 0x03250208 +0, 11, 11, 1, 4, 0x0335020c +0, 12, 12, 1, 4, 0x034b0211 +0, 13, 13, 1, 4, 0x034b020f +0, 14, 14, 1, 4, 0x0343020e +0, 15, 15, 1, 4, 0x00440011 +0, 16, 16, 1, 4, 0x00400011 +0, 17, 17, 1, 4, 0x003a000f +0, 18, 18, 1, 4, 0x0339020d +0, 19, 19, 1, 4, 0x003a000f +0, 20, 20, 1, 4, 0x0034000d +0, 21, 21, 1, 4, 0x0034000d +0, 22, 22, 1, 4, 0x0036000e +0, 23, 23, 1, 4, 0x03290208 +0, 24, 24, 1, 4, 0x03230204 +0, 25, 25, 1, 4, 0x03170201 +0, 26, 26, 1, 4, 0x030701fd +0, 27, 27, 1, 4, 0x02fd01fc +0, 28, 28, 1, 4, 0x00060002 +0, 29, 29, 1, 4, 0x000c0004 From 286368099a3a2db515264dd51cf12376db719ab2 Mon Sep 17 00:00:00 2001 From: Petru Rares Sincraian Date: Thu, 28 Jul 2016 20:01:40 +0200 Subject: [PATCH 58/71] fate: add test for stereotools filter Signed-off-by: Michael Niedermayer --- tests/fate/filter-audio.mak | 4 ++++ tests/ref/fate/filter-stereotools | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 tests/ref/fate/filter-stereotools diff --git a/tests/fate/filter-audio.mak b/tests/fate/filter-audio.mak index ed1cbb1a3163c..ac4c3f47bc63d 100644 --- a/tests/fate/filter-audio.mak +++ b/tests/fate/filter-audio.mak @@ -118,6 +118,10 @@ FATE_AFILTER_SAMPLES-$(call FILTERDEMDECENCMUX, SILENCEREMOVE, WAV, PCM_S16LE, P fate-filter-silenceremove: SRC = $(TARGET_SAMPLES)/audio-reference/divertimenti_2ch_96kHz_s24.wav fate-filter-silenceremove: CMD = framecrc -i $(SRC) -aframes 30 -af silenceremove=0:0:0:-1:0:-90dB +FATE_AFILTER_SAMPLES-$(call FILTERDEMDECENCMUX, STEREOTOOLS, WAV, PCM_S16LE, PCM_S16LE, WAV) += fate-filter-stereotools +fate-filter-stereotools: SRC = $(TARGET_SAMPLES)/audio-reference/luckynight_2ch_44kHz_s16.wav +fate-filter-stereotools: CMD = framecrc -i $(SRC) -aframes 20 -af stereotools=mlev=0.015625 + tests/data/hls-list.m3u8: TAG = GEN tests/data/hls-list.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data $(M)$(TARGET_EXEC) $(TARGET_PATH)/$< \ diff --git a/tests/ref/fate/filter-stereotools b/tests/ref/fate/filter-stereotools new file mode 100644 index 0000000000000..89babd693dd63 --- /dev/null +++ b/tests/ref/fate/filter-stereotools @@ -0,0 +1,25 @@ +#tb 0: 1/44100 +#media_type 0: audio +#codec_id 0: pcm_s16le +#sample_rate 0: 44100 +#channel_layout 0: 3 +0, 0, 0, 1024, 4096, 0x48b6d241 +0, 1024, 1024, 1024, 4096, 0xe0c4ca9a +0, 2048, 2048, 1024, 4096, 0x6dd8e26c +0, 3072, 3072, 1024, 4096, 0x047cce1c +0, 4096, 4096, 1024, 4096, 0x0b7bc8e4 +0, 5120, 5120, 1024, 4096, 0xf0c9d037 +0, 6144, 6144, 1024, 4096, 0x6f23c83d +0, 7168, 7168, 1024, 4096, 0xe6d8c099 +0, 8192, 8192, 1024, 4096, 0xcca3cb25 +0, 9216, 9216, 1024, 4096, 0xefced25b +0, 10240, 10240, 1024, 4096, 0x8614cdcb +0, 11264, 11264, 1024, 4096, 0x06d1eb3f +0, 12288, 12288, 1024, 4096, 0x7afbcffd +0, 13312, 13312, 1024, 4096, 0x6371dcd8 +0, 14336, 14336, 1024, 4096, 0xdd8f90d9 +0, 15360, 15360, 1024, 4096, 0x448c08f4 +0, 16384, 16384, 1024, 4096, 0x4d9b2d26 +0, 17408, 17408, 1024, 4096, 0x735a05da +0, 18432, 18432, 1024, 4096, 0x8651bf40 +0, 19456, 19456, 1024, 4096, 0xbf98c4e7 From 156b5bb9bf75777ee01b327ff3af01eeb4d7e3fd Mon Sep 17 00:00:00 2001 From: Stefano Sabatini Date: Tue, 19 Apr 2016 10:19:55 +0200 Subject: [PATCH 59/71] lavf/mpegtsenc: add special case for handling timed ID3 packets Set the stream_id to 0xbd (private_stream_id_1). Tools seem to assume that value, and this is consistent with MPEG TS specification (ITU-T H.222.0 section 2.12.3). --- libavformat/mpegtsenc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c index b45a283285df1..fd849e5b36671 100644 --- a/libavformat/mpegtsenc.c +++ b/libavformat/mpegtsenc.c @@ -1238,6 +1238,9 @@ static void mpegts_write_pes(AVFormatContext *s, AVStream *st, st->codecpar->codec_id == AV_CODEC_ID_AC3 && ts->m2ts_mode) { *q++ = 0xfd; + } else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA && + st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) { + *q++ = 0xbd; } else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA) { *q++ = stream_id != -1 ? stream_id : 0xfc; From 238733f7417cd290ebac6fa70f3e62ded2c0bb3f Mon Sep 17 00:00:00 2001 From: Josh de Kock Date: Fri, 29 Jul 2016 02:09:03 +0100 Subject: [PATCH 60/71] hapdec: remove unused memory.h include Most systems have this, so it isn't really a problem to include it even if it's not used, but some do not have memory.h as it is non-standard. Since it's unused just remove it anyway. --- libavcodec/hapdec.c | 1 - 1 file changed, 1 deletion(-) diff --git a/libavcodec/hapdec.c b/libavcodec/hapdec.c index 5a399dcb25dd9..f1d44cda24b51 100644 --- a/libavcodec/hapdec.c +++ b/libavcodec/hapdec.c @@ -37,7 +37,6 @@ #include "bytestream.h" #include "hap.h" #include "internal.h" -#include "memory.h" #include "snappy.h" #include "texturedsp.h" #include "thread.h" From 0219dc6c072586a14c641d108ef3e7da70fecae7 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer Date: Fri, 29 Jul 2016 02:45:16 +0200 Subject: [PATCH 61/71] avformat/rmdec: Clear extradata when extradata_size is cleared Signed-off-by: Michael Niedermayer --- libavformat/rmdec.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libavformat/rmdec.c b/libavformat/rmdec.c index cb0481ed4d9f4..0d3b56f1b53c6 100644 --- a/libavformat/rmdec.c +++ b/libavformat/rmdec.c @@ -207,6 +207,7 @@ static int rm_read_audio_stream_info(AVFormatContext *s, AVIOContext *pb, break; case AV_CODEC_ID_RA_288: st->codecpar->extradata_size= 0; + av_freep(&st->codecpar->extradata); ast->audio_framesize = st->codecpar->block_align; st->codecpar->block_align = coded_framesize; break; From bc9ce5f6bec01cea4c291e5a339d3c08d89700f0 Mon Sep 17 00:00:00 2001 From: Lucas Cooper Date: Mon, 25 Jul 2016 11:54:37 -0700 Subject: [PATCH 62/71] avfilter: Add new format for PSNR stats log Add an AVOption stats_version with a new header for V2 stats, which specifies the stats log version and lists the fields that will be present in the log (to ease parsing). The primary motivation is to facilitate the addition of optional fields to the log without breaking backwards compatibility, while making the logs easier to parse. Signed-off-by: Michael Niedermayer --- libavfilter/vf_psnr.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/libavfilter/vf_psnr.c b/libavfilter/vf_psnr.c index 0c8d0f1a310c2..3bec747573882 100644 --- a/libavfilter/vf_psnr.c +++ b/libavfilter/vf_psnr.c @@ -43,6 +43,8 @@ typedef struct PSNRContext { uint64_t nb_frames; FILE *stats_file; char *stats_file_str; + int stats_version; + int stats_header_written; int max[4], average_max; int is_rgb; uint8_t rgba_map[4]; @@ -60,6 +62,7 @@ typedef struct PSNRContext { static const AVOption psnr_options[] = { {"stats_file", "Set file where to store per-frame difference information", OFFSET(stats_file_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS }, {"f", "Set file where to store per-frame difference information", OFFSET(stats_file_str), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS }, + {"stats_version", "Set the format version for the stats file.", OFFSET(stats_version), AV_OPT_TYPE_INT, {.i64=1}, 1, 2, FLAGS }, { NULL } }; @@ -169,6 +172,19 @@ static AVFrame *do_psnr(AVFilterContext *ctx, AVFrame *main, set_meta(metadata, "lavfi.psnr.psnr_avg", 0, get_psnr(mse, 1, s->average_max)); if (s->stats_file) { + if (s->stats_version == 2 && !s->stats_header_written) { + fprintf(s->stats_file, "psnr_log_version:2 fields:n"); + fprintf(s->stats_file, ",mse_avg"); + for (j = 0; j < s->nb_components; j++) { + fprintf(s->stats_file, ",mse_%c", s->comps[j]); + } + fprintf(s->stats_file, ",psnr_avg"); + for (j = 0; j < s->nb_components; j++) { + fprintf(s->stats_file, ",psnr_%c", s->comps[j]); + } + fprintf(s->stats_file, "\n"); + s->stats_header_written = 1; + } fprintf(s->stats_file, "n:%"PRId64" mse_avg:%0.2f ", s->nb_frames, mse); for (j = 0; j < s->nb_components; j++) { c = s->is_rgb ? s->rgba_map[j] : j; From 52ec4cc09b5be755f166b7ed4755433c95173d6d Mon Sep 17 00:00:00 2001 From: Chris Cunningham Date: Wed, 27 Jul 2016 18:33:30 -0700 Subject: [PATCH 63/71] libavformat/matroskadec: Add test for seeking with codec delay. Also cleanup parens for the skip_to_timecode check. Signed-off-by: Michael Niedermayer --- libavformat/matroskadec.c | 2 +- tests/fate/seek.mak | 3 +++ tests/ref/seek/mkv-codec-delay | 48 ++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 tests/ref/seek/mkv-codec-delay diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c index 60b1b345d266f..d07a0920cff12 100644 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@ -3153,7 +3153,7 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, // Compare signed timecodes. Timecode may be negative due to codec delay // offset. We don't support timestamps greater than int64_t anyway - see // AVPacket's pts. - if ((int64_t)timecode < (int64_t)(matroska->skip_to_timecode)) + if ((int64_t)timecode < (int64_t)matroska->skip_to_timecode) return res; if (is_keyframe) matroska->skip_to_keyframe = 0; diff --git a/tests/fate/seek.mak b/tests/fate/seek.mak index b831cf82d9af6..f835da5226ed2 100644 --- a/tests/fate/seek.mak +++ b/tests/fate/seek.mak @@ -247,8 +247,11 @@ FATE_SEEK += $(FATE_SEEK_LAVF-yes:%=fate-seek-lavf-%) FATE_SEEK_EXTRA-$(CONFIG_MP3_DEMUXER) += fate-seek-extra-mp3 FATE_SEEK_EXTRA-$(call ALLYES, CACHE_PROTOCOL PIPE_PROTOCOL MP3_DEMUXER) += fate-seek-cache-pipe +FATE_SEEK_EXTRA-$(CONFIG_MATROSKA_DEMUXER) += fate-seek-mkv-codec-delay fate-seek-extra-mp3: CMD = run libavformat/tests/seek$(EXESUF) $(TARGET_SAMPLES)/gapless/gapless.mp3 -fastseek 1 fate-seek-cache-pipe: CMD = cat $(TARGET_SAMPLES)/gapless/gapless.mp3 | run libavformat/tests/seek$(EXESUF) cache:pipe:0 -read_ahead_limit -1 +fate-seek-mkv-codec-delay: CMD = run libavformat/tests/seek$(EXESUF) $(TARGET_SAMPLES)/mkv/codec_delay_opus.mkv + FATE_SEEK_EXTRA += $(FATE_SEEK_EXTRA-yes) diff --git a/tests/ref/seek/mkv-codec-delay b/tests/ref/seek/mkv-codec-delay new file mode 100644 index 0000000000000..9d4582c139e12 --- /dev/null +++ b/tests/ref/seek/mkv-codec-delay @@ -0,0 +1,48 @@ +ret: 0 st: 0 flags:1 dts:-0.007000 pts:-0.007000 pos: 748 size: 320 +ret: 0 st:-1 flags:0 ts:-1.000000 +ret: 0 st: 0 flags:1 dts:-0.007000 pts:-0.007000 pos: 748 size: 320 +ret: 0 st:-1 flags:1 ts: 1.894167 +ret: 0 st: 0 flags:1 dts: 1.014000 pts: 1.014000 pos: 9306 size: 291 +ret: 0 st: 0 flags:0 ts: 0.788000 +ret: 0 st: 0 flags:1 dts: 0.794000 pts: 0.794000 pos: 7358 size: 154 +ret: 0 st: 0 flags:1 ts:-0.317000 +ret: 0 st: 0 flags:1 dts:-0.007000 pts:-0.007000 pos: 748 size: 320 +ret:-1 st:-1 flags:0 ts: 2.576668 +ret: 0 st:-1 flags:1 ts: 1.470835 +ret: 0 st: 0 flags:1 dts: 1.014000 pts: 1.014000 pos: 9306 size: 291 +ret: 0 st: 0 flags:0 ts: 0.365000 +ret: 0 st: 0 flags:1 dts: 0.374000 pts: 0.374000 pos: 3963 size: 150 +ret: 0 st: 0 flags:1 ts:-0.741000 +ret: 0 st: 0 flags:1 dts:-0.007000 pts:-0.007000 pos: 748 size: 320 +ret:-1 st:-1 flags:0 ts: 2.153336 +ret: 0 st:-1 flags:1 ts: 1.047503 +ret: 0 st: 0 flags:1 dts: 1.014000 pts: 1.014000 pos: 9306 size: 291 +ret: 0 st: 0 flags:0 ts:-0.058000 +ret: 0 st: 0 flags:1 dts:-0.007000 pts:-0.007000 pos: 748 size: 320 +ret: 0 st: 0 flags:1 ts: 2.836000 +ret: 0 st: 0 flags:1 dts: 1.014000 pts: 1.014000 pos: 9306 size: 291 +ret:-1 st:-1 flags:0 ts: 1.730004 +ret: 0 st:-1 flags:1 ts: 0.624171 +ret: 0 st: 0 flags:1 dts: 0.614000 pts: 0.614000 pos: 5903 size: 159 +ret: 0 st: 0 flags:0 ts:-0.482000 +ret: 0 st: 0 flags:1 dts:-0.007000 pts:-0.007000 pos: 748 size: 320 +ret: 0 st: 0 flags:1 ts: 2.413000 +ret: 0 st: 0 flags:1 dts: 1.014000 pts: 1.014000 pos: 9306 size: 291 +ret:-1 st:-1 flags:0 ts: 1.306672 +ret: 0 st:-1 flags:1 ts: 0.200839 +ret: 0 st: 0 flags:1 dts: 0.194000 pts: 0.194000 pos: 2512 size: 159 +ret: 0 st: 0 flags:0 ts:-0.905000 +ret: 0 st: 0 flags:1 dts:-0.007000 pts:-0.007000 pos: 748 size: 320 +ret: 0 st: 0 flags:1 ts: 1.989000 +ret: 0 st: 0 flags:1 dts: 1.014000 pts: 1.014000 pos: 9306 size: 291 +ret: 0 st:-1 flags:0 ts: 0.883340 +ret: 0 st: 0 flags:1 dts: 0.894000 pts: 0.894000 pos: 8154 size: 155 +ret: 0 st:-1 flags:1 ts:-0.222493 +ret: 0 st: 0 flags:1 dts:-0.007000 pts:-0.007000 pos: 748 size: 320 +ret:-1 st: 0 flags:0 ts: 2.672000 +ret: 0 st: 0 flags:1 ts: 1.566000 +ret: 0 st: 0 flags:1 dts: 1.014000 pts: 1.014000 pos: 9306 size: 291 +ret: 0 st:-1 flags:0 ts: 0.460008 +ret: 0 st: 0 flags:1 dts: 0.474000 pts: 0.474000 pos: 4768 size: 153 +ret: 0 st:-1 flags:1 ts:-0.645825 +ret: 0 st: 0 flags:1 dts:-0.007000 pts:-0.007000 pos: 748 size: 320 From 22df70e9edaa8353e5edcc65c660d2d9f19ede5a Mon Sep 17 00:00:00 2001 From: Timothy Gu Date: Fri, 29 Jul 2016 17:18:09 -0700 Subject: [PATCH 64/71] doxygen: Add a note on libavutil's modular nature --- libavutil/avutil.h | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/libavutil/avutil.h b/libavutil/avutil.h index c1f76c16ea815..27e9cf0f67e3e 100644 --- a/libavutil/avutil.h +++ b/libavutil/avutil.h @@ -23,7 +23,8 @@ /** * @file - * external API header + * @ingroup lavu + * Convenience header that includes @ref lavu "libavutil"'s core. */ /** @@ -81,11 +82,14 @@ * @defgroup lavu Common utility functions * * @brief - * libavutil contains the code shared across all the other FFmpeg - * libraries - * - * @note In order to use the functions provided by avutil you must include - * the specific header. + * libavutil contains the code shared across all the other FFmpeg libraries. + * + * @note + * libavutil is designed to be modular. In most cases, in order to use the + * functions provided by one component of libavutil you must explicitly include + * the specific header containing that feature. If you are only using + * media-related components, you could simply include libavutil/avutil.h, which + * brings in most of the "core" components. * * @{ * From f198b8af72eb27171efa057dca883298b9fe5b8c Mon Sep 17 00:00:00 2001 From: Timothy Gu Date: Fri, 29 Jul 2016 17:38:33 -0700 Subject: [PATCH 65/71] doxygen: Fix PREDEFINED syntax --- doc/Doxyfile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/Doxyfile b/doc/Doxyfile index 0c1604e007690..d67e432aca981 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -1355,13 +1355,13 @@ INCLUDE_FILE_PATTERNS = # undefined via #undef or recursively expanded use the := operator # instead of the = operator. -PREDEFINED = "__attribute__(x)=" \ - "DECLARE_ALIGNED(a,t,n)=t n" \ - "offsetof(x,y)=0x42" \ - av_alloc_size \ +PREDEFINED = __attribute__(x)= \ + "DECLARE_ALIGNED(n,t,v)=t v" \ + offsetof(x,y)=0x42 \ + av_alloc_size(...)= \ AV_GCC_VERSION_AT_LEAST(x,y)=1 \ AV_GCC_VERSION_AT_MOST(x,y)=0 \ - __GNUC__=1 \ + __GNUC__ \ # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. From 6253e5676fb1541c5736767d061a035729380852 Mon Sep 17 00:00:00 2001 From: Timothy Gu Date: Fri, 29 Jul 2016 18:56:32 -0700 Subject: [PATCH 66/71] doxygen: Update Doxyfile for Doxygen 1.8.8 --- doc/Doxyfile | 2399 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 1566 insertions(+), 833 deletions(-) diff --git a/doc/Doxyfile b/doc/Doxyfile index d67e432aca981..753c383a26808 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -1,102 +1,129 @@ -# Doxyfile 1.7.1 +# Doxyfile 1.8.8 # This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project +# doxygen (www.doxygen.org) for a project. # -# All text after a hash (#) is considered a comment and will be ignored +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. # The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all -# text before the first occurrence of this tag. Doxygen uses libiconv (or the -# iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. PROJECT_NAME = FFmpeg -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. PROJECT_NUMBER = -# With the PROJECT_LOGO tag one can specify a logo or icon that is included -# in the documentation. The maximum height of the logo should not exceed 55 -# pixels and the maximum width should not exceed 200 pixels. Doxygen will -# copy the logo to the output directory. +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify an logo or icon that is included in +# the documentation. The maximum height of the logo should not exceed 55 pixels +# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo +# to the output directory. + PROJECT_LOGO = -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. OUTPUT_DIRECTORY = doc/doxy -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. CREATE_SUBDIRS = NO +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, -# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English -# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, -# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, -# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. OUTPUT_LANGUAGE = English -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. +# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. BRIEF_MEMBER_DESC = YES -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. +# The default value is: YES. REPEAT_BRIEF = YES -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief +# doxygen will generate a detailed section even if there is only a brief # description. +# The default value is: NO. ALWAYS_DETAILED_SEC = NO @@ -104,153 +131,207 @@ ALWAYS_DETAILED_SEC = NO # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. +# The default value is: NO. INLINE_INHERITED_MEMB = NO -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. +# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. FULL_PATH_NAMES = YES -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = . -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. STRIP_FROM_INC_PATH = -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems -# doesn't support long names like on DOS, Mac, or CD-ROM. +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. SHORT_NAMES = NO -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments -# (thus requiring an explicit @brief command for a brief description.) +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. JAVADOC_AUTOBRIEF = YES -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring -# an explicit \brief command for a brief description.) +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. QT_AUTOBRIEF = NO -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. MULTILINE_CPP_IS_BRIEF = NO -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. INHERIT_DOCS = YES -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a +# new page for each member. If set to NO, the documentation of a member will be +# part of the file/class/namespace that contains it. +# The default value is: NO. SEPARATE_MEMBER_PAGES = NO -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. TAB_SIZE = 8 -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. ALIASES = -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. OPTIMIZE_OUTPUT_FOR_C = YES -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for -# Java. For instance, namespaces will be presented as packages, qualified -# scopes will look different, etc. +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources only. Doxygen will then generate output that is more tailored for -# Fortran. +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for -# VHDL. +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it -# parses. With this tag you can assign which parser to use for a given extension. -# Doxygen has a built-in mapping, but you can override or extend it using this -# tag. The format is ext=language, where ext is a file extension, and language -# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, -# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make -# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C -# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions -# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. EXTENSION_MAPPING = +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by by putting a % sign in front of the word +# or globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also make the inheritance and collaboration +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. +# The default value is: NO. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. +# The default value is: NO. CPP_CLI_SUPPORT = NO -# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. -# Doxygen will parse them like normal C++ but will assume all classes use public -# instead of private inheritance when no explicit protection keyword is present. +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. SIP_SUPPORT = NO -# For Microsoft's IDL there are propget and propput attributes to indicate getter -# and setter methods for a property. Setting this option to YES (the default) -# will make doxygen to replace the get and set methods by a property in the -# documentation. This will only work if the methods are indeed getting or -# setting a simple type. If this is not the case, or you want to show the -# methods anyway, you should set this option to NO. +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. IDL_PROPERTY_SUPPORT = YES @@ -258,371 +339,470 @@ IDL_PROPERTY_SUPPORT = YES # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. +# The default value is: NO. DISTRIBUTE_GROUP_DOC = NO -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. SUBGROUPING = YES -# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum -# is documented as struct, union, or enum with the name of the typedef. So +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically -# be useful for C code in case the coding convention dictates that all compound +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. TYPEDEF_HIDES_STRUCT = YES -# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to -# determine which symbols to keep in memory and which to flush to disk. -# When the cache is full, less often used symbols will be written to disk. -# For small to medium size projects (<1000 input files) the default value is -# probably good enough. For larger projects a too small cache size can cause -# doxygen to be busy swapping symbols to and from disk most of the time -# causing a significant performance penality. -# If the system has enough physical memory increasing the cache will improve the -# performance by keeping more symbols in memory. Note that the value works on -# a logarithmic scale so increasing the size by one will roughly double the -# memory usage. The cache size is given by this formula: -# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols - -SYMBOL_CACHE_SIZE = 0 +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. EXTRACT_ALL = YES -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will +# be included in the documentation. +# The default value is: NO. EXTRACT_PRIVATE = YES -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file will be +# included in the documentation. +# The default value is: NO. EXTRACT_STATIC = YES -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. EXTRACT_LOCAL_CLASSES = YES -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. +# This flag is only useful for Objective-C code. When set to YES local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO only methods in the interface are +# included. +# The default value is: NO. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base -# name of the file that contains the anonymous namespace. By default -# anonymous namespace are hidden. +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. EXTRACT_ANON_NSPACES = NO -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. HIDE_UNDOC_MEMBERS = NO -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO these classes will be included in the various overviews. This option has +# no effect if EXTRACT_ALL is enabled. +# The default value is: NO. HIDE_UNDOC_CLASSES = NO -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO these declarations will be +# included in the documentation. +# The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. HIDE_IN_BODY_DOCS = NO -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. INTERNAL_DOCS = NO -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. +# The default value is: system dependent. CASE_SENSE_NAMES = YES -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES the +# scope will be hidden. +# The default value is: NO. HIDE_SCOPE_NAMES = NO -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. SHOW_INCLUDE_FILES = YES -# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen -# will list include files with double quotes in the documentation -# rather than with sharp brackets. +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. FORCE_LOCAL_INCLUDES = NO -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. INLINE_INFO = YES -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. +# The default value is: YES. SORT_MEMBER_DOCS = NO -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. SORT_BRIEF_DOCS = NO -# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen -# will sort the (brief and detailed) documentation of class members so that -# constructors and destructors are listed first. If set to NO (the default) -# the constructors will appear in the respective orders defined by -# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. -# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO -# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. SORT_MEMBERS_CTORS_1ST = NO -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the -# hierarchy of group names into alphabetical order. If set to NO (the default) -# the group names will appear in their defined order. +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. SORT_GROUP_NAMES = NO -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. SORT_BY_SCOPE_NAME = NO -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the +# todo list. This list is created by putting \todo commands in the +# documentation. +# The default value is: YES. GENERATE_TODOLIST = YES -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. +# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the +# test list. This list is created by putting \test commands in the +# documentation. +# The default value is: YES. GENERATE_TESTLIST = YES -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. +# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. GENERATE_BUGLIST = YES -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. +# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. GENERATE_DEPRECATEDLIST= YES -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. ENABLED_SECTIONS = -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and defines in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. MAX_INITIALIZER_LINES = 30 -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES the list +# will mention the files that were used to generate the documentation. +# The default value is: YES. SHOW_USED_FILES = YES -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. -# This will remove the Files entry from the Quick Index and from the -# Folder Tree View (if specified). The default is YES. +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. SHOW_FILES = YES -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the -# Namespaces page. -# This will remove the Namespaces entry from the Quick Index -# and from the Folder Tree View (if specified). The default is YES. +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the program writes to standard output -# is used as the file version. See the manual for examples. +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated -# output files in an output format independent way. The create the layout file -# that represents doxygen's defaults, run doxygen with the -l option. -# You can optionally specify a file name after the option, if omitted -# DoxygenLayout.xml will be used as the name of the layout file. +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. LAYOUT_FILE = +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + #--------------------------------------------------------------------------- -# configuration options related to warning and progress messages +# Configuration options related to warning and progress messages #--------------------------------------------------------------------------- -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. +# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. WARNINGS = YES -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. +# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. WARN_IF_UNDOCUMENTED = YES -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. WARN_IF_DOC_ERROR = YES -# This WARN_NO_PARAMDOC option can be abled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO doxygen will only warn about wrong or incomplete parameter +# documentation, but not about the absence of documentation. +# The default value is: NO. WARN_NO_PARAMDOC = NO -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). WARN_LOGFILE = #--------------------------------------------------------------------------- -# configuration options related to the input files +# Configuration options related to the input files #--------------------------------------------------------------------------- -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. +# Note: If this tag is empty the current directory is searched. INPUT = # This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is -# also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for -# the list of possible encodings. +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank the +# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, +# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, +# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, +# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, +# *.qsf, *.as and *.js. FILE_PATTERNS = -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. RECURSIVE = YES -# The EXCLUDE tag can be used to specify files and/or directories that should +# The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. EXCLUDE = -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix filesystem feature) are excluded +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded # from the input. +# The default value is: NO. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories -# for example use the pattern */test/* +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* EXCLUDE_PATTERNS = *.git \ *.d @@ -632,677 +812,1108 @@ EXCLUDE_PATTERNS = *.git \ # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* EXCLUDE_SYMBOLS = -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). EXAMPLE_PATH = doc/examples/ # If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. EXAMPLE_PATTERNS = *.c # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. EXAMPLE_RECURSIVE = NO -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. -# If FILTER_PATTERNS is specified, this tag will be -# ignored. +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. -# Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. -# The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER -# is applied to all files. +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). +# INPUT_FILTER ) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. FILTER_SOURCE_FILES = NO +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + #--------------------------------------------------------------------------- -# configuration options related to source browsing +# Configuration options related to source browsing #--------------------------------------------------------------------------- -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. SOURCE_BROWSER = YES -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. INLINE_SOURCES = NO -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. STRIP_CODE_COMMENTS = NO -# If the REFERENCED_BY_RELATION tag is set to YES -# then for each documented function all documented -# functions referencing it will be listed. +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. REFERENCED_BY_RELATION = YES -# If the REFERENCES_RELATION tag is set to YES -# then for each documented function all documented entities -# called/used by that function will be listed. +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. REFERENCES_RELATION = NO -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. -# Otherwise they will link to the documentation. +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES, then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. REFERENCES_LINK_SOURCE = YES -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. VERBATIM_HEADERS = YES +# If the CLANG_ASSISTED_PARSING tag is set to YES, then doxygen will use the +# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the +# cost of reduced performance. This can be particularly helpful with template +# rich C++ code for which doxygen's built-in parser lacks the necessary type +# information. +# Note: The availability of this option depends on whether or not doxygen was +# compiled with the --with-libclang option. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + #--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index +# Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. ALPHABETICAL_INDEX = YES -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. COLS_IN_ALPHA_INDEX = 5 -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = #--------------------------------------------------------------------------- -# configuration options related to the HTML output +# Configuration options related to the HTML output #--------------------------------------------------------------------------- -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. +# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output +# The default value is: YES. GENERATE_HTML = YES -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = html -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a # standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. HTML_STYLESHEET = -# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. -# Doxygen will adjust the colors in the stylesheet and background images -# according to this color. Hue is specified as an angle on a colorwheel, -# see http://en.wikipedia.org/wiki/Hue for more information. -# For instance the value 0 represents red, 60 is yellow, 120 is green, -# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. -# The allowed range is 0 to 359. - -#HTML_COLORSTYLE_HUE = 120 - -# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of -# the colors in the HTML output. For a value of 0 the output will use -# grayscales only. A value of 255 will produce the most vivid colors. +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefor more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra stylesheet files is of importance (e.g. the last +# stylesheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the stylesheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_SAT = 100 -# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to -# the luminance component of the colors in the HTML output. Values below -# 100 gradually make the output lighter, whereas values above 100 make -# the output darker. The value divided by 100 is the actual gamma applied, -# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, -# and 100 does not change the gamma. +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting -# this to NO can help when comparing the output of multiple runs. +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the -# page has loaded. For this to work a browser that supports -# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox -# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_SECTIONS = NO -# If the GENERATE_DOCSET tag is set to YES, additional index files -# will be generated that can be used as input for Apple's Xcode 3 -# integrated development environment, introduced with OS X 10.5 (Leopard). -# To create a documentation set, doxygen will generate a Makefile in the -# HTML output directory. Running make will produce the docset in that -# directory and running "make install" will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find -# it at startup. -# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_DOCSET = NO -# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the -# feed. A documentation feed provides an umbrella under which multiple -# documentation sets from a single provider (such as a company or product suite) -# can be grouped. +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDNAME = "Doxygen generated docs" -# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that -# should uniquely identify the documentation set bundle. This should be a -# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen -# will append .docset to the name. +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_BUNDLE_ID = org.doxygen.Project -# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_ID = org.doxygen.Publisher -# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_NAME = Publisher -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) -# of the generated HTML documentation. +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_HTMLHELP = NO -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be # written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_FILE = -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler ( hhc.exe). If non-empty +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. HHC_LOCATION = -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). +# The GENERATE_CHI flag controls if a separate .chi index file is generated ( +# YES) or that it should be included in the master .chm file ( NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING -# is used to encode HtmlHelp index (hhk), content (hhc) and project file -# content. +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. +# The BINARY_TOC flag controls whether a binary table of contents is generated ( +# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. BINARY_TOC = NO -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and -# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated -# that can be used as input for Qt's qhelpgenerator to generate a -# Qt Compressed Help (.qch) of the generated HTML documentation. +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_QHP = NO -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can -# be used to specify the file name of the resulting .qch file. -# The path specified is relative to the HTML output folder. +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. QCH_FILE = -# The QHP_NAMESPACE tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#namespace +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. QHP_NAMESPACE = org.doxygen.Project -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#virtual-folders +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. QHP_VIRTUAL_FOLDER = doc -# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to -# add. For more information please see -# http://doc.trolltech.com/qthelpproject.html#custom-filters +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = -# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the -# custom filter to add. For more information please see -# -# Qt Help Project / Custom Filters. +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this -# project's -# filter section matches. -# -# Qt Help Project / Filter Attributes. +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = -# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can -# be used to specify the location of Qt's qhelpgenerator. -# If non-empty doxygen will try to run qhelpgenerator on the generated -# .qhp file. +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = -# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files -# will be generated, which together with the HTML files, form an Eclipse help -# plugin. To install this plugin and make it available under the help contents -# menu in Eclipse, the contents of the directory containing the HTML and XML -# files needs to be copied into the plugins directory of eclipse. The name of -# the directory within the plugins directory should be the same as -# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before -# the help appears. +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_ECLIPSEHELP = NO -# A unique identifier for the eclipse help plugin. When installing the plugin -# the directory name containing the HTML and XML files should also have -# this name. +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. ECLIPSE_DOC_ID = org.doxygen.Project -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. DISABLE_INDEX = NO -# This tag can be used to set the number of enum values (range [1..20]) -# that doxygen will group on one line in the generated HTML documentation. - -ENUM_VALUES_PER_LINE = 4 - # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. -# If the tag value is set to YES, a side panel will be generated -# containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). -# Windows users are probably better off using the HTML help feature. +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NO -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. TREEVIEW_WIDTH = 250 -# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open -# links to external symbols imported via tag files in a separate window. +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO -# Use this tag to change the font size of Latex formulas included -# as images in the HTML documentation. The default is 10. Note that -# when you change the font size after a successful doxygen run you need -# to manually remove any form_*.png images from the HTML output directory -# to force them to be regenerated. +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are -# not supported properly for IE 6.0, but are supported on all modern browsers. -# Note that when changing this option you need to delete any form_*.png files -# in the HTML output before the changes have effect. +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_TRANSPARENT = YES -# When the SEARCHENGINE tag is enabled doxygen will generate a search box -# for the HTML output. The underlying search engine uses javascript -# and DHTML and should work on any modern browser. Note that when using -# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets -# (GENERATE_DOCSET) there is already a search function so this one should -# typically be disabled. For large projects the javascript based search engine -# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using prerendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /