ffmepg 播放Rtsp流解码器(转换成RGB32)

ffmepg 播放Rtsp流解码器(转换成RGB32)

ffmepg 播放Rtsp流的代码

#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/pixfmt.h"
#include "libswscale/swscale.h"
#include "libavutil/imgutils.h"

typedef void* (*rtsp_callback_t)(unisgned char* data,unsigned int width,unsigned int height)

int rtspPlayer(const char* url,rtsp_callback_t callback)
{
	//初始化网络模块以及ffmpeg
    avformat_network_init();
    av_register_all();

    //申请 AVFormatContext 结构体
    AVFormatContext *pFormatCtx = avformat_alloc_context();
    if(pFormatCtx == nullptr){
       qDebug() << "alloc av fromat error!\n" << endl;
       return;
    }

    AVDictionary *avdic=NULL;
    char option_key[]="rtsp_transport";
    char option_value[]="tcp";
    av_dict_set(&avdic,option_key,option_value,0);

    char option_key2[]="max_delay";
    char option_value2[]="100";
    av_dict_set(&avdic,option_key2,option_value2,0);
    
    //打开媒体文件
    if (avformat_open_input(&pFormatCtx, url, NULL, &avdic) != 0) {
        qDebug("can't open the file. \n");
        return;
    }

    //查找解码器
    if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
        qDebug("Could't find stream infomation.\n");
        return;
    }

    //查找解码器参数
    int videoStream = -1;
    for (unsigned int i = 0; i < pFormatCtx->nb_streams; i++) {
        if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            videoStream = i;
        }
    }
    if (videoStream == -1) {
        qDebug("Didn't find a video stream.\n");
        return;
    }

    //申请解码器
    AVCodecContext* pCodecCtx = avcodec_alloc_context3(NULL);
    //从AVFormatContext设置解码器参数
    avcodec_parameters_to_context(pCodecCtx, pFormatCtx->streams[videoStream]->codecpar);
    //查找解码器
    AVCodec *pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
    //设置解码器参数
    pCodecCtx->bit_rate =0;
    pCodecCtx->time_base.num=1;  //下面两行:一秒钟25帧
    pCodecCtx->time_base.den=10;
    pCodecCtx->frame_number=1;  //每包一个视频帧

    if (pCodec == NULL) {
        qDebug("Codec not found.\n");
        return;
    }

    //打开解码器
    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
        qDebug("Could not open codec.\n");
        return;
    }

    //初始化SwsContext 设置转换为 AV_PIX_FMT_RGB32
    struct SwsContext *img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
            pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,
            AV_PIX_FMT_RGB32, SWS_BICUBIC, NULL, NULL, NULL);

    //申请内存
    AVFrame *pFrame     = av_frame_alloc();
    AVFrame *pFrameRGB  = av_frame_alloc();
    uint8_t *out_buffer = (uint8_t *) av_malloc(av_image_get_buffer_size(AV_PIX_FMT_RGB32, pCodecCtx->width, pCodecCtx->height, 1) * sizeof(uint8_t));

    av_image_fill_arrays(pFrameRGB->data, pFrameRGB->linesize, out_buffer, AV_PIX_FMT_RGB32, pCodecCtx->width, pCodecCtx->height, 1);

    AVPacket *packet = (AVPacket *) malloc(sizeof(AVPacket)); //分配一个packet
    av_new_packet(packet, pCodecCtx->width * pCodecCtx->height); //分配packet的数据

    while (1)
    {
        //从stream中获取一帧率数据
        if (av_read_frame(pFormatCtx, packet) < 0){
            break;
        }

        if (packet->stream_index == videoStream) {

            //送入解码器
            int ret = avcodec_send_packet(pCodecCtx, packet);
            int got_picture = avcodec_receive_frame(pCodecCtx, pFrame);

            if (ret < 0) {
                qDebug("decode error.\n");
                break;
            }

            if (!got_picture) {
                //颜色空间转换,最后输出到out_buffer
                sws_scale(img_convert_ctx,(uint8_t const * const *) pFrame->data,
                        pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data,
                        pFrameRGB->linesize);
				if(callback != NULL){
					//Do something you need...
					callback((uchar *)out_buffer,pCodecCtx->width,pCodecCtx->height);
            	}
        }

        av_packet_unref(packet);
        usleep(1000);
    }

    av_free(out_buffer);
    av_free(pFrame);
    av_free(pFrameRGB);

    avcodec_close(pCodecCtx);
    avformat_close_input(&pFormatCtx);
    sws_freeContext(img_convert_ctx);
}

