gpt4 book ai didi

ffmpeg - FFMPEG libavcodec 解码然后重新编码视频问题

转载 作者:行者123 更新时间:2023-12-04 23:04:49 29 4
gpt4 key购买 nike

我正在尝试使用 FFMpeg 中的 libavcodec 库来解码然后重新编码 h264 视频。

我有解码部分工作(很好地渲染到一个 SDL 窗口)但是当我尝试重新编码帧时,我在重新编码的视频样本中得到了错误的数据。

这是我的编码逻辑的精简代码片段。

EncodeResponse H264Codec::EncodeFrame(AVFrame* pFrame, StreamCodecContainer* pStreamCodecContainer, AVPacket* pPacket)
{
int result = 0;

result = avcodec_send_frame(pStreamCodecContainer->pEncodingCodecContext, pFrame);

if(result < 0)
{
return EncodeResponse::Fail;
}

while (result >= 0)
{
result = avcodec_receive_packet(pStreamCodecContainer->pEncodingCodecContext, pPacket);

// If the encoder needs more frames to create a packed then return and wait for
// method to be called again upon a new frame been present.
// Else check if we have failed to encode for some reason.
// Else a packet has successfully been returned, then write it to the file.
if (result == AVERROR(EAGAIN) || result == AVERROR_EOF)
{
// Higher level logic, dedcodes next frame from source
// video then calls this method again.
return EncodeResponse::SendNextFrame;
}
else if (result < 0)
{
return EncodeResponse::Fail;
}
else
{
// Prepare packet for muxing.
if (pStreamCodecContainer->codecType == AVMEDIA_TYPE_VIDEO)
{
av_packet_rescale_ts(m_pPacket, pStreamCodecContainer->pEncodingCodecContext->time_base,
m_pDecodingFormatContext->streams[pStreamCodecContainer->streamIndex]->time_base);
}

m_pPacket->stream_index = pStreamCodecContainer->streamIndex;

int result = av_interleaved_write_frame(m_pEncodingFormatContext, m_pPacket);

av_packet_unref(m_pPacket);
}
}

return EncodeResponse::EncoderEndOfFile;
}

我注意到的奇怪行为是,在我从 avcodec_receive_packet 获得第一个数据包之前,我必须向 avcodec_send_frame 发送 50+ 帧。

我构建了 FFMpeg 的调试版本并单步执行代码,我注意到 avcodec_receive_packet 返回了 AVERROR(EAGAIN),因为在 encoder.c 中的 x264encoder::encode 中存在以下内容
    if( h->frames.i_input <= h->frames.i_delay + 1 - h->i_thread_frames )
{
/* Nothing yet to encode, waiting for filling of buffers */
pic_out->i_type = X264_TYPE_AUTO;
return 0;
}

出于某种原因,我的代码上下文 (h) 从来没有任何框架。我花了很长时间尝试调试 ffmpeg 并确定我做错了什么。但是已经达到了我的视频编解码知识的极限(很少)。

我正在使用没有音频的视频进行测试,以减少复杂性。

我已经创建了我的应用程序的精简版本并提供了一个自包含(带有 ffmpeg 和 SDL 构建的依赖项)项目。希望这可以帮助任何愿意帮助我的人:)。

项目链接
https://github.com/maxhap/video-codec

在查看编码器初始化后,我发现我必须在调用 avcodec_open2 之前设置编解码器 AV_CODEC_FLAG_GLOBAL_HEADER
pStreamCodecContainer->pEncodingCodecContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

这种变化导致重新编码的 moov 框看起来更加不正常(使用 MP4Box.js 来解析它)。但是,视频仍然无法正常播放,输出视频在 VLC 中播放时开始有灰框,在其他播放器中无法播放。

从那以后,我尝试通过示例代码创建编码上下文,而不是使用我的解码编解码器参数。这导致修复了错误/数据或编码问题。但是,我的 DTS 时间正在扩大

这是我的新编解码器初始化
if (pStreamCodecContainer->codecType == AVMEDIA_TYPE_VIDEO) 
{
pStreamCodecContainer->pEncodingCodecContext->height = pStreamCodecContainer->pDecodingCodecContext->height;
pStreamCodecContainer->pEncodingCodecContext->width = pStreamCodecContainer->pDecodingCodecContext->width;
pStreamCodecContainer->pEncodingCodecContext->sample_aspect_ratio = pStreamCodecContainer->pDecodingCodecContext->sample_aspect_ratio;

/* take first format from list of supported formats */
if (pStreamCodecContainer->pEncodingCodec->pix_fmts)
{
pStreamCodecContainer->pEncodingCodecContext->pix_fmt = pStreamCodecContainer->pEncodingCodec->pix_fmts[0];
}
else
{
pStreamCodecContainer->pEncodingCodecContext->pix_fmt = pStreamCodecContainer->pDecodingCodecContext->pix_fmt;
}

/* video time_base can be set to whatever is handy and supported by encoder */
pStreamCodecContainer->pEncodingCodecContext->time_base = av_inv_q(pStreamCodecContainer->pDecodingCodecContext->framerate);
pStreamCodecContainer->pEncodingCodecContext->sample_aspect_ratio = pStreamCodecContainer->pDecodingCodecContext->sample_aspect_ratio;
}
else
{
pStreamCodecContainer->pEncodingCodecContext->channel_layout = pStreamCodecContainer->pDecodingCodecContext->channel_layout;
pStreamCodecContainer->pEncodingCodecContext->channels =
av_get_channel_layout_nb_channels(pStreamCodecContainer->pEncodingCodecContext->channel_layout);

/* take first format from list of supported formats */
pStreamCodecContainer->pEncodingCodecContext->sample_fmt = pStreamCodecContainer->pEncodingCodec->sample_fmts[0];
pStreamCodecContainer->pEncodingCodecContext->time_base = AVRational{ 1, pStreamCodecContainer->pEncodingCodecContext->sample_rate };
}

任何想法为什么我的 DTS 时间重新调整不正确?

我设法通过直接从解码流中使用 time_base 值来修复 DTS 缩放。

所以
pStreamCodecContainer->pEncodingCodecContext->time_base = m_pDecodingFormatContext->streams[pStreamCodecContainer->streamIndex]->time_base

代替
pStreamCodecContainer->pEncodingCodecContext->time_base = av_inv_q(pStreamCodecContainer->pDecodingCodecContext->framerate);

我将根据我的所有发现创建一个答案。

最佳答案

为了修复损坏的 moov 框的初始问题,我必须添加 AV_CODEC_FLAG_GLOBAL_HEADER在调用 avcodec_open2 之前标记到编码编解码器上下文。

encCodecContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

下一个问题是编码包中严重缩放的 DTS 值,这导致了最终 mp4 持续时间长达数百小时的副作用。为了解决这个问题,我必须将编码编解码器上下文时基更改为解码上下文流时基。这与使用 av_inv_q(framerate) 不同。正如 avcodec 转码示例中所建议的那样。
encCodecContext->time_base = decCodecFormatContext->streams[streamIndex]->time_base;

关于ffmpeg - FFMPEG libavcodec 解码然后重新编码视频问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53127434/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com