由于工作,需要对RTMP视频直播流进行接收和播放。研究一段时间,终于有所成效。下面对在研究过程进行一些总结,方便其他人员少走一些弯路。
一、简介
视频包含原始音频和视频数据,服务器在推送这些原始数据时,需要对音视频进行编码,同时在传输过程中通过视频流输协议进行封装,比如(rtmp,rtsp…)。因此,客户端如果想要播放网络传输的视频流,我们需要剥取传输协议封装的音视频文件,同时对其进行解码,分别获取对应的音频和视频文件,然后对其进行操作。如图(摘自雷神的流程图,太懒…)
值得庆幸的是,FFMPEG对网络视频流的传输协议进行很好的处理,对项目比较急的人,可以忽略传输协议的研究(有兴趣可以后期研究),更加高效的完成项目的集成。客户端的接收与播放过程主要是对视频和音频进行处理,我将分别进行介绍。
二、FFMPEG初始化
处理音视频之前,我们首先需要与服务器进行连接,获取视频流相关各种信息。
2.1).h文件,数据成员
AVFormatContext *pFormatCtx;//FFMPEG解封装(flv,mp4,rmvb,avi)功能的结构体
AVPacket *packet; //存储压缩的数据
AVFrame *pFrame; //存储原始数据(即非压缩数据,例如对视频来说是YUV,RGB,对音频来说是PCM)
AVCodecContext *pCodecCtx; //视频编码
int videoindex; //视频编码序号
AVFrame *pFrameYUV; //原始的yuv图像数据
struct SwsContext *img_convert_ctx;
uint8_t *out_buffer;
AVCodecContext *pAudioCodecCtx; //音频编码
int audioIndex; //音频编码序号
// AVCodec *pAudioCodec;
uint8_t *outAudio_buffer; //原始的PCM数据
struct SwrContext *au_convert_ctx;
int outAudio_buffer_size; //原始音频数据大小
SDL_Renderer* sdlRenderer;
SDL_Texture* sdlTexture;
SDL_Rect sdlRect;
SDL_Window *screen;
2.2)初始化FFMpeg
char filepath[] = "rtmp://118.178.252.242/live/123"; //rtmp流服务器url
//申请内存
pFrame = av_frame_alloc();
pFrameYUV = av_frame_alloc();
packet = (AVPacket *)av_malloc(sizeof(AVPacket));
pFormatCtx = avformat_alloc_context();
outAudio_buffer = (uint8_t *)av_malloc(MAX_AUDIO_FRAME_SIZE * 2);
av_register_all();
avformat_network_init();
dwLastFrameRealtime = GetTickCount();
pFormatCtx->interrupt_callback.opaque = this; //C++
pFormatCtx->interrupt_callback.callback = interrupt_cb; //超时链接,设置回调函数,否则有可能ffmpeg在打开和读取数据阻塞进程。
if (avformat_open_input(&pFormatCtx, filepath, NULL, NULL) != 0) {
//与服务器建立链接
printf("Couldn't open input stream.\n");
return -1;
}
if (avformat_find_stream_info(pFormatCtx, NULL)<0) {
printf("Couldn't find stream information.\n");
return -1;
}
//Output Info-----------------------------
av_dump_format(pFormatCtx, 0, filepath, 0);
2.3)初始化SDL
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
printf("Could not initialize SDL - %s\n", SDL_GetError());
return -1;
}
三、视频
下面将对视频进行一些处理,主要是对视频进行解码&#x