基于上述函数的QT rtsp 播放器

在未使用openGL或者SDL显示视频的情况下,实测延时较小。在这里插入图片描述

在Qt中使用FFmpeg播放RTSP H264视频的方法如下[^1][^2]: 1. 首先,确保你已经安装了Qt和FFmpeg,并且已经将FFmpeg的库文件添加到Qt项目中。 2. 创建一个Qt项目,并在项目文件中添加FFmpeg的头文件和库文件的路径。 3. 在Qt的代码中,使用FFmpeg的API来实现视频播放。以下是一个简单的示例代码: ```cpp #include <QCoreApplication> #include <QDebug> #include <QThread> extern "C" { #include <libavformat/avformat.h> #include <libavcodec/avcodec.h> #include <libswscale/swscale.h> } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // 初始化FFmpeg av_register_all(); // 创建AVFormatContext对象 AVFormatContext *formatContext = avformat_alloc_context(); // 打开视频 if (avformat_open_input(&formatContext, "rtsp://your_rtsp_url", nullptr, nullptr) != 0) { qDebug() << "无法打开视频"; return -1; } // 查找视频信息 if (avformat_find_stream_info(formatContext, nullptr) < 0) { qDebug() << "无法获取视频信息"; return -1; } // 查找视频索引 int videoStreamIndex = -1; for (int i = 0; i < formatContext->nb_streams; i++) { if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { videoStreamIndex = i; break; } } // 如果找不到视频索引,退出程序 if (videoStreamIndex == -1) { qDebug() << "找不到视频"; return -1; } // 获取视频解码器参数 AVCodecParameters *codecParameters = formatContext->streams[videoStreamIndex]->codecpar; // 查找视频解码器 AVCodec *codec = avcodec_find_decoder(codecParameters->codec_id); if (codec == nullptr) { qDebug() << "找不到视频解码器"; return -1; } // 创建解码器上下文 AVCodecContext *codecContext = avcodec_alloc_context3(codec); if (avcodec_parameters_to_context(codecContext, codecParameters) < 0) { qDebug() << "无法创建解码器上下文"; return -1; } // 打开解码器 if (avcodec_open2(codecContext, codec, nullptr) < 0) { qDebug() << "无法打开解码器"; return -1; } // 创建帧对象 AVFrame *frame = av_frame_alloc(); // 创建解码后的帧对象 AVFrame *decodedFrame = av_frame_alloc(); // 创建解码后的帧的缓冲区 uint8_t *buffer = nullptr; int bufferSize = av_image_get_buffer_size(AV_PIX_FMT_RGB24, codecContext->width, codecContext->height, 1); buffer = (uint8_t *)av_malloc(bufferSize * sizeof(uint8_t)); av_image_fill_arrays(decodedFrame->data, decodedFrame->linesize, buffer, AV_PIX_FMT_RGB24, codecContext->width, codecContext->height, 1); // 创建视频转换上下文 SwsContext *swsContext = sws_getContext(codecContext->width, codecContext->height, codecContext->pix_fmt, codecContext->width, codecContext->height, AV_PIX_FMT_RGB24, SWS_BILINEAR, nullptr, nullptr, nullptr); // 读取视频帧 AVPacket packet; while (av_read_frame(formatContext, &packet) >= 0) { if (packet.stream_index == videoStreamIndex) { // 解码视频帧 avcodec_send_packet(codecContext, &packet); avcodec_receive_frame(codecContext, frame); // 转换视频帧格式 sws_scale(swsContext, frame->data, frame->linesize, 0, codecContext->height, decodedFrame->data, decodedFrame->linesize); // 在这里可以将解码后的帧显示到界面上 // 延时一段时间,模拟视频播放 QThread::msleep(40); } av_packet_unref(&packet); } // 释放资源 av_frame_free(&frame); av_frame_free(&decodedFrame); avcodec_free_context(&codecContext); avformat_close_input(&formatContext); avformat_free_context(formatContext); return a.exec(); } ``` 请注意,上述代码只是一个简单的示例,实际的视频播放功能可能需要更多的处理和错误处理。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值