Rk3588 FFmpeg 拉流 RTSP, 硬解码转RGB
时间: 2025-05-27 09:18:59 浏览: 48
在RK3588平台上使用FFmpeg拉取RTSP流并进行硬解码转为RGB,可以通过以下步骤实现。以下是详细的解决方案和代码示例。
### 解决方案
1. **安装FFmpeg**:确保你的RK3588设备上已经安装了支持硬件加速的FFmpeg版本,并且编译时启用了`librockchip_vpu`或其他相关的硬件加速库。
2. **拉取RTSP流**:使用FFmpeg的API来打开RTSP流。
3. **硬解码**:利用FFmpeg的硬件加速功能(如Rockchip VPU)对视频流进行解码。
4. **转换为RGB**:将解码后的YUV格式帧转换为RGB格式。
以下是完整的C代码实现:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
int main(int argc, char *argv[]) {
const char *rtsp_url = "rtsp://your_rtsp_stream_url";
AVFormatContext *fmt_ctx = NULL;
AVCodecContext *dec_ctx = NULL;
AVStream *video_stream = NULL;
AVPacket packet;
AVFrame *frame = NULL, *rgb_frame = NULL;
struct SwsContext *sws_ctx = NULL;
// 初始化FFmpeg
av_register_all();
avformat_network_init();
// 打开RTSP流
if (avformat_open_input(&fmt_ctx, rtsp_url, NULL, NULL) != 0) {
fprintf(stderr, "无法打开RTSP流\n");
return -1;
}
// 获取流信息
if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
fprintf(stderr, "无法获取流信息\n");
return -1;
}
// 查找视频流
int video_stream_idx = -1;
for (int i = 0; i < fmt_ctx->nb_streams; i++) {
if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
video_stream_idx = i;
break;
}
}
if (video_stream_idx == -1) {
fprintf(stderr, "未找到视频流\n");
return -1;
}
video_stream = fmt_ctx->streams[video_stream_idx];
// 查找解码器
AVCodec *codec = avcodec_find_decoder(video_stream->codecpar->codec_id);
if (!codec) {
fprintf(stderr, "未找到解码器\n");
return -1;
}
// 打开解码器
dec_ctx = avcodec_alloc_context3(codec);
if (avcodec_parameters_to_context(dec_ctx, video_stream->codecpar) < 0) {
fprintf(stderr, "无法复制解码器参数\n");
return -1;
}
if (avcodec_open2(dec_ctx, codec, NULL) < 0) {
fprintf(stderr, "无法打开解码器\n");
return -1;
}
// 初始化SwsContext用于颜色空间转换
frame = av_frame_alloc();
rgb_frame = av_frame_alloc();
uint8_t *rgb_buffer = (uint8_t *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_RGB24, dec_ctx->width, dec_ctx->height, 1));
av_image_fill_arrays(rgb_frame->data, rgb_frame->linesize, rgb_buffer, AV_PIX_FMT_RGB24, dec_ctx->width, dec_ctx->height, 1);
sws_ctx = sws_getContext(dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt,
dec_ctx->width, dec_ctx->height, AV_PIX_FMT_RGB24,
SWS_BILINEAR, NULL, NULL, NULL);
// 读取数据包并解码
while (av_read_frame(fmt_ctx, &packet) >= 0) {
if (packet.stream_index == video_stream_idx) {
int ret = avcodec_send_packet(dec_ctx, &packet);
if (ret < 0) {
fprintf(stderr, "无法发送数据包到解码器\n");
continue;
}
while (ret >= 0) {
ret = avcodec_receive_frame(dec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
break;
else if (ret < 0) {
fprintf(stderr, "无法接收解码帧\n");
break;
}
// 转换为RGB
sws_scale(sws_ctx, (const uint8_t *const *)frame->data, frame->linesize,
0, dec_ctx->height, rgb_frame->data, rgb_frame->linesize);
// 处理RGB帧(例如保存到文件或显示)
printf("成功转换一帧为RGB\n");
}
}
av_packet_unref(&packet);
}
// 清理资源
sws_freeContext(sws_ctx);
av_frame_free(&frame);
av_frame_free(&rgb_frame);
avcodec_free_context(&dec_ctx);
avformat_close_input(&fmt_ctx);
return 0;
}
```
### 代码解释
1. **初始化FFmpeg**:
- 使用`av_register_all()`注册所有可用的格式和编解码器。
- 使用`avformat_network_init()`初始化网络模块以支持RTSP协议。
2. **打开RTSP流**:
- 使用`avformat_open_input()`打开指定的RTSP URL。
- 使用`avformat_find_stream_info()`获取流的详细信息。
3. **查找视频流**:
- 遍历所有流,找到第一个视频流。
4. **解码器设置**:
- 使用`avcodec_find_decoder()`查找与视频流匹配的解码器。
- 使用`avcodec_open2()`打开解码器。
5. **颜色空间转换**:
- 使用`sws_getContext()`创建一个上下文,用于将解码后的YUV帧转换为RGB。
- 使用`sws_scale()`执行实际的颜色空间转换。
6. **循环读取和解码**:
- 使用`av_read_frame()`从RTSP流中读取数据包。
- 使用`avcodec_send_packet()`和`avcodec_receive_frame()`进行解码。
- 将解码后的帧通过`sws_scale()`转换为RGB格式。
7. **清理资源**:
- 释放所有分配的内存和关闭上下文。
### 注意事项
- 确保FFmpeg编译时启用了`--enable-librockchip_vpu`以支持RK3588的硬件加速。
- 如果需要保存RGB帧,可以将其写入文件或传递给其他处理模块。
阅读全文
相关推荐















