Как мне кодировать видео h265 mov с полным цветовым диапазоном 0-255 с помощью vaapi libva - PullRequest
0 голосов
/ 24 декабря 2018

Я делаю аппаратное кодирование h265 в файл контейнера MOV, используя аппаратное ускорение vaapi с помощью libva.У меня есть воспроизводимый видеофайл, но экспортированный диапазон цветов не соответствует входным данным.Чёрные и белые сокрушены, и все игроки сообщают о «цветовой гамме» как «ограниченной» или «ТВ»

Я попытался установить полную цветовую гамму в разных местах в кодеке / формате init снесколько различных способов:

outputStream->codec->color_range = AVCOL_RANGE_JPEG;
codecContext->color_range = AVCOL_RANGE_JPEG;
av_dict_set(&pCodecDictionary, "dst_range", "1", 0);
av_dict_set(&pCodecDictionary, "range", "full", 0);
av_dict_set(&pCodecDictionary, "color_range", "2", 0);
av_opt_set(m_pLIBAVContext->codecContext, "color_range", "2", 0);
av_opt_set(m_pLIBAVContext->codecContext, "range", "full", 0);
av_opt_set_int(m_pLIBAVContext->codecContext,"color_range", 2, 0);
av_opt_set_int(m_pLIBAVContext->codecContext, "dst_range", 1, 0);

, но ни один из них не имеет никакого эффекта

Это полный код настройки кодера vaapi h265 (c ++)

// Register codecs
// Uncomment register all if necessary otherwise remove
avcodec_register_all();
av_register_all();

// Create hardware device context 
LIBAV_CHECK_RETURN(av_hwdevice_ctx_create(&m_pLIBAVContext->hw_device_ctx, AV_HWDEVICE_TYPE_VAAPI, NULL, NULL, 0));

int ret;
std::string filename = pTargetMedia->Url() + std::string("/") + pGalleryItem->Name();
if ((ret = avformat_alloc_output_context2(&m_pLIBAVContext->ofmt_ctx, NULL, "mov", nullptr)) < 0) {
    J3AssertMsg(false, "Failed to allocate output context");
    //return ret;
}

// Find the codec
if (!(m_pLIBAVContext->codec = avcodec_find_encoder_by_name(CodecName))) {
    J3AssertMsg(false,"LIBAV Error: Could not find encoder");
}

m_pLIBAVContext->outputStream = avformat_new_stream(m_pLIBAVContext->ofmt_ctx, m_pLIBAVContext->codec);
if (!m_pLIBAVContext->outputStream) {
    J3AssertMsg(false, "Failed to allocate output stream\n");
}

m_pLIBAVContext->outputStream->time_base.den = FRAME_RATE;
m_pLIBAVContext->outputStream->time_base.num = 1;
m_pLIBAVContext->outputStream->avg_frame_rate.den = FRAME_RATE;
m_pLIBAVContext->outputStream->avg_frame_rate.num = 1;

// Allocate Codec context
m_pLIBAVContext->codecContext = m_pLIBAVContext->outputStream->codec;

// Setup codec context
// Hacky override the fourcc for hevc so quicktime plays it!
char fourcc[] = "hvc1";
m_pLIBAVContext->outputStream->codec->codec_tag = (fourcc[3] << 24) + (fourcc[2] << 16) + (fourcc[1] << 8) + fourcc[0];

m_pLIBAVContext->outputStream->codec->color_range = AVCOL_RANGE_JPEG;
m_pLIBAVContext->outputStream->codec->colorspace = AVColorSpace::AVCOL_SPC_UNSPECIFIED;
m_pLIBAVContext->outputStream->codec->color_primaries = AVColorPrimaries::AVCOL_PRI_UNSPECIFIED;
m_pLIBAVContext->outputStream->codec->color_trc = AVColorTransferCharacteristic::AVCOL_TRC_UNSPECIFIED;

//m_pLIBAVContext->codecContext->codec_id = m_pLIBAVContext->ofmt_ctx->oformat->video_codec;
m_pLIBAVContext->ofmt_ctx->oformat->video_codec = m_pLIBAVContext->codecContext->codec_id;

m_pLIBAVContext->codecContext->width = ImageDimensions.X();
m_pLIBAVContext->codecContext->height = ImageDimensions.Y();
m_pLIBAVContext->codecContext->time_base.den = FRAME_RATE;
m_pLIBAVContext->codecContext->time_base.num = 1;   
m_pLIBAVContext->codecContext->framerate = (AVRational) { FRAME_RATE, 1 };
m_pLIBAVContext->codecContext->sample_aspect_ratio = (AVRational) { 1, 1 };
m_pLIBAVContext->codecContext->bit_rate = 50000000;//100000000; // 100megabit
m_pLIBAVContext->codecContext->gop_size = 0;
m_pLIBAVContext->codecContext->max_b_frames = 1;

