如何编码1个图像并使用ffmpeg h264_nvenc接收它
How to encode 1 image and receive it using ffmpeg h264_nvenc
我正试图使用ffmpeg和编码器h264_nvenc创建屏幕的实时流,但在平移时,我的鼠标移动和鼠标移动之间有5-6帧延迟(前5-6帧为黑色(
我需要以某种方式使用h264_nvenc对我的屏幕的1个图像进行编码,并将其作为有效帧(包(接收,或者可能将延迟减少到1-2帧
也许还有一些其他方法可以立即获得图像
UPD:我意识到我的延迟是因为编码器和解码器的帧延迟,所以有什么方法可以完全消除这种帧延迟吗?(增加了解码器初始化功能和解码功能(
我已经做了一些测试,并设法用解码器和编码器冲洗方法立即接收图像,但第二次无法做到这一点
编码功能:
static void encode(AVCodecContext* enc_ctx, AVFrame* frame, AVPacket* pkt, AVPacket** new_packet)
{
int ret;
ret = avcodec_send_frame(enc_ctx, frame);
if (ret < 0) {
fprintf(stderr, "Error sending a frame for encodingn");
exit(1);
}
int size = 0;
while (ret >= 0) {
ret = avcodec_receive_packet(enc_ctx, pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
{
//printf("count: %i size: %in", count, size);
return;
}
else if (ret < 0) {
fprintf(stderr, "Error during encodingn");
exit(1);
}
size += pkt->size;
*new_packet = av_packet_clone(pkt);
av_packet_unref(pkt);
}
}
FFMpeg编码器初始化:
void InitializeFFmpegEncoder()
{
const AVCodec* codec;
int i, ret, x, y;
FILE* f;
// Encoder
codec = avcodec_find_encoder_by_name("h264_nvenc"); // hevc_nvenc h264_nvenc
if (!codec) {
fprintf(stderr, "Codec '%s' not foundn", "hevc");
exit(1);
}
/*codec = avcodec_find_encoder(AV_CODEC_ID_H265);
if (!codec) {
fprintf(stderr, "Codec '%s' not foundn", "hevc");
exit(1);
}*/
cout << "Encoder codec name: " << codec->name << endl;
cout << "1" << endl;
enc_c = avcodec_alloc_context3(codec);
if (!enc_c) {
fprintf(stderr, "Could not allocate video codec contextn");
exit(1);
}
cout << "2" << endl;
pkt = av_packet_alloc();
if (!pkt)
exit(1);
cout << "3" << endl;
/* put sample parameters */
enc_c->bit_rate = 192000000;
/* resolution must be a multiple of two */
enc_c->width = 1920;
enc_c->height = 1080;
/* frames per second */
enc_c->time_base = AVRational(1, 1);
//enc_c->framerate = AVRational(60, 1);
/* emit one intra frame every ten frames
* check frame pict_type before passing frame
* to encoder, if frame->pict_type is AV_PICTURE_TYPE_I
* then gop_size is ignored and the output of encoder
* will always be I frame irrespective to gop_size
*/
enc_c->gop_size = 1;
enc_c->max_b_frames = 0;
enc_c->pix_fmt = AV_PIX_FMT_BGR0;
enc_c->keyint_min = 0;
if (codec->id == AV_CODEC_ID_H264)
{
//av_opt_set(enc_c->priv_data, "preset", "p1", 0);
//av_opt_set(enc_c->priv_data, "tune", "ull", 0);
//av_opt_set(enc_c->priv_data, "zerolatency", "1", 0);
//av_opt_set(enc_c->priv_data, "preset", "p1", 0);
//av_opt_set(enc_c->priv_data, "tune", "ull", 0);
//av_opt_set(enc_c->priv_data, "strict_gop", "1", 0);
//av_opt_set(enc_c->priv_data, "preset", "lossless", 0);
//av_opt_set(enc_c->priv_data, "zerolatency", "1", 0);
}
cout << "4" << endl;
/* open it */
ret = avcodec_open2(enc_c, codec, NULL);
if (ret < 0) {
printf("Could not open codec: %sn", av_make_error_string((char[64])(0), 64, ret));
exit(1);
}
cout << "5" << endl;
frame = av_frame_alloc();
if (!frame) {
fprintf(stderr, "Could not allocate video framen");
exit(1);
}
frame->format = AV_PIX_FMT_BGR0; // AV_PIX_FMT_YUV444P AV_PIX_FMT_ARGB
frame->width = enc_c->width;
frame->height = enc_c->height;
cout << "6" << endl;
ret = av_frame_get_buffer(frame, 0);
if (ret < 0) {
fprintf(stderr, "Could not allocate the video frame datan");
exit(1);
}
cout << "7" << endl;
}
解码器初始化功能:
int InitializeFFmpegDecoder()
{
int ret;
const AVCodec* decoder = NULL;
enum AVHWDeviceType type;
int i;
decoder = avcodec_find_decoder_by_name("h264_cuvid"); // h264_cuvid hevc_cuvid
if (!decoder) {
fprintf(stderr, "Codec not foundn");
exit(1);
}
cout << "Decoder name: " << decoder->name << endl;
if (!(decoder_ctx = avcodec_alloc_context3(decoder)))
return AVERROR(ENOMEM);
decoder_ctx->get_format = ffmpeg_GetFormat;
decoder_ctx->gop_size = 0;
decoder_ctx->max_b_frames = 0;
decoder_ctx->keyint_min = 0;
decoder_ctx->flags |= AV_CODEC_FLAG_LOW_DELAY;
//decoder_ctx->get_format = get_format;
if ((ret = avcodec_open2(decoder_ctx, decoder, NULL)) < 0) {
fprintf(stderr, "Failed to open codec for stream n");
return -1;
}
if (ctx == NULL)
{
ctx = sws_getContext(1920, 1080,
AV_PIX_FMT_NV12, 1920, 1080, // AV_PIX_FMT_YUV420P AV_PIX_FMT_NV12
AV_PIX_FMT_BGR0, 0, 0, 0, 0);
}
}
解码功能:
static void decode(AVCodecContext* dec_ctx, AVFrame* frame, AVPacket* pkt, char* bgra_image)
{
int ret;
ret = avcodec_send_packet(dec_ctx, pkt);
if (ret < 0) {
fprintf(stderr, "Error sending a packet for decodingn");
exit(1);
}
while (ret >= 0) {
ret = avcodec_receive_frame(dec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return;
else if (ret < 0) {
fprintf(stderr, "Error during decodingn");
exit(1);
}
char* outData[1] = { bgra_image }; // RGB24 have one plane
int outLinesize[1] = { 4 * 1920 }; // RGB stride
sws_scale(ctx, frame->data, frame->linesize, 0, 1080, (uint8_t* const*)outData, outLinesize);
//*new_frame = av_frame_clone(frame);
//av_frame_ref()
//break;
}
}
您可以为解码器检查av_seek_frame(av_format_ctx, video_stream_index, timestamp, AVSEEK_FLAG_BACKWARD)
。转到要编码的帧,然后对该帧进行编码。
对单个帧进行编码的工作方式与查找要查找的帧后的循环中的工作方式相同,请注意av_seek查找iFrames。
对于h264_nvenc,将选项delay
设置为0
但是对于解码器h264_cuvid
,我不知道如何制作0延迟流,所以我切换到DXVA2并将max_b_frames
设置为0
相关文章:
- FFmpeg:制作一个应用程序比直接使用ffmepg更好吗
- 使用FFMPEG将RGB图像序列保存到.mp4时出现问题
- FFMPEG配置文件级别id大小无效
- FFMpeg库:如何在音频文件中精确查找
- OpenCV RTP-Stream with FFMPEG
- FFMPEG H264对每个图像进行编码
- ffmpeg H264一次对帧进行编码,用于网络流传输
- 使用 FFMPEG 将每个输入图像转换为 H264 编译时出错,该图像在 MevisLab 中运行的 Visual St
- 寻求使用 FFmpeg 在 mp4 容器中 h264 编解码器的视频帧.数据包 pts 始终为 0
- 将标准的Android H264软件编码器替换为基于ffmpeg的编码器
- 使用 ffmpeg 和分离的 AVCodecContext 解码 h264 rtsp
- H264 编码视频流 FFMPEG C++
- 使用libx264将FFMPEG RTSP流转换为MPEG4/H264文件
- 用ffmpeg解码h264流引入延迟,如何避免
- ffmpeg::avcodec_encode_video setting PTS h264
- 如何使用ffmpeg直接将H264原始流写入mp4
- libvlc ffmpeg:在mpegts h264流中没有搜索
- Ffmpeg:如何保存h264原始数据为mp4文件
- h264 ffmpeg:如何初始化ffmpeg来解码用x264创建的nal
- FFmpeg c++ api解码h264错误