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顯示視頻的情況下,實測延時較小。在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章