1324 lines · 47.6 KB · C
RawDownload
/* * 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 <string.h> #include <va/va.h>#include <va/va_enc_hevc.h> #include "libavutil/avassert.h"#include "libavutil/common.h"#include "libavutil/pixdesc.h"#include "libavutil/opt.h"#include "libavutil/mastering_display_metadata.h" #include "avcodec.h"#include "cbs.h"#include "cbs_h265.h"#include "h265_profile_level.h"#include "hevc.h"#include "hevc_sei.h"#include "internal.h"#include "put_bits.h"#include "vaapi_encode.h" enum {    SEI_MASTERING_DISPLAY       = 0x08,    SEI_CONTENT_LIGHT_LEVEL     = 0x10,}; typedef struct VAAPIEncodeH265Picture {    int pic_order_cnt;     int64_t last_idr_frame;     int slice_nal_unit;    int slice_type;    int pic_type;} VAAPIEncodeH265Picture; typedef struct VAAPIEncodeH265Context {    VAAPIEncodeContext common;     // User options.    int qp;    int aud;    int profile;    int tier;    int level;    int sei;     // Derived settings.    int fixed_qp_idr;    int fixed_qp_p;    int fixed_qp_b;     // Writer structures.    H265RawAUD   raw_aud;    H265RawVPS   raw_vps;    H265RawSPS   raw_sps;    H265RawPPS   raw_pps;    H265RawSlice raw_slice;     SEIRawMasteringDisplayColourVolume sei_mastering_display;    SEIRawContentLightLevelInfo        sei_content_light_level;     CodedBitstreamContext *cbc;    CodedBitstreamFragment current_access_unit;    int aud_needed;    int sei_needed;} VAAPIEncodeH265Context;  static int vaapi_encode_h265_write_access_unit(AVCodecContext *avctx,                                               char *data, size_t *data_len,                                               CodedBitstreamFragment *au){    VAAPIEncodeH265Context *priv = avctx->priv_data;    int err;     err = ff_cbs_write_fragment_data(priv->cbc, au);    if (err < 0) {        av_log(avctx, AV_LOG_ERROR, "Failed to write packed header.\n");        return err;    }     if (*data_len < 8 * au->data_size - au->data_bit_padding) {        av_log(avctx, AV_LOG_ERROR, "Access unit too large: "               "%zu < %zu.\n", *data_len,               8 * au->data_size - au->data_bit_padding);        return AVERROR(ENOSPC);    }     memcpy(data, au->data, au->data_size);    *data_len = 8 * au->data_size - au->data_bit_padding;     return 0;} static int vaapi_encode_h265_add_nal(AVCodecContext *avctx,                                     CodedBitstreamFragment *au,                                     void *nal_unit){    H265RawNALUnitHeader *header = nal_unit;    int err;     err = ff_cbs_insert_unit_content(au, -1,                                     header->nal_unit_type, nal_unit, NULL);    if (err < 0) {        av_log(avctx, AV_LOG_ERROR, "Failed to add NAL unit: "               "type = %d.\n", header->nal_unit_type);        return err;    }     return 0;} static int vaapi_encode_h265_write_sequence_header(AVCodecContext *avctx,                                                   char *data, size_t *data_len){    VAAPIEncodeH265Context *priv = avctx->priv_data;    CodedBitstreamFragment   *au = &priv->current_access_unit;    int err;     if (priv->aud_needed) {        err = vaapi_encode_h265_add_nal(avctx, au, &priv->raw_aud);        if (err < 0)            goto fail;        priv->aud_needed = 0;    }     err = vaapi_encode_h265_add_nal(avctx, au, &priv->raw_vps);    if (err < 0)        goto fail;     err = vaapi_encode_h265_add_nal(avctx, au, &priv->raw_sps);    if (err < 0)        goto fail;     err = vaapi_encode_h265_add_nal(avctx, au, &priv->raw_pps);    if (err < 0)        goto fail;     err = vaapi_encode_h265_write_access_unit(avctx, data, data_len, au);fail:    ff_cbs_fragment_reset(au);    return err;} static int vaapi_encode_h265_write_slice_header(AVCodecContext *avctx,                                                VAAPIEncodePicture *pic,                                                VAAPIEncodeSlice *slice,                                                char *data, size_t *data_len){    VAAPIEncodeH265Context *priv = avctx->priv_data;    CodedBitstreamFragment   *au = &priv->current_access_unit;    int err;     if (priv->aud_needed) {        err = vaapi_encode_h265_add_nal(avctx, au, &priv->raw_aud);        if (err < 0)            goto fail;        priv->aud_needed = 0;    }     err = vaapi_encode_h265_add_nal(avctx, au, &priv->raw_slice);    if (err < 0)        goto fail;     err = vaapi_encode_h265_write_access_unit(avctx, data, data_len, au);fail:    ff_cbs_fragment_reset(au);    return err;} static int vaapi_encode_h265_write_extra_header(AVCodecContext *avctx,                                                VAAPIEncodePicture *pic,                                                int index, int *type,                                                char *data, size_t *data_len){    VAAPIEncodeH265Context *priv = avctx->priv_data;    CodedBitstreamFragment   *au = &priv->current_access_unit;    int err;     if (priv->sei_needed) {        if (priv->aud_needed) {            err = vaapi_encode_h265_add_nal(avctx, au, &priv->aud);            if (err < 0)                goto fail;            priv->aud_needed = 0;        }         if (priv->sei_needed & SEI_MASTERING_DISPLAY) {            err = ff_cbs_sei_add_message(priv->cbc, au, 1,                                         SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME,                                         &priv->sei_mastering_display, NULL);            if (err < 0)                goto fail;        }         if (priv->sei_needed & SEI_CONTENT_LIGHT_LEVEL) {            err = ff_cbs_sei_add_message(priv->cbc, au, 1,                                         SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO,                                         &priv->sei_content_light_level, NULL);            if (err < 0)                goto fail;        }         priv->sei_needed = 0;         err = vaapi_encode_h265_write_access_unit(avctx, data, data_len, au);        if (err < 0)            goto fail;         ff_cbs_fragment_reset(au);         *type = VAEncPackedHeaderRawData;        return 0;    } else {        return AVERROR_EOF;    } fail:    ff_cbs_fragment_reset(au);    return err;} static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx){    VAAPIEncodeContext                *ctx = avctx->priv_data;    VAAPIEncodeH265Context           *priv = avctx->priv_data;    H265RawVPS                        *vps = &priv->raw_vps;    H265RawSPS                        *sps = &priv->raw_sps;    H265RawPPS                        *pps = &priv->raw_pps;    H265RawProfileTierLevel           *ptl = &vps->profile_tier_level;    H265RawVUI                        *vui = &sps->vui;    VAEncSequenceParameterBufferHEVC *vseq = ctx->codec_sequence_params;    VAEncPictureParameterBufferHEVC  *vpic = ctx->codec_picture_params;    const AVPixFmtDescriptor *desc;    int chroma_format, bit_depth;    int i;     memset(vps, 0, sizeof(*vps));    memset(sps, 0, sizeof(*sps));    memset(pps, 0, sizeof(*pps));      desc = av_pix_fmt_desc_get(priv->common.input_frames->sw_format);    av_assert0(desc);    if (desc->nb_components == 1) {        chroma_format = 0;    } else {        if (desc->log2_chroma_w == 1 && desc->log2_chroma_h == 1) {            chroma_format = 1;        } else if (desc->log2_chroma_w == 1 && desc->log2_chroma_h == 0) {            chroma_format = 2;        } else if (desc->log2_chroma_w == 0 && desc->log2_chroma_h == 0) {            chroma_format = 3;        } else {            av_log(avctx, AV_LOG_ERROR, "Chroma format of input pixel format "                   "%s is not supported.\n", desc->name);            return AVERROR(EINVAL);        }    }    bit_depth = desc->comp[0].depth;      // VPS     vps->nal_unit_header = (H265RawNALUnitHeader) {        .nal_unit_type         = HEVC_NAL_VPS,        .nuh_layer_id          = 0,        .nuh_temporal_id_plus1 = 1,    };     vps->vps_video_parameter_set_id = 0;     vps->vps_base_layer_internal_flag  = 1;    vps->vps_base_layer_available_flag = 1;    vps->vps_max_layers_minus1         = 0;    vps->vps_max_sub_layers_minus1     = 0;    vps->vps_temporal_id_nesting_flag  = 1;     ptl->general_profile_space = 0;    ptl->general_profile_idc   = avctx->profile;    ptl->general_tier_flag     = priv->tier;     if (chroma_format == 1) {        ptl->general_profile_compatibility_flag[1] = bit_depth ==  8;        ptl->general_profile_compatibility_flag[2] = bit_depth <= 10;    }    ptl->general_profile_compatibility_flag[4] = 1;     ptl->general_progressive_source_flag    = 1;    ptl->general_interlaced_source_flag     = 0;    ptl->general_non_packed_constraint_flag = 1;    ptl->general_frame_only_constraint_flag = 1;     ptl->general_max_12bit_constraint_flag = bit_depth <= 12;    ptl->general_max_10bit_constraint_flag = bit_depth <= 10;    ptl->general_max_8bit_constraint_flag  = bit_depth ==  8;     ptl->general_max_422chroma_constraint_flag  = chroma_format <= 2;    ptl->general_max_420chroma_constraint_flag  = chroma_format <= 1;    ptl->general_max_monochrome_constraint_flag = chroma_format == 0;     ptl->general_intra_constraint_flag = ctx->gop_size == 1;     ptl->general_lower_bit_rate_constraint_flag = 1;     if (avctx->level != FF_LEVEL_UNKNOWN) {        ptl->general_level_idc = avctx->level;    } else {        const H265LevelDescriptor *level;         level = ff_h265_guess_level(ptl, avctx->bit_rate,                                    ctx->surface_width, ctx->surface_height,                                    ctx->nb_slices, ctx->tile_rows, ctx->tile_cols,                                    (ctx->b_per_p > 0) + 1);        if (level) {            av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name);            ptl->general_level_idc = level->level_idc;        } else {            av_log(avctx, AV_LOG_VERBOSE, "Stream will not conform to "                   "any normal level; using level 8.5.\n");            ptl->general_level_idc = 255;            // The tier flag must be set in level 8.5.            ptl->general_tier_flag = 1;        }    }     vps->vps_sub_layer_ordering_info_present_flag = 0;    vps->vps_max_dec_pic_buffering_minus1[0]      = ctx->max_b_depth + 1;    vps->vps_max_num_reorder_pics[0]              = ctx->max_b_depth;    vps->vps_max_latency_increase_plus1[0]        = 0;     vps->vps_max_layer_id             = 0;    vps->vps_num_layer_sets_minus1    = 0;    vps->layer_id_included_flag[0][0] = 1;     vps->vps_timing_info_present_flag = 1;    if (avctx->framerate.num > 0 && avctx->framerate.den > 0) {        vps->vps_num_units_in_tick  = avctx->framerate.den;        vps->vps_time_scale         = avctx->framerate.num;        vps->vps_poc_proportional_to_timing_flag = 1;        vps->vps_num_ticks_poc_diff_one_minus1   = 0;    } else {        vps->vps_num_units_in_tick  = avctx->time_base.num;        vps->vps_time_scale         = avctx->time_base.den;        vps->vps_poc_proportional_to_timing_flag = 0;    }    vps->vps_num_hrd_parameters = 0;      // SPS     sps->nal_unit_header = (H265RawNALUnitHeader) {        .nal_unit_type         = HEVC_NAL_SPS,        .nuh_layer_id          = 0,        .nuh_temporal_id_plus1 = 1,    };     sps->sps_video_parameter_set_id = vps->vps_video_parameter_set_id;     sps->sps_max_sub_layers_minus1    = vps->vps_max_sub_layers_minus1;    sps->sps_temporal_id_nesting_flag = vps->vps_temporal_id_nesting_flag;     sps->profile_tier_level = vps->profile_tier_level;     sps->sps_seq_parameter_set_id = 0;     sps->chroma_format_idc          = chroma_format;    sps->separate_colour_plane_flag = 0;     sps->pic_width_in_luma_samples  = ctx->surface_width;    sps->pic_height_in_luma_samples = ctx->surface_height;     if (avctx->width  != ctx->surface_width ||        avctx->height != ctx->surface_height) {        sps->conformance_window_flag = 1;        sps->conf_win_left_offset   = 0;        sps->conf_win_right_offset  =            (ctx->surface_width - avctx->width) >> desc->log2_chroma_w;        sps->conf_win_top_offset    = 0;        sps->conf_win_bottom_offset =            (ctx->surface_height - avctx->height) >> desc->log2_chroma_h;    } else {        sps->conformance_window_flag = 0;    }     sps->bit_depth_luma_minus8   = bit_depth - 8;    sps->bit_depth_chroma_minus8 = bit_depth - 8;     sps->log2_max_pic_order_cnt_lsb_minus4 = 8;     sps->sps_sub_layer_ordering_info_present_flag =        vps->vps_sub_layer_ordering_info_present_flag;    for (i = 0; i <= sps->sps_max_sub_layers_minus1; i++) {        sps->sps_max_dec_pic_buffering_minus1[i] =            vps->vps_max_dec_pic_buffering_minus1[i];        sps->sps_max_num_reorder_pics[i] =            vps->vps_max_num_reorder_pics[i];        sps->sps_max_latency_increase_plus1[i] =            vps->vps_max_latency_increase_plus1[i];    }     // These have to come from the capabilities of the encoder.  We have no    // way to query them, so just hardcode parameters which work on the Intel    // driver.    // CTB size from 8x8 to 32x32.    sps->log2_min_luma_coding_block_size_minus3   = 0;    sps->log2_diff_max_min_luma_coding_block_size = 2;    // Transform size from 4x4 to 32x32.    sps->log2_min_luma_transform_block_size_minus2   = 0;    sps->log2_diff_max_min_luma_transform_block_size = 3;    // Full transform hierarchy allowed (2-5).    sps->max_transform_hierarchy_depth_inter = 3;    sps->max_transform_hierarchy_depth_intra = 3;    // AMP works.    sps->amp_enabled_flag = 1;    // SAO and temporal MVP do not work.    sps->sample_adaptive_offset_enabled_flag = 0;    sps->sps_temporal_mvp_enabled_flag       = 0;     sps->pcm_enabled_flag = 0;     // STRPSs should ideally be here rather than defined individually in    // each slice, but the structure isn't completely fixed so for now    // don't bother.    sps->num_short_term_ref_pic_sets     = 0;    sps->long_term_ref_pics_present_flag = 0;     sps->vui_parameters_present_flag = 1;     if (avctx->sample_aspect_ratio.num != 0 &&        avctx->sample_aspect_ratio.den != 0) {        static const AVRational sar_idc[] = {            {   0,  0 },            {   1,  1 }, {  12, 11 }, {  10, 11 }, {  16, 11 },            {  40, 33 }, {  24, 11 }, {  20, 11 }, {  32, 11 },            {  80, 33 }, {  18, 11 }, {  15, 11 }, {  64, 33 },            { 160, 99 }, {   4,  3 }, {   3,  2 }, {   2,  1 },        };        int num, den, i;        av_reduce(&num, &den, avctx->sample_aspect_ratio.num,                  avctx->sample_aspect_ratio.den, 65535);        for (i = 0; i < FF_ARRAY_ELEMS(sar_idc); i++) {            if (num == sar_idc[i].num &&                den == sar_idc[i].den) {                vui->aspect_ratio_idc = i;                break;            }        }        if (i >= FF_ARRAY_ELEMS(sar_idc)) {            vui->aspect_ratio_idc = 255;            vui->sar_width  = num;            vui->sar_height = den;        }        vui->aspect_ratio_info_present_flag = 1;    }     // Unspecified video format, from table E-2.    vui->video_format             = 5;    vui->video_full_range_flag    =        avctx->color_range == AVCOL_RANGE_JPEG;    vui->colour_primaries         = avctx->color_primaries;    vui->transfer_characteristics = avctx->color_trc;    vui->matrix_coefficients      = avctx->colorspace;    if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED ||        avctx->color_trc       != AVCOL_TRC_UNSPECIFIED ||        avctx->colorspace      != AVCOL_SPC_UNSPECIFIED)        vui->colour_description_present_flag = 1;    if (avctx->color_range     != AVCOL_RANGE_UNSPECIFIED ||        vui->colour_description_present_flag)        vui->video_signal_type_present_flag = 1;     if (avctx->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED) {        vui->chroma_loc_info_present_flag = 1;        vui->chroma_sample_loc_type_top_field    =        vui->chroma_sample_loc_type_bottom_field =            avctx->chroma_sample_location - 1;    }     vui->vui_timing_info_present_flag        = 1;    vui->vui_num_units_in_tick               = vps->vps_num_units_in_tick;    vui->vui_time_scale                      = vps->vps_time_scale;

Lines 1–500 of 1324.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t