【c++】使用FFmpeg库进行视频流处理的

时间:2025-02-24 09:49:24
void MyVideoCapture::run_stream() //ffmpeg拉流获取视频帧 { AVFormatContext *pFormatCtx; AVCodecContext *pCodecCtx; AVCodec *pCodec; AVFrame *pFrame, *pFrameRGB; AVPacket *packet; uint8_t *out_buffer; static struct SwsContext *img_convert_ctx; int videoStream, i, numBytes; int ret, got_picture; avformat_network_init(); // 初始化网络库 av_register_all();// 初始化所有组件,调用该函数后,才能使用复用器和编解码器 pFormatCtx = avformat_alloc_context();// 分配AVFormatContext,它是FFMPEG解封装(flv,mp4,rmvb,avi)功能的结构体 // ffmpeg取rtsp流时av_read_frame阻塞的解决办法 设置参数优化 AVDictionary* avdic = NULL; av_dict_set(&avdic, "buffer_size", "102400", 0); //设置缓存大小,1080p可将值调大 av_dict_set(&avdic, "rtmp_transport", "tcp", 0); //以udp方式打开,如果以tcp方式打开将udp替换为tcp av_dict_set(&avdic, "stimeout", "2000000", 0); //设置超时断开连接时间,单位微秒 av_dict_set(&avdic, "max_delay", "300000", 0); //设置最大时延 ///rtsp地址,可根据实际情况修改 char *url; // QString ab = "C:/Users/goby/Desktop/Video_left.mp4";rtsp_address url= addrest.toLocal8Bit().data(); // qDebug() << url << "url"<<addrest; 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; } videoStream = -1; // 确定流格式是否为视频 for (i = 0; i < pFormatCtx->nb_streams; i++) { if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { videoStream = i; break; } } ///如果videoStream为-1 说明没有找到视频流 if (videoStream == -1) { qDebug("Didn't find a video stream.\n"); return; } ///查找解码器 pCodecCtx = pFormatCtx->streams[videoStream]->codec; pCodec = avcodec_find_decoder(pCodecCtx->codec_id); // 根据编码器的ID号查找对应的解码器 pCodecCtx->bit_rate = 0; //码率 pCodecCtx->time_base.num = 1; //下面两行:一秒钟10帧 pCodecCtx->time_base.den = 10; pCodecCtx->frame_number = 1; //每包一个视频帧 if (pCodec == NULL) { qDebug("Codec not found.\n"); return; } // Initialize the AVCodecContext to use the given AVCodec if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) { qDebug("Could not open codec.\n"); return; } // alloc AVFrame 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, AV_PIX_FMT_RGB32, SWS_BICUBIC, NULL, NULL, NULL); numBytes = avpicture_get_size(AV_PIX_FMT_RGB32, pCodecCtx->width,pCodecCtx->height); out_buffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t)); // 将分配的内存空间给m_AVFrameRGB使用 avpicture_fill((AVPicture *) pFrameRGB, out_buffer, AV_PIX_FMT_RGB32, pCodecCtx->width, pCodecCtx->height); // 为AVPacket分别内存空间 int y_size = pCodecCtx->width * pCodecCtx->height; packet = (AVPacket *) malloc(sizeof(AVPacket)); //分配一个packet av_new_packet(packet, y_size); //分配packet的数据 int j=0; while (1) { j++; if (av_read_frame(pFormatCtx, packet) < 0) { qDebug() << "av_read_frame < 0"; break; //这里认为视频读取完了 } if (packet->stream_index == videoStream) { ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture,packet); if (ret < 0) { qDebug("decode error.\n"); return; } if (got_picture) {// 对解码视频帧进行缩放、格式转换等操作 sws_scale(img_convert_ctx,(uint8_t const * const *) pFrame->data,pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize); //把这个RGB数据 用QImage加载 QImage tmpImg((uchar *)out_buffer,pCodecCtx->width,pCodecCtx->height,QImage::Format_RGB32); QImage image = tmpImg.copy(); //把图像复制一份 传递给界面显示 emit output_imag(image); }else qDebug() << "got_picture < 0"; }else /*qDebug() << "packet->stream_index not video stream";*/ av_free_packet(packet); //释放资源,否则内存会一直上升 } //对MyFFmpegInit接口中申请的资源进行释放操作 av_free(out_buffer); av_free(pFrameRGB); avcodec_close(pCodecCtx); avformat_close_input(&pFormatCtx); }

相关文章