ffmpeg RTSP流拉取

extern "C" {
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "libavutil/pixdesc.h"
#include "libavutil/mem.h"
}

using namespace std;

typedef enum {
    
    SLPiecesErrorNone,
    SLPiecesErrorOpenFile,
    SLPiecesErrorStreamInfoNotFound,
    SLPiecesErrorCodecNotFound,
    SLPiecesErrorOpenCodec,
    SLPiecesErrorAllocateFrame,
    SLPiecesErroSetupScaler,
    SLPiecesErroReSampler,
    SLPiecesErroUnsupported,
} SLPiecesError;

class SLRtspDecoder{
public:
    SLRtspDecoder();
    ~SLRtspDecoder();
    
public:
    void regsterWindow(CAEAGLLayer  *layer);
    int starPlayVideo(std::string &path);
    void stopPlayVideo();
    
private:
    SLPiecesError avformatOpenInput(std::string &path);
    SLPiecesError openVideoStream();
    void closeVideoStream();
    SLPiecesError openAVCodec(int videoStream);
    
    int readDataFromNetwork(AVPacket &avPacket);
    vector<int> collectStreams(AVFormatContext *formatCtx, enum AVMediaType codecType);
    void avStreamFPSTimeBase(AVStream *st, float defaultTimeBase, float *pFPS, float *pTimeBase);
    
private:
    bool isHaveLayer;
    float _fps;
    float _videoTimeBase;

    GLRender mGLRender;
    CAEAGLLayer *mViewWindow;
    
private:
    
    int _videoStream;
    int _artworkStream;
    bool _isFirstIFrame;
    vector<int> _videoStreams;
    
    AVFormatContext  *_formatCtx;
    AVFrame          *_videoFrame;
    AVCodecContext   *_videoCodecCtx;
};
#include "SLRtspDecoder.hpp"

SLRtspDecoder::SLRtspDecoder()
{

}

SLRtspDecoder::~SLRtspDecoder()
{

}

void SLRtspDecoder::regsterWindow(CAEAGLLayer *layer)
{
    mViewWindow = layer;
}

int SLRtspDecoder::starPlayVideo(std::string &path)
{
    //Step 1: Register all file formats and codec library.
    av_register_all();
    
    //Step 2: Open the network video stream.
    avformat_network_init();
    _isFirstIFrame = false;
    
    //Step 3: AVFormat open input and get parameters(_formatCtx).
    SLPiecesError errCode = this->avformatOpenInput(path);
    if (errCode != SLPiecesErrorNone) {
        return -1;
    }
    
    //Step4:Set avcodec with video stream.
    SLPiecesError videoErr = this->openVideoStream();
    if (videoErr != SLPiecesErrorNone) {
        return -1;
    }
    
    AVPacket avPacket;
    while (true){
        this->readDataFromNetwork(avPacket);
    }

    return 0;
}

int SLRtspDecoder::readDataFromNetwork(AVPacket &avPacket)
{
    int nRet = av_read_frame(_formatCtx, &avPacket);
    if(nRet < 0){
        clock_t now = clock();
        while(clock() - now < 100);
        return -1;
    }
    
    if (avPacket.stream_index ==_videoStream) {
        //Return the number of bytes used: got_picture_ptr Zero if no frame could be decompressed,.
        int gotFrame = 0;
        int lenUseable = avcodec_decode_video2(_videoCodecCtx, _videoFrame, &gotFrame, &avPacket);
        
        if (lenUseable <= 0 || gotFrame == 0) {
            printf(0, "--->decode video error, skip packet.");
            return -1;
        }
        
        //Find the first key frame.
        if(!_isFirstIFrame && _videoFrame->key_frame){
            _isFirstIFrame = true;
            return -1;
        }
        
        if (_videoCodecCtx->width > 0 && _videoCodecCtx->height > 0 && !isHaveLayer) {
            isHaveLayer = true;
            mGLRender.setGLSurface(_videoCodecCtx->width, _videoCodecCtx->height, mViewWindow);
        }
        
        if(_videoCodecCtx->width > 0 && _videoCodecCtx->height > 0){
            mGLRender.nativeGLRender(_videoFrame->data[0],_videoFrame->data[1],_videoFrame->data[2]);
        }
    }
    av_free_packet(&avPacket);
    return 0;
}

