ffmpeg视频H264压缩,rtsp推流课程教学视频:
https://edu.youkuaiyun.com/course/detail/27795
课件中里面提供源码可以直接下载运行!
-------------------------------------------------------------------------------------------------------------------------------------
一、界面
1 打开的pushbutton
2 停止/开始的pushbutton
3 进度条 QSlider
4 播放窗口widget
二、创建videothread线程
该线程用于读取视频数据流 具体实现过程可以参考
http://blog.youkuaiyun.com/yunge812/article/details/79342089
其中需要添加SDL处理音频的部分进去
2.1 SDL初始化
if (SDL_Init(SDL_INIT_AUDIO))
{
fprintf(stderr,"Could not initialize SDL - %s. \n", SDL_GetError());
exit(1);
}
2.2 获取音频流信息
for (i = 0; i < pFormatCtx->nb_streams; i++)
{
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO && audioStream < 0)
{
audioStream = i;
}
}
///如果audioStream为-1 说明没有找到音频流
if (audioStream == -1) {
printf("Didn't find a audio stream.\n");
return;
}
if (audioStream >= 0)
{
/// 设置SDL音频流信息 音频处理初始化
audio_stream_component_open(&mVideoState, audioStream); //该函数后续会进行完成
}
audio_stream_component_open函数在3.3.1中会涉及
2.3 查找音频解码器
///================================ 查找音频解码器 =================================//
AVCodecContext *aCodecCtx;
aCodecCtx = pFormatCtx->streams[audioStream]->codec;
AVCodec *aCodec;
aCodec = avcodec_find_decoder(aCodecCtx->codec_id);
if (aCodec == NULL)
{
printf("ACodec not found.\n");
return;
}
///================================ 打开音频解码器 ==================================//
if (avcodec_open2(aCodecCtx, aCodec, NULL) < 0)
{
printf("Could not open audio codec.\n");
return;
} 1 SDL初始化
vs->audio_st = pFormatCtx->streams[audioStream]; ///设置音频解码
packet_queue_init(&vs->videoq); //音频处理:初始化队列
2.4 创建视频解码的线程 由SDL进行创建 video_thread函数后续阶段完成
vs->video_tid = SDL_CreateThread(video_thread, "video_thread", &mVideoState);
vs->player = this; //线程指针
2.5 分配AVPacket用于存放读取的视频
AVPacket *packet = (AVPacket *) malloc(sizeof(AVPacket)); //分配一个packet 用于存放读取的视频
三、开始进行音视频的读取
3.1 音视频统一读取
//=========================== 读取视频信息 ===============================//
if (av_read_frame(pFormatCtx, packet) < 0) //读取的是一帧视频 数据存入一个AVPacket的结构中
{
qDebug() << "read error." ;
return ;
}
//此时数据存储在packet中
if (packet->stream_index == videoStream)
{
packet_queue_put(&vs->videoq, packet); //这里我们将视频数据存入队列
}
else if( packet->stream_index == audioStream )
{
packet_queue_put(&vs->audioq, packet);//这里我们将音频数据存入队列
}
3.2 视频读取线程 将视频转换成QImage显示
3.2.1 视频相关结构体的分配
///解码视频相关
AVFrame *pFrame, *pFrameRGB;
uint8_t *out_buffer_rgb; //解码后的rgb数据
struct SwsContext *img_convert_ctx; //用于解码后的视频格式转换
AVCodecContext *pCodecCtx = is->video_st->codec; //视频解码器
pFrame = av_frame_alloc();
pFrameRGB = av_frame_alloc();
///这里我们改成了 将解码后的YUV数据转换成RGB32
img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,
PIX_FMT_RGB32, SWS_BICUBIC, NULL, NULL, NULL);
numBytes = avpicture_get_size(PIX_FMT_RGB32, pCodecCtx->width,pCodecCtx->height);
out_buffer_rgb = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));
avpicture_fill((AVPicture *) pFrameRGB, out_buffer_rgb, PIX_FMT_RGB32, pCodecCtx->width, pCodecCtx->height);
// 会将pFrameRGB的数据按RGB格