FFmpeg解码H264视频流局部花屏解决方法

在项目中使用到了FFmpeg实现屏幕广播技术,其物理拓扑图如下:
在这里插入图片描述
由于我们的场景是在局域网中,因此基于FFmpeg的udp协议进行播放;当视频流是从windows 10 系统播出时,部分接收端存在局部花屏现象现象;

为了验证花屏问题,我们提出两种解决方案:

  • 控制播放源的发送数据大小

  • 增加接收缓存区,避免丢包

方法一:

我们把播放源的计算机网络环境从自动监测设置为100M双工时,接收端花屏现象就不存在了;但这个极大浪费了当前的网络带宽,非优选方案

方法二:

通过查询资料,1920*1080高分辨率情况下,FFmpeg发送的数据会比较大,超过了FFmpeg默认最大值,需要扩大接收端的接收缓冲区,其方法修改方法如下:

在FFmpeg的源码中,找到udp.c文件并修改UDP_MAX_PKT_SIZE 默认值
在这里插入图片描述
在同等条件下,发现接收端已经不存在局部花屏现象,此方案为最优

参考资料:

https://blog.csdn.net/sz76211822/article/details/87797475

以下是使用FFmpeg解码H.264视频流的示例代码: ``` #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <fcntl.h> #include <sys/time.h> #include <sys/types.h> #include <sys/stat.h> extern "C" { #include <libavcodec/avcodec.h> } int main(int argc, char **argv) { AVCodec *codec = NULL; AVCodecContext *codec_ctx = NULL; AVFrame *frame = NULL; AVPacket packet; int ret, i, video_stream_index; int got_frame = 0; int frame_count = 0; int video_width, video_height; struct timeval start_time, end_time; if (argc < 2) { printf("Usage: %s <input_file>\n", argv[0]); return -1; } avcodec_register_all(); // 打开文件并读取视频流信息 AVFormatContext *format_ctx = NULL; if (avformat_open_input(&format_ctx, argv[1], NULL, NULL) != 0) { printf("Couldn't open input file\n"); return -1; } if (avformat_find_stream_info(format_ctx, NULL) < 0) { printf("Couldn't find stream information\n"); return -1; } // 查找视频流,并初始化解码器 for (i = 0; i < format_ctx->nb_streams; i++) { if (format_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { video_stream_index = i; codec_ctx = avcodec_alloc_context3(codec); avcodec_parameters_to_context(codec_ctx, format_ctx->streams[i]->codecpar); codec = avcodec_find_decoder(codec_ctx->codec_id); if (!codec) { printf("Unsupported codec\n"); return -1; } if (avcodec_open2(codec_ctx, codec, NULL) < 0) { printf("Could not open codec\n"); return -1; } video_width = codec_ctx->width; video_height = codec_ctx->height; break; } } // 初始化AVFrame并分配内存 frame = av_frame_alloc(); if (!frame) { printf("Could not allocate frame\n"); return -1; } gettimeofday(&start_time, NULL); // 读取视频流解码 while (av_read_frame(format_ctx, &packet) >= 0) { if (packet.stream_index == video_stream_index) { ret = avcodec_decode_video2(codec_ctx, frame, &got_frame, &packet); if (ret < 0) { printf("Error decoding video frame\n"); return -1; } if (got_frame) { printf("Decoded frame %d\n", frame_count++); // 在这里可以处理解码后的帧,例如渲染到屏幕上 } } av_packet_unref(&packet); } gettimeofday(&end_time, NULL); double elapsed_time = (end_time.tv_sec - start_time.tv_sec) + (end_time.tv_usec - start_time.tv_usec) / 1000000.0; printf("Decoded %d frames in %f seconds (average fps: %f)\n", frame_count, elapsed_time, frame_count / elapsed_time); avcodec_free_context(&codec_ctx); avformat_close_input(&format_ctx); av_frame_free(&frame); return 0; } ``` 这段代码打开指定文件并读取视频流信息,查找视频流并初始化解码器,然后循环读取视频流解码每个视频帧。在解码每个帧后,您可以将其渲染到屏幕上或进行其他处理。最后,它将打印解码帧的数量和解码时间,然后释放所有资源。 请注意,为了简化代码,这个示例忽略了错误处理和内存释放。在实际应用中,您需要确保正确地处理和释放所有资源,以避免内存泄漏和其他问题。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值