SLPiecesError SLRtspDecoder::avformatOpenInput(std::string &path)
{
    //Allocate an AVFormatContext.
    AVFormatContext *formatCtx = avformat_alloc_context();
    if (!formatCtx){
        return SLPiecesErrorOpenFile;
    }
    
    //Open an input stream and read the header. The codecs are not opened.
    AVDictionary * opts = NULL;
    int net = avformat_open_input(&formatCtx, path.c_str(), NULL, &opts);
    if (net < 0) {
        if (formatCtx){
            avformat_close_input(&formatCtx);
            avformat_free_context(formatCtx);
        }
        return SLPiecesErrorOpenFile;
    }
    
    //Read packets of a media file to get stream information.
    if (avformat_find_stream_info(formatCtx, NULL) < 0) {
        avformat_close_input(&formatCtx);
        return SLPiecesErrorStreamInfoNotFound;
    }

    //Print detailed information about the input or output format.
    av_dump_format(formatCtx, 0, "1", false);
    _formatCtx = formatCtx;
    return SLPiecesErrorNone;
}

SLPiecesError SLRtspDecoder::openVideoStream()
{
    _videoStream = -1;
    _artworkStream = -1;
    SLPiecesError errCode = SLPiecesErrorCodecNotFound;
    _videoStreams = collectStreams(_formatCtx, AVMEDIA_TYPE_VIDEO);
    
    for (auto iter = _videoStreams.begin(); iter != _videoStreams.end(); iter ++) {
        const int iStream = *iter;
        
        if (0 == (_formatCtx->streams[iStream]->disposition & AV_DISPOSITION_ATTACHED_PIC)) {
            errCode = this->openAVCodec(iStream);
            if (errCode == SLPiecesErrorNone){
                break;
            }
        } else {
            _artworkStream = iStream;
        }
    }
    
    return errCode;
}

vector<int> SLRtspDecoder::collectStreams(AVFormatContext *formatCtx, enum AVMediaType codecType)
{
    vector<int> streamVector;
    for (int i = 0; i < formatCtx->nb_streams; ++i){
        if (codecType == formatCtx->streams[i]->codec->codec_type){
            streamVector.push_back(i);
        }
    }
    
    return streamVector;
}

SLPiecesError SLRtspDecoder::openAVCodec(int videoStream)
{
    // Find a registered decoder with a matching codec ID.
    AVCodecContext *codecCtx = _formatCtx->streams[videoStream]->codec;
    AVCodec *codec = avcodec_find_decoder(codecCtx->codec_id);
    if (!codec){
        return SLPiecesErrorCodecNotFound;
    }
    
    // Initialize the AVCodecContext to use the given AVCodec.
    if (avcodec_open2(codecCtx, codec, NULL) < 0){
        return SLPiecesErrorOpenCodec;
    }
    
    // Allocate an AVFrame and set its fields to default values.
    _videoFrame = av_frame_alloc();
    if (!_videoFrame) {
        avcodec_close(codecCtx);
        return SLPiecesErrorAllocateFrame;
    }
    
    // Calc fps
    _videoStream = videoStream;
    _videoCodecCtx = codecCtx;
    
    AVStream *streamData = _formatCtx->streams[_videoStream];
    avStreamFPSTimeBase(streamData, 0.04, &_fps, &_videoTimeBase);
    return SLPiecesErrorNone;
}

void SLRtspDecoder::avStreamFPSTimeBase(AVStream *st, float defaultTimeBase, float *pFPS, float *pTimeBase)
{
    float fps, timebase;
    
    if (st->time_base.den && st->time_base.num){
        timebase = av_q2d(st->time_base);
    }else if(st->codec->time_base.den && st->codec->time_base.num){
        timebase = av_q2d(st->codec->time_base);
    }else{
        timebase = defaultTimeBase;
    }
    
    if (st->codec->ticks_per_frame != 1) {
        timebase *= st->codec->ticks_per_frame;
    }
    
    if (st->avg_frame_rate.den && st->avg_frame_rate.num){
        fps = av_q2d(st->avg_frame_rate);
    }else if (st->r_frame_rate.den && st->r_frame_rate.num){
        fps = av_q2d(st->r_frame_rate);
    }else{
        fps = 1.0 / timebase;
    }
    
    if (pFPS){
        *pFPS = fps;
    }
    
    if (pTimeBase){
        *pTimeBase = timebase;
    }
}

void SLRtspDecoder::stopPlayVideo(){
    
    this->closeVideoStream();
    if (_formatCtx) {
        avformat_close_input(&_formatCtx);
        _formatCtx = NULL;
    }
}

void SLRtspDecoder::closeVideoStream()
{
    _videoStream = -1;
    
    if (_videoFrame) {
        //av_free(_videoFrame);
        _videoFrame = NULL;
    }
    
    if (_videoCodecCtx) {
        avcodec_close(_videoCodecCtx);
        _videoCodecCtx = NULL;
    }
}


  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值