710 lines · 23.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 <va/va.h>#include <va/va_enc_mpeg2.h> #include "libavutil/avassert.h" #include "avcodec.h"#include "cbs.h"#include "cbs_mpeg2.h"#include "mpeg12.h"#include "vaapi_encode.h" typedef struct VAAPIEncodeMPEG2Context {    VAAPIEncodeContext common;     // User options.    int profile;    int level;     // Derived settings.    int quant_i;    int quant_p;    int quant_b;     unsigned int bit_rate;    unsigned int vbv_buffer_size;     AVRational frame_rate;     unsigned int f_code_horizontal;    unsigned int f_code_vertical;     // Stream state.    int64_t last_i_frame;     // Writer structures.    MPEG2RawSequenceHeader sequence_header;    MPEG2RawExtensionData  sequence_extension;    MPEG2RawExtensionData  sequence_display_extension;    MPEG2RawGroupOfPicturesHeader gop_header;    MPEG2RawPictureHeader  picture_header;    MPEG2RawExtensionData  picture_coding_extension;     CodedBitstreamContext *cbc;    CodedBitstreamFragment current_fragment;} VAAPIEncodeMPEG2Context;  static int vaapi_encode_mpeg2_write_fragment(AVCodecContext *avctx,                                             char *data, size_t *data_len,                                             CodedBitstreamFragment *frag){    VAAPIEncodeMPEG2Context *priv = avctx->priv_data;    int err;     err = ff_cbs_write_fragment_data(priv->cbc, frag);    if (err < 0) {        av_log(avctx, AV_LOG_ERROR, "Failed to write packed header.\n");        return err;    }     if (*data_len < 8 * frag->data_size - frag->data_bit_padding) {        av_log(avctx, AV_LOG_ERROR, "Access unit too large: "               "%zu < %zu.\n", *data_len,               8 * frag->data_size - frag->data_bit_padding);        return AVERROR(ENOSPC);    }     memcpy(data, frag->data, frag->data_size);    *data_len = 8 * frag->data_size - frag->data_bit_padding;     return 0;} static int vaapi_encode_mpeg2_add_header(AVCodecContext *avctx,                                         CodedBitstreamFragment *frag,                                         int type, void *header){    int err;     err = ff_cbs_insert_unit_content(frag, -1, type, header, NULL);    if (err < 0) {        av_log(avctx, AV_LOG_ERROR, "Failed to add header: "               "type = %d.\n", type);        return err;    }     return 0;} static int vaapi_encode_mpeg2_write_sequence_header(AVCodecContext *avctx,                                                    char *data, size_t *data_len){    VAAPIEncodeMPEG2Context *priv = avctx->priv_data;    CodedBitstreamFragment  *frag = &priv->current_fragment;    int err;     err = vaapi_encode_mpeg2_add_header(avctx, frag, MPEG2_START_SEQUENCE_HEADER,                                        &priv->sequence_header);    if (err < 0)        goto fail;     err = vaapi_encode_mpeg2_add_header(avctx, frag, MPEG2_START_EXTENSION,                                        &priv->sequence_extension);    if (err < 0)        goto fail;     err = vaapi_encode_mpeg2_add_header(avctx, frag, MPEG2_START_EXTENSION,                                        &priv->sequence_display_extension);    if (err < 0)        goto fail;     err = vaapi_encode_mpeg2_add_header(avctx, frag, MPEG2_START_GROUP,                                        &priv->gop_header);    if (err < 0)        goto fail;     err = vaapi_encode_mpeg2_write_fragment(avctx, data, data_len, frag);fail:    ff_cbs_fragment_reset(frag);    return 0;} static int vaapi_encode_mpeg2_write_picture_header(AVCodecContext *avctx,                                                   VAAPIEncodePicture *pic,                                                   char *data, size_t *data_len){    VAAPIEncodeMPEG2Context *priv = avctx->priv_data;    CodedBitstreamFragment  *frag = &priv->current_fragment;    int err;     err = vaapi_encode_mpeg2_add_header(avctx, frag, MPEG2_START_PICTURE,                                        &priv->picture_header);    if (err < 0)        goto fail;     err = vaapi_encode_mpeg2_add_header(avctx, frag, MPEG2_START_EXTENSION,                                        &priv->picture_coding_extension);    if (err < 0)        goto fail;     err = vaapi_encode_mpeg2_write_fragment(avctx, data, data_len, frag);fail:    ff_cbs_fragment_reset(frag);    return 0;} static int vaapi_encode_mpeg2_init_sequence_params(AVCodecContext *avctx){    VAAPIEncodeContext                 *ctx = avctx->priv_data;    VAAPIEncodeMPEG2Context           *priv = avctx->priv_data;    MPEG2RawSequenceHeader              *sh = &priv->sequence_header;    MPEG2RawSequenceExtension           *se = &priv->sequence_extension.data.sequence;    MPEG2RawSequenceDisplayExtension   *sde = &priv->sequence_display_extension.data.sequence_display;    MPEG2RawGroupOfPicturesHeader     *goph = &priv->gop_header;    MPEG2RawPictureHeader               *ph = &priv->picture_header;    MPEG2RawPictureCodingExtension     *pce = &priv->picture_coding_extension.data.picture_coding;    VAEncSequenceParameterBufferMPEG2 *vseq = ctx->codec_sequence_params;    VAEncPictureParameterBufferMPEG2  *vpic = ctx->codec_picture_params;    int code, ext_n, ext_d;     memset(sh,   0, sizeof(*sh));    memset(se,   0, sizeof(*se));    memset(sde,  0, sizeof(*sde));    memset(goph, 0, sizeof(*goph));    memset(ph,   0, sizeof(*ph));    memset(pce,  0, sizeof(*pce));      if (ctx->va_bit_rate > 0) {        priv->bit_rate = (ctx->va_bit_rate + 399) / 400;    } else {        // Unknown (not a bitrate-targetting mode), so just use the        // highest value.        priv->bit_rate = 0x3fffffff;    }    if (avctx->rc_buffer_size > 0) {        priv->vbv_buffer_size = (avctx->rc_buffer_size + (1 << 14) - 1) >> 14;    } else {        // Unknown, so guess a value from the bitrate.        priv->vbv_buffer_size = priv->bit_rate >> 14;    }     switch (avctx->level) {    case 4: // High.    case 6: // High 1440.        priv->f_code_horizontal = 9;        priv->f_code_vertical   = 5;        break;    case 8: // Main.        priv->f_code_horizontal = 8;        priv->f_code_vertical   = 5;        break;    case 10: // Low.    default:        priv->f_code_horizontal = 7;        priv->f_code_vertical   = 4;        break;    }      // Sequence header     sh->sequence_header_code = MPEG2_START_SEQUENCE_HEADER;     sh->horizontal_size_value = avctx->width  & 0xfff;    sh->vertical_size_value   = avctx->height & 0xfff;     if (avctx->sample_aspect_ratio.num != 0 &&        avctx->sample_aspect_ratio.den != 0) {        AVRational dar = av_div_q(avctx->sample_aspect_ratio,                                  (AVRational) { avctx->width, avctx->height });         if (av_cmp_q(avctx->sample_aspect_ratio, (AVRational) { 1, 1 }) == 0) {            sh->aspect_ratio_information = 1;        } else if (av_cmp_q(dar, (AVRational) { 3, 4 }) == 0) {            sh->aspect_ratio_information = 2;        } else if (av_cmp_q(dar, (AVRational) { 9, 16 }) == 0) {            sh->aspect_ratio_information = 3;        } else if (av_cmp_q(dar, (AVRational) { 100, 221 }) == 0) {            sh->aspect_ratio_information = 4;        } else {            av_log(avctx, AV_LOG_WARNING, "Sample aspect ratio %d:%d is not "                   "representable, signalling square pixels instead.\n",                   avctx->sample_aspect_ratio.num,                   avctx->sample_aspect_ratio.den);            sh->aspect_ratio_information = 1;        }    } else {        // Unknown - assume square pixels.        sh->aspect_ratio_information = 1;    }     if (avctx->framerate.num > 0 && avctx->framerate.den > 0)        priv->frame_rate = avctx->framerate;    else        priv->frame_rate = av_inv_q(avctx->time_base);    ff_mpeg12_find_best_frame_rate(priv->frame_rate,                                   &code, &ext_n, &ext_d, 0);    sh->frame_rate_code = code;     sh->bit_rate_value        = priv->bit_rate & 0x3ffff;    sh->vbv_buffer_size_value = priv->vbv_buffer_size & 0x3ff;     sh->constrained_parameters_flag     = 0;    sh->load_intra_quantiser_matrix     = 0;    sh->load_non_intra_quantiser_matrix = 0;      // Sequence extension     priv->sequence_extension.extension_start_code = MPEG2_START_EXTENSION;    priv->sequence_extension.extension_start_code_identifier =        MPEG2_EXTENSION_SEQUENCE;     se->profile_and_level_indication = avctx->profile << 4 | avctx->level;    se->progressive_sequence = 1;    se->chroma_format        = 1;     se->horizontal_size_extension = avctx->width  >> 12;    se->vertical_size_extension   = avctx->height >> 12;     se->bit_rate_extension        = priv->bit_rate >> 18;    se->vbv_buffer_size_extension = priv->vbv_buffer_size >> 10;    se->low_delay                 = ctx->b_per_p == 0;     se->frame_rate_extension_n = ext_n;    se->frame_rate_extension_d = ext_d;      // Sequence display extension     priv->sequence_display_extension.extension_start_code =        MPEG2_START_EXTENSION;    priv->sequence_display_extension.extension_start_code_identifier =        MPEG2_EXTENSION_SEQUENCE_DISPLAY;     // Unspecified video format, from table 6-6.    sde->video_format = 5;     sde->colour_primaries         = avctx->color_primaries;    sde->transfer_characteristics = avctx->color_trc;    sde->matrix_coefficients      = avctx->colorspace;    sde->colour_description       =        avctx->color_primaries != AVCOL_PRI_UNSPECIFIED ||        avctx->color_trc       != AVCOL_TRC_UNSPECIFIED ||        avctx->colorspace      != AVCOL_SPC_UNSPECIFIED;     sde->display_horizontal_size = avctx->width;    sde->display_vertical_size   = avctx->height;      // GOP header     goph->group_start_code = MPEG2_START_GROUP;     // Marker bit in the middle of time_code.    goph->time_code   = 1 << 12;    goph->closed_gop  = 1;    goph->broken_link = 0;      // Defaults for picture header     ph->picture_start_code = MPEG2_START_PICTURE;     ph->vbv_delay = 0xffff; // Not currently calculated.     ph->full_pel_forward_vector  = 0;    ph->forward_f_code           = 7;    ph->full_pel_backward_vector = 0;    ph->forward_f_code           = 7;      // Defaults for picture coding extension     priv->picture_coding_extension.extension_start_code =        MPEG2_START_EXTENSION;    priv->picture_coding_extension.extension_start_code_identifier =        MPEG2_EXTENSION_PICTURE_CODING;     pce->intra_dc_precision         = 0;    pce->picture_structure          = 3;    pce->top_field_first            = 0;    pce->frame_pred_frame_dct       = 1;    pce->concealment_motion_vectors = 0;    pce->q_scale_type               = 0;    pce->intra_vlc_format           = 0;    pce->alternate_scan             = 0;    pce->repeat_first_field         = 0;    pce->progressive_frame          = 1;    pce->composite_display_flag     = 0;       *vseq = (VAEncSequenceParameterBufferMPEG2) {        .intra_period = ctx->gop_size,        .ip_period    = ctx->b_per_p + 1,         .picture_width  = avctx->width,        .picture_height = avctx->height,         .bits_per_second          = ctx->va_bit_rate,        .frame_rate               = av_q2d(priv->frame_rate),        .aspect_ratio_information = sh->aspect_ratio_information,        .vbv_buffer_size          = priv->vbv_buffer_size,         .sequence_extension.bits = {            .profile_and_level_indication = se->profile_and_level_indication,            .progressive_sequence         = se->progressive_sequence,            .chroma_format                = se->chroma_format,            .low_delay                    = se->low_delay,            .frame_rate_extension_n       = se->frame_rate_extension_n,            .frame_rate_extension_d       = se->frame_rate_extension_d,        },         .new_gop_header = 1,        .gop_header.bits = {            .time_code   = goph->time_code,            .closed_gop  = goph->closed_gop,            .broken_link = goph->broken_link,        },    };     *vpic = (VAEncPictureParameterBufferMPEG2) {        .forward_reference_picture  = VA_INVALID_ID,        .backward_reference_picture = VA_INVALID_ID,        .reconstructed_picture      = VA_INVALID_ID,        .coded_buf                  = VA_INVALID_ID,         .vbv_delay = 0xffff,        .f_code    = { { 15, 15 }, { 15, 15 } },         .picture_coding_extension.bits = {            .intra_dc_precision         = pce->intra_dc_precision,            .picture_structure          = pce->picture_structure,            .top_field_first            = pce->top_field_first,            .frame_pred_frame_dct       = pce->frame_pred_frame_dct,            .concealment_motion_vectors = pce->concealment_motion_vectors,            .q_scale_type               = pce->q_scale_type,            .intra_vlc_format           = pce->intra_vlc_format,            .alternate_scan             = pce->alternate_scan,            .repeat_first_field         = pce->repeat_first_field,            .progressive_frame          = pce->progressive_frame,            .composite_display_flag     = pce->composite_display_flag,        },         .composite_display.bits = {            .v_axis            = pce->v_axis,            .field_sequence    = pce->field_sequence,            .sub_carrier       = pce->sub_carrier,            .burst_amplitude   = pce->burst_amplitude,            .sub_carrier_phase = pce->sub_carrier_phase,        },    };     return 0;} static int vaapi_encode_mpeg2_init_picture_params(AVCodecContext *avctx,                                                 VAAPIEncodePicture *pic){    VAAPIEncodeMPEG2Context          *priv = avctx->priv_data;    MPEG2RawPictureHeader              *ph = &priv->picture_header;    MPEG2RawPictureCodingExtension    *pce = &priv->picture_coding_extension.data.picture_coding;    VAEncPictureParameterBufferMPEG2 *vpic = pic->codec_picture_params;     if (pic->type == PICTURE_TYPE_IDR || pic->type == PICTURE_TYPE_I) {        ph->temporal_reference  = 0;        ph->picture_coding_type = 1;        priv->last_i_frame = pic->display_order;    } else {        ph->temporal_reference = pic->display_order - priv->last_i_frame;        ph->picture_coding_type = pic->type == PICTURE_TYPE_B ? 3 : 2;    }     if (pic->type == PICTURE_TYPE_P || pic->type == PICTURE_TYPE_B) {        pce->f_code[0][0] = priv->f_code_horizontal;        pce->f_code[0][1] = priv->f_code_vertical;    } else {        pce->f_code[0][0] = 15;        pce->f_code[0][1] = 15;    }    if (pic->type == PICTURE_TYPE_B) {        pce->f_code[1][0] = priv->f_code_horizontal;        pce->f_code[1][1] = priv->f_code_vertical;    } else {        pce->f_code[1][0] = 15;        pce->f_code[1][1] = 15;    }     vpic->reconstructed_picture = pic->recon_surface;    vpic->coded_buf             = pic->output_buffer;     switch (pic->type) {    case PICTURE_TYPE_IDR:    case PICTURE_TYPE_I:        vpic->picture_type = VAEncPictureTypeIntra;        break;    case PICTURE_TYPE_P:        vpic->picture_type = VAEncPictureTypePredictive;        vpic->forward_reference_picture = pic->refs[0]->recon_surface;        break;    case PICTURE_TYPE_B:        vpic->picture_type = VAEncPictureTypeBidirectional;        vpic->forward_reference_picture  = pic->refs[0]->recon_surface;        vpic->backward_reference_picture = pic->refs[1]->recon_surface;        break;    default:        av_assert0(0 && "invalid picture type");    }     vpic->temporal_reference = ph->temporal_reference;    vpic->f_code[0][0]       = pce->f_code[0][0];    vpic->f_code[0][1]       = pce->f_code[0][1];    vpic->f_code[1][0]       = pce->f_code[1][0];    vpic->f_code[1][1]       = pce->f_code[1][1];     return 0;} static int vaapi_encode_mpeg2_init_slice_params(AVCodecContext *avctx,                                               VAAPIEncodePicture *pic,                                               VAAPIEncodeSlice *slice){    VAAPIEncodeMPEG2Context            *priv = avctx->priv_data;    VAEncSliceParameterBufferMPEG2   *vslice = slice->codec_slice_params;    int qp;     vslice->macroblock_address = slice->block_start;    vslice->num_macroblocks    = slice->block_size;     switch (pic->type) {    case PICTURE_TYPE_IDR:    case PICTURE_TYPE_I:        qp = priv->quant_i;        break;    case PICTURE_TYPE_P:        qp = priv->quant_p;        break;    case PICTURE_TYPE_B:        qp = priv->quant_b;        break;

Lines 1–500 of 710.

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