1/* 2 * This file is part of FFmpeg. 3 * 4 * FFmpeg is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * FFmpeg is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with FFmpeg; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19#include <inttypes.h> 20 21#include "libavutil/log.h" 22 23#include "bsf.h" 24#include "bsf_internal.h" 25#include "cbs.h" 26#include "cbs_bsf.h" 27#include "cbs_h264.h" 28#include "codec_id.h" 29#include "h264.h" 30#include "packet.h" 31 32#define NEW_GLOBAL_PIC_INIT_QP 26 33 34typedef struct H264RedundantPPSContext { 35 CBSBSFContext common; 36} H264RedundantPPSContext; 37 38 39static int h264_redundant_pps_fixup_pps(H264RedundantPPSContext *ctx, 40 CodedBitstreamUnit *unit) 41{ 42 H264RawPPS *pps; 43 int err; 44 45 // The changes we are about to perform affect the parsing process, 46 // so we must make sure that the PPS is writable, otherwise the 47 // parsing of future slices will be incorrect and even raise errors. 48 err = ff_cbs_make_unit_writable(ctx->common.input, unit); 49 if (err < 0) 50 return err; 51 pps = unit->content; 52 53 // Overwrite pic_init_qp with the global value. 54 pps->pic_init_qp_minus26 = NEW_GLOBAL_PIC_INIT_QP - 26; 55 56 // Some PPSs have this set, so it must be set in all of them. 57 // (Slices which do not use such a PPS on input will still have 58 // *_weight_l*flag as zero and therefore write equivalently.) 59 pps->weighted_pred_flag = 1; 60 61 return 0; 62} 63 64static int h264_redundant_pps_fixup_slice(H264RedundantPPSContext *ctx, 65 H264RawSliceHeader *slice) 66{ 67 const CodedBitstreamH264Context *const in = ctx->common.input->priv_data; 68 const H264RawPPS *const pps = in->pps[slice->pic_parameter_set_id]; 69 70 // We modified the PPS's qp value, now offset this by applying 71 // the negative offset to the slices. 72 slice->slice_qp_delta += pps->pic_init_qp_minus26 73 - (NEW_GLOBAL_PIC_INIT_QP - 26); 74 75 return 0; 76} 77 78static int h264_redundant_pps_update_fragment(AVBSFContext *bsf, 79 AVPacket *pkt, 80 CodedBitstreamFragment *au) 81{ 82 H264RedundantPPSContext *ctx = bsf->priv_data; 83 int au_has_sps; 84 int err, i; 85 86 au_has_sps = 0; 87 for (i = 0; i < au->nb_units; i++) { 88 CodedBitstreamUnit *nal = &au->units[i]; 89 90 if (nal->type == H264_NAL_SPS) 91 au_has_sps = 1; 92 if (nal->type == H264_NAL_PPS) { 93 err = h264_redundant_pps_fixup_pps(ctx, nal); 94 if (err < 0) 95 return err; 96 if (!au_has_sps) { 97 av_log(bsf, AV_LOG_VERBOSE, "Deleting redundant PPS " 98 "at %"PRId64".\n", pkt->pts); 99 ff_cbs_delete_unit(au, i); 100 i--; 101 continue; 102 } 103 } 104 if (nal->type == H264_NAL_SLICE || 105 nal->type == H264_NAL_IDR_SLICE) { 106 H264RawSlice *slice = nal->content; 107 h264_redundant_pps_fixup_slice(ctx, &slice->header); 108 } 109 } 110 111 return 0; 112} 113 114static const CBSBSFType h264_redundant_pps_type = { 115 .codec_id = AV_CODEC_ID_H264, 116 .fragment_name = "access unit", 117 .unit_name = "NAL unit", 118 .update_fragment = &h264_redundant_pps_update_fragment, 119}; 120 121static int h264_redundant_pps_init(AVBSFContext *bsf) 122{ 123 return ff_cbs_bsf_generic_init(bsf, &h264_redundant_pps_type); 124} 125 126static const enum AVCodecID h264_redundant_pps_codec_ids[] = { 127 AV_CODEC_ID_H264, AV_CODEC_ID_NONE, 128}; 129 130const FFBitStreamFilter ff_h264_redundant_pps_bsf = { 131 .p.name = "h264_redundant_pps", 132 .p.codec_ids = h264_redundant_pps_codec_ids, 133 .priv_data_size = sizeof(H264RedundantPPSContext), 134 .init = &h264_redundant_pps_init, 135 .close = &ff_cbs_bsf_generic_close, 136 .filter = &ff_cbs_bsf_generic_filter, 137}; 138