m_pLIBAVContext->codecContext->color_range = AVCOL_RANGE_JPEG;
m_pLIBAVContext->codecContext->colorspace = AVColorSpace::AVCOL_SPC_UNSPECIFIED;
m_pLIBAVContext->codecContext->color_primaries = AVColorPrimaries::AVCOL_PRI_UNSPECIFIED;
m_pLIBAVContext->codecContext->color_trc = AVColorTransferCharacteristic::AVCOL_TRC_UNSPECIFIED;

m_pLIBAVContext->codecContext->pix_fmt = AV_PIX_FMT_VAAPI;

if (m_pLIBAVContext->ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
    m_pLIBAVContext->codecContext->flags |= CODEC_FLAG_GLOBAL_HEADER;

av_opt_set(m_pLIBAVContext->codecContext, "preset", "ultrafast", 0);
av_opt_set(m_pLIBAVContext->codecContext, "color_range", "2", 0);

av_opt_set(m_pLIBAVContext->codecContext, "range", "full", 0);
av_opt_set_int(m_pLIBAVContext->codecContext, "color_range", 2, 0);
av_opt_set_int(m_pLIBAVContext->codecContext, "dst_range", 1, 0);

// set hw_frames_ctx for encoder's AVCodecContext
if ( set_hwframe_ctx(m_pLIBAVContext->codecContext, m_pLIBAVContext->hw_device_ctx, ImageDimensions.X(), ImageDimensions.Y()) != 0) {
    J3AssertMsg(false,"LIBAV Error: Failed to set hwframe context.\n");
}

// Open video encoder codec
av_opt_set_int(m_pLIBAVContext->codecContext, "video_full_range_flag", 2, 0);
AVDictionary* pCodecDictionary = NULL;
av_dict_set(&pCodecDictionary, "dst_range", "1", 0);
av_dict_set(&pCodecDictionary, "range", "full", 0);
av_dict_set(&pCodecDictionary, "color_range", "2", 0);
LIBAV_CHECK_RETURN(avcodec_open2(m_pLIBAVContext->codecContext, m_pLIBAVContext->codec, &pCodecDictionary));
av_dict_free(&pCodecDictionary);

av_opt_set(m_pLIBAVContext->codecContext, "range", "full", 0);
av_opt_set_int(m_pLIBAVContext->codecContext, "color_range", 2, 0);
av_opt_set_int(m_pLIBAVContext->codecContext, "video_full_range_flag", 2, 0);

// Setup software frame
// Data will be copied here before being uploaded to gpu
// TODO: avoid the double copy in Enqueue()
// Memset the colour channels to zero for monochrome image
J3Assert(m_pLIBAVContext->sw_frame == nullptr);
m_pLIBAVContext->sw_frame = av_frame_alloc();
J3AssertMsg(m_pLIBAVContext->sw_frame, "Failed to allocated software avframe");
m_pLIBAVContext->sw_frame->width = ImageDimensions.X();
m_pLIBAVContext->sw_frame->height = ImageDimensions.Y();
m_pLIBAVContext->sw_frame->format = AV_PIX_FMT_NV12;
av_frame_set_color_range(m_pLIBAVContext->sw_frame, AVCOL_RANGE_JPEG);

m_pLIBAVContext->sw_frame->color_range = AVCOL_RANGE_JPEG;

const u32 FrameBufferAlignment = 32;
LIBAV_CHECK_RETURN(av_frame_get_buffer(m_pLIBAVContext->sw_frame, FrameBufferAlignment));
const u32 ChromaDataSizeBytes = (ImageDimensions.X() * ImageDimensions.Y()) / 2;
memset(m_pLIBAVContext->sw_frame->data[1], 128, ChromaDataSizeBytes);

// Setup hardware frame
J3Assert(m_pLIBAVContext->hw_frame == nullptr);
m_pLIBAVContext->hw_frame = av_frame_alloc();
av_frame_set_color_range(m_pLIBAVContext->hw_frame, AVCOL_RANGE_JPEG);
av_frame_set_colorspace(m_pLIBAVContext->hw_frame, AVColorSpace::AVCOL_SPC_BT709);
J3AssertMsg(m_pLIBAVContext->hw_frame, "Failed to allocated hardware avframe");
LIBAV_CHECK_RETURN(av_hwframe_get_buffer(m_pLIBAVContext->codecContext->hw_frames_ctx, m_pLIBAVContext->hw_frame, 0));
J3AssertMsg(m_pLIBAVContext->hw_frame->hw_frames_ctx, "Failed to allocate hardware frame");

// Open the target file
av_opt_set_int(m_pLIBAVContext->codecContext, "video_full_range_flag", 2, 0);

if (!(m_pLIBAVContext->ofmt_ctx->oformat->flags & AVFMT_NOFILE)) {
    if ((ret = avio_open(&m_pLIBAVContext->ofmt_ctx->pb, filename.c_str(), AVIO_FLAG_WRITE)) < 0) {
        J3AssertMsg(false, "Could not open output file '%s'", filename);
    }
}

if ((ret = avformat_write_header(m_pLIBAVContext->ofmt_ctx, NULL)) < 0) {
    J3AssertMsg(false, "Error occurred when opening output file\n");
}

Есть ли некоторыескрытый способ пометить цветовую гамму как 0-255 вместо 16-235?

...