FFMPEG 实时流媒体 客户端 大致流程

@property AVFormatContext                   *pFormatCtx;

//video
@property struct AVCodecContext *pVideoCodecCtx;
@property struct AVFrame *videoAVFrame;
@property int video_sampleRate;
@property int video_stream_index;

//audio
@property enum AVCodecID audio_codecID;
@property int audio_sampleRate;
@property int audio_stream_index;
@property AVCodecContext *pAudioCodecCtx;
@property struct AVFrame *audioAVFrame;
@property SwrContext *swrContext;



    av_register_all();
    avcodec_register_all();
    avformat_network_init();

    _pFormatCtx = avformat_alloc_context();
    
    errCode = avformat_open_input(&_pFormatCtx, "rtsp://192.168.1.100:554/live1.sdp", NULL, NULL);
    if(errCode!=0)
    {
        printf("Couldn't open input stream \n");
        return;
    }
    if(avformat_find_stream_info(_pFormatCtx, NULL)<0)
    {
        printf("Couldn't find stream information \n");
        return;
    }
    for(int i = 0;i < _pFormatCtx->nb_streams;i++)
    {
        if(_pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
        {
            AVCodec *audioCodec = NULL
            _audio_sampleRate = _pFormatCtx->streams[i]->codec->sample_rate;
            
            audioCodec = avcodec_find_decoder(_pAudioCodecCtx->codec_id);
            _audio_stream_index = i;

            if(!audioCodec)
            {
                printf("get audio Codec error\n");
            }
            if(avcodec_open2(_pAudioCodecCtx, audioCodec, NULL)<0)
            {
                printf("avcode_open for audio error\n");
            }
            
            //For Audio Convert
            int64_t chIn = av_get_default_channel_layout(_pAudioCodecCtx->channels);//src channel数,例如channel为2
            int64_t chOut = av_get_default_channel_layout(_audioPlayer->_channels);//dst channel数,例如channel为2
            
			//从src的格式(网络数据),转为dst的格式(本地播放器,可以自己设定)
            _swrContext = swr_alloc_set_opts(NULL,
                                             chOut,//dst
                                             _audioPlayer->_sampleFormat,//dst 例如AV_SAMPLE_FMT_S16
                                             _audioPlayer->_sampleRate,//dst 例如8k
                                             chIn, //src
                                             _pAudioCodecCtx->sample_fmt,//src
                                             _pAudioCodecCtx->sample_rate,//src
                                             0,
                                             NULL);
            swr_init(_swrContext);
			//End Aduio Convert
        }
        else if(_pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
        {
			AVCodec *videcCodec = NULL;
            _pVideoCodecCtx = _pFormatCtx->streams[i]->codec;
            videcCodec = avcodec_find_decoder(_pVideoCodecCtx->codec_id);
            
            _video_stream_index = i;
            
            if(videcCodec==NULL)
            {
                printf("Video Codec not found \n");
                return ;
            }
            if(avcodec_open2(_pVideoCodecCtx, _pVideoCodec, NULL)<0)
            {
                printf("Video Codec open Fail \n");
                return;
            }  
        }
    }
    _videoAVFrame = avcodec_alloc_frame();
    _audioAVFrame = avcodec_alloc_frame();
    if(!_audioAVFrame || !_videoAVFrame)
    {
        printf("alloc frame fail\n");
    }
    
		
	//Read Frame
    while (1)
    {
        int ret = 0;
        int got_frame = 0;
        AVPacket packet;
        if(av_read_frame(_pFormatCtx,&packet)<0)
        {
            printf("av_read_frame not find frame\n");
            continue;
        }
        if(packet.stream_index == _video_stream_index)
        {
            ret = avcodec_decode_video2(_pVideoCodecCtx, _videoAVFrame, &got_frame, &packet);
            if(ret<0)
            {
                printf("video decode fail\n");
            }
            if(got_frame)
            {
				//to do
				//图像信息都在_videoAVFrame中,自己去渲染
            }
        }
        else if(packet.stream_index == _audio_stream_index)
        {
            ret = avcodec_decode_audio4(_pAudioCodecCtx, _audioAVFrame, &got_frame, &packet);
            if(ret<0)
            {
                printf("decode audio fail\n");
            }
            if(got_frame)
            {
				//音频信息都在_audioAVFrame中,自己渲染
				//音频比视频多一步:音频转化,将所有的音频都转为固定的设定(例如都转为8k 2ch 16bits)
                static unsigned char * p = NULL;
                if(p==NULL)
                {
                    p = (unsigned char*)malloc(1024*1024);//接收区足够大,暂不释放
                }
                
                int numSample = swr_convert(_swrContext, &p, _audioAVFrame->nb_samples, (const uint8_t**)_audioAVFrame->data, _audioAVFrame->nb_samples);
                
                //实际有效的输出到耳机的bytes数目
                int iAvaSize = numSample * _audioPlayer->_channels/* dst 的channel数*/ * _audioPlayer->mDataFormat.mBitsPerChannel/*dst  bits数,例如AV_SAMPLE_FMT_S16就应该是16bits*/ / 8;
                
				//to do
				//memcpy(地址,p,iAvaSize);//iAvaSize为实际输出的有效bytes
            }
        }
        av_free_packet(&packet);
    }


    avcodec_free_frame(&_audioAVFrame);
    avcodec_free_frame(&_videoAVFrame);

    if (_pFormatCtx)
    {
        avformat_close_input(&_pFormatCtx);
        avformat_free_context(_pFormatCtx);
    }


你可能感兴趣的:(FFMPEG 实时流媒体 客户端 大致流程)