生成一个使用rockchip rmmpp 硬件编码器 输出h264格式用ffmpeg推流出去
时间: 2023-06-15 16:03:29 浏览: 389
以下是使用rockchip rmmpp 硬件编码器将视频流编码为 H264 格式,然后使用 FFmpeg 推流的示例命令:
```bash
ffmpeg -f v4l2 -input_format mjpeg -video_size 640x480 -i /dev/video0 -c:v h264_rkmpp -f flv rtmp://your_streaming_server_url
```
这个命令假定你的摄像头设备是 `/dev/video0`,视频输入格式为 MJPEG,分辨率为 640x480。h264_rkmpp 是 FFmpeg 中支持 Rockchip RMMPP 硬件编码器的编码器。
你需要将 `rtmp://your_streaming_server_url` 替换为你自己的 RTMP 流媒体服务器的推流地址。
相关问题
生成一个使用qt下 jpeg图片使用rockchip rmmpp 硬件编码器 输出h264格式用ffmpeg推流出去
这是一个比较复杂的任务,需要使用到一些专业的技能和工具。以下是大致的步骤:
1. 使用 Qt 中的函数加载 JPEG 图片并将其转换为 YUV 格式的数据。
2. 将 YUV 数据传输到 Rockchip RMMPP 硬件编码器,使用硬件编码器将 YUV 数据编码为 H.264 格式的视频流。
3. 使用 FFmpeg 将编码后的 H.264 视频流推送到网络上。
具体实现步骤如下:
1. 加载 JPEG 图片并将其转换为 YUV 格式的数据。可以使用 Qt 中的 QImage 类和其转换函数来实现。
```cpp
QImage image("test.jpg");
QByteArray imageData;
QBuffer buffer(&imageData);
buffer.open(QIODevice::ReadWrite);
image.save(&buffer, "JPEG");
// 转换为 YUV 格式
int width = image.width();
int height = image.height();
int size = width * height * 3 / 2; // YUV 数据的大小
unsigned char* yuvData = new unsigned char[size];
libyuv::ConvertFromI420((const uint8_t*)buffer.data().data(), buffer.data().size(),
yuvData, width,
yuvData + width * height, width / 2,
yuvData + width * height * 5 / 4, width / 2,
0, 0, // 无需旋转
width, height,
width, height,
libyuv::kRotate0, libyuv::FOURCC_I420);
```
2. 将 YUV 数据传输到 Rockchip RMMPP 硬件编码器,使用硬件编码器将 YUV 数据编码为 H.264 格式的视频流。
首先需要初始化 Rockchip RMMPP 硬件编码器,然后将 YUV 数据传输到硬件编码器中,进行编码。
```cpp
// 初始化硬件编码器
MPP_RET ret = MPP_OK;
MppCtx mpp_ctx = NULL;
MppApi *mpi = NULL;
MppCodingType coding_type = MPP_VIDEO_CodingAVC;
MppParam param;
ret = mpp_create(&mpp_ctx, &mpi);
if (ret != MPP_OK) {
qDebug() << "mpp_create failed!";
return;
}
// 设置编码器参数
MppEncPrepCfg prep_cfg;
MppEncRcCfg rc_cfg;
MppEncH264Cfg h264_cfg;
memset(&prep_cfg, 0, sizeof(prep_cfg));
prep_cfg.change = MPP_ENC_PREP_CFG_CHANGE_INPUT |
MPP_ENC_PREP_CFG_CHANGE_FORMAT |
MPP_ENC_PREP_CFG_CHANGE_ROTATION;
prep_cfg.width = width;
prep_cfg.height = height;
prep_cfg.format = MPP_FMT_YUV420SP;
prep_cfg.rotation = MPP_ENC_ROT_0;
memset(&rc_cfg, 0, sizeof(rc_cfg));
rc_cfg.change = MPP_ENC_RC_CFG_CHANGE_RC_MODE;
rc_cfg.rc_mode = MPP_ENC_RC_MODE_CBR;
memset(&h264_cfg, 0, sizeof(h264_cfg));
h264_cfg.change = MPP_ENC_H264_CFG_CHANGE_PROFILE |
MPP_ENC_H264_CFG_CHANGE_ENTROPY |
MPP_ENC_H264_CFG_CHANGE_TRANS_8x8 |
MPP_ENC_H264_CFG_CHANGE_QP_LIMIT;
h264_cfg.profile = MPP_PROFILE_H264_HIGH;
h264_cfg.entropy_coding_mode = 1; // CABAC
h264_cfg.transform8x8_mode = 1;
h264_cfg.qp_max = 40;
h264_cfg.qp_min = 20;
h264_cfg.qp_max_step = 4;
param = &prep_cfg;
mpi->control(mpp_ctx, MPP_ENC_SET_PREP_CFG, param);
param = &rc_cfg;
mpi->control(mpp_ctx, MPP_ENC_SET_RC_CFG, param);
param = &h264_cfg;
mpi->control(mpp_ctx, MPP_ENC_SET_CODEC_CFG, param);
ret = mpi->init(mpp_ctx, MPP_CTX_ENC, coding_type);
if (ret != MPP_OK) {
qDebug() << "mpi->init failed!";
return;
}
// 传输 YUV 数据到硬件编码器
MppBuffer yuv_buf = NULL;
MppBuffer packet_buf = NULL;
MppFrame frame = NULL;
MppPacket packet = NULL;
ret = mpp_buffer_get(mpp_ctx, &yuv_buf, size);
if (ret != MPP_OK) {
qDebug() << "mpp_buffer_get yuv_buf failed!";
return;
}
memcpy((void*)mpp_buffer_get_ptr(yuv_buf), yuvData, size);
ret = mpi->poll(mpp_ctx, MPP_PORT_INPUT, MPP_POLL_BLOCK);
if (ret != MPP_OK) {
qDebug() << "mpi->poll input failed!";
return;
}
ret = mpi->dequeue(mpp_ctx, MPP_PORT_INPUT, &frame);
if (ret != MPP_OK) {
qDebug() << "mpi->dequeue input failed!";
return;
}
frame->width = width;
frame->height = height;
frame->hor_stride = width;
frame->ver_stride = height;
frame->buf[0] = yuv_buf;
frame->buf[1] = frame->buf[0] + width * height;
frame->buf[2] = frame->buf[1] + width * height / 4;
ret = mpi->enqueue(mpp_ctx, MPP_PORT_INPUT, frame);
if (ret != MPP_OK) {
qDebug() << "mpi->enqueue input failed!";
return;
}
ret = mpi->poll(mpp_ctx, MPP_PORT_OUTPUT, MPP_POLL_BLOCK);
if (ret != MPP_OK) {
qDebug() << "mpi->poll output failed!";
return;
}
ret = mpi->dequeue(mpp_ctx, MPP_PORT_OUTPUT, &packet);
if (ret != MPP_OK) {
qDebug() << "mpi->dequeue output failed!";
return;
}
// 获取编码后的数据
unsigned char* h264Data = new unsigned char[packet->length];
memcpy(h264Data, mpp_packet_get_data(packet), packet->length);
```
3. 使用 FFmpeg 将编码后的 H.264 视频流推送到网络上。
首先需要初始化 FFmpeg,然后将编码后的 H.264 视频流写入到 FFmpeg 的 AVPacket 中,并使用 FFmpeg 将 AVPacket 推送到网络上。
```cpp
// 初始化 FFmpeg
av_register_all();
avformat_network_init();
AVFormatContext* fmt_ctx = NULL;
avformat_alloc_output_context2(&fmt_ctx, NULL, "flv", "rtmp://xxx.xxx.xxx.xxx:1935/live");
AVOutputFormat* fmt = fmt_ctx->oformat;
AVStream* video_stream = avformat_new_stream(fmt_ctx, NULL);
AVCodec* codec = avcodec_find_encoder_by_name("libx264");
AVCodecContext* codec_ctx = avcodec_alloc_context3(codec);
codec_ctx->codec_id = AV_CODEC_ID_H264;
codec_ctx->codec_type = AVMEDIA_TYPE_VIDEO;
codec_ctx->width = width;
codec_ctx->height = height;
codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
codec_ctx->time_base = { 1, 25 };
codec_ctx->bit_rate = 500000;
avcodec_open2(codec_ctx, codec, NULL);
video_stream->codecpar->codec_id = AV_CODEC_ID_H264;
video_stream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
video_stream->codecpar->width = width;
video_stream->codecpar->height = height;
video_stream->codecpar->format = codec_ctx->pix_fmt;
video_stream->codecpar->bit_rate = codec_ctx->bit_rate;
video_stream->time_base = codec_ctx->time_base;
avformat_write_header(fmt_ctx, NULL);
// 推送编码后的视频流到网络
AVPacket pkt;
av_init_packet(&pkt);
pkt.data = h264Data;
pkt.size = packet->length;
pkt.stream_index = video_stream->index;
av_write_frame(fmt_ctx, &pkt);
av_write_trailer(fmt_ctx);
avcodec_free_context(&codec_ctx);
avformat_free_context(fmt_ctx);
```
这样,就完成了使用 Qt、Rockchip RMMPP 硬件编码器和 FFmpeg 将 JPEG 图片编码为 H.264 格式并推送到网络上的任务。
生成一个qt下 jpeg图片使用rockchip rmmpp 硬件编码器 输出h264格式用ffmpeg推流出去的完整程序
下面是一个使用 Rockchip RMMPP 硬件编码器将 JPEG 图像编码为 H.264 视频并使用 FFmpeg 推流的 QT 程序的示例:
```cpp
#include <QDebug>
#include <QObject>
#include <QTimer>
#include <QImage>
#include <QDateTime>
#include <QCoreApplication>
#include <QByteArray>
#include <QBuffer>
#include <rockchip/rk_mpi.h>
#include <rockchip/rk_rga.h>
#include <rockchip/rockface/rockface.h>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
}
static AVFormatContext *ctx;
static AVCodecContext *codec_ctx;
static AVCodec *codec;
static int video_stream_index;
static AVStream *video_stream;
static AVFrame *frame;
static AVPacket pkt;
static void init_ffmpeg(const char *url, int width, int height, int fps)
{
av_register_all();
codec = avcodec_find_encoder_by_name("libx264");
if (!codec) {
qDebug() << "Codec not found";
exit(1);
}
codec_ctx = avcodec_alloc_context3(codec);
if (!codec_ctx) {
qDebug() << "Could not allocate video codec context";
exit(1);
}
codec_ctx->bit_rate = 400000;
codec_ctx->width = width;
codec_ctx->height = height;
codec_ctx->time_base = {1, fps};
codec_ctx->framerate = {fps, 1};
codec_ctx->gop_size = 10;
codec_ctx->max_b_frames = 1;
codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
if (codec->id == AV_CODEC_ID_H264) {
av_opt_set(codec_ctx->priv_data, "preset", "ultrafast", 0);
}
if (avcodec_open2(codec_ctx, codec, NULL) < 0) {
qDebug() << "Could not open codec";
exit(1);
}
avformat_alloc_output_context2(&ctx, NULL, "flv", url);
if (!ctx) {
qDebug() << "Could not allocate output context";
exit(1);
}
if (ctx->oformat->video_codec != AV_CODEC_ID_NONE) {
video_stream = avformat_new_stream(ctx, NULL);
if (!video_stream) {
qDebug() << "Could not create new stream";
exit(1);
}
video_stream_index = video_stream->index;
AVCodecParameters *codecpar = video_stream->codecpar;
codecpar->codec_id = ctx->oformat->video_codec;
codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
codecpar->width = width;
codecpar->height = height;
codecpar->format = AV_PIX_FMT_YUV420P;
codecpar->codec_tag = 0;
avcodec_parameters_to_context(codec_ctx, codecpar);
av_dump_format(ctx, 0, url, 1);
}
if (!(ctx->oformat->flags & AVFMT_NOFILE)) {
if (avio_open(&ctx->pb, url, AVIO_FLAG_WRITE) < 0) {
qDebug() << "Could not open output file";
exit(1);
}
}
if (avformat_write_header(ctx, NULL) < 0) {
qDebug() << "Error occurred when opening output file";
exit(1);
}
frame = av_frame_alloc();
if (!frame) {
qDebug() << "Could not allocate video frame";
exit(1);
}
frame->format = codec_ctx->pix_fmt;
frame->width = codec_ctx->width;
frame->height = codec_ctx->height;
if (av_frame_get_buffer(frame, 32) < 0) {
qDebug() << "Could not allocate the video frame data";
exit(1);
}
}
static void encode_and_write_frame(AVFrame *frame)
{
int ret;
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
ret = avcodec_send_frame(codec_ctx, frame);
if (ret < 0) {
qDebug() << "Error sending a frame for encoding";
exit(1);
}
while (ret >= 0) {
ret = avcodec_receive_packet(codec_ctx, &pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return;
else if (ret < 0) {
qDebug() << "Error during encoding";
exit(1);
}
av_write_frame(ctx, &pkt);
av_packet_unref(&pkt);
}
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// Initialize RMMPP
RK_MPI_SYS_Init();
RK_MPI_RGN_Init();
RK_MPI_RGN_Setup();
// Initialize FFmpeg
init_ffmpeg("rtmp://example.com/live/stream", 640, 480, 30);
// Capture JPEG image and encode to H.264
while (true) {
// Capture JPEG image
QImage img(640, 480, QImage::Format_RGB888);
img.fill(Qt::red);
// Convert to YUV420P
QByteArray yuv_data;
yuv_data.resize(640 * 480 * 3 / 2);
uchar *y_data = (uchar *)yuv_data.data();
uchar *u_data = y_data + 640 * 480;
uchar *v_data = u_data + 640 * 480 / 4;
QImage yuv_image(y_data, 640, 480, QImage::Format_YUV420P);
QImage rgb_image = img.convertToFormat(QImage::Format_RGB888);
for (int y = 0; y < 480; y++) {
memcpy(y_data + y * 640, rgb_image.scanLine(y), 640 * 3);
}
for (int y = 0; y < 480 / 2; y++) {
for (int x = 0; x < 640 / 2; x++) {
int r = *(rgb_image.scanLine(y * 2) + x * 6 + 0);
int g = *(rgb_image.scanLine(y * 2) + x * 6 + 1);
int b = *(rgb_image.scanLine(y * 2) + x * 6 + 2);
*u_data++ = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
r = *(rgb_image.scanLine(y * 2) + x * 6 + 3);
g = *(rgb_image.scanLine(y * 2) + x * 6 + 4);
b = *(rgb_image.scanLine(y * 2) + x * 6 + 5);
*v_data++ = ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;
}
}
// Encode to H.264 and write to output stream
frame->pts = QDateTime::currentMSecsSinceEpoch() * 90;
frame->data[0] = y_data;
frame->data[1] = u_data - 640 * 480 / 4;
frame->data[2] = v_data - 640 * 480 / 4;
encode_and_write_frame(frame);
}
// Clean up
av_write_trailer(ctx);
avcodec_free_context(&codec_ctx);
av_frame_free(&frame);
if (!(ctx->oformat->flags & AVFMT_NOFILE)) {
avio_closep(&ctx->pb);
}
avformat_free_context(ctx);
RK_MPI_RGN_Exit();
RK_MPI_SYS_Exit();
return a.exec();
}
```
这个程序中使用了 `RK_MPI_RGN_Setup()` 和 `RK_MPI_RGN_Exit()` 函数来初始化和清理 Rockchip RMMPP 硬件编码器。请注意,这些函数可能与您的系统有所不同,具体取决于您使用的硬件。
此程序同时使用了 FFmpeg 和 Rockchip RMMPP,因此需要链接以下库:
```txt
-lavcodec -lavformat -lavutil -lswscale -lrockface -lrk_mpi -lrk_rga -lrk_vpu
```
请注意,此程序仅提供作为示例使用,实际使用中您需要根据您的需求进行修改。
阅读全文