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

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

    • ffmepg 播放Rtsp流的代码
    • 基于上述函数的QT rtsp 播放器

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显示视频的情况下,实测延时较小。ffmepg 播放Rtsp流解码器(转换成RGB32)_第1张图片

你可能感兴趣的:(ffmepg)