ffmpeg拉取rtsp视频流
公司项目需要提供实时显示网络摄像头实时视频.
void RTSPFFmpeg::rtsp_open(const char *url) { AVFormatContext* format_ctx = avformat_alloc_context(); AVCodecContext *pAVCodecContext_video = nullptr; AVCodec *pAVCodec_video = nullptr; AVCodecParameters *pAVCodePar_video = avcodec_parameters_alloc(); AVPacket *pAVPacket = av_packet_alloc(); ; // ffmpeg单帧数据包 AVFrame *pAVFrame_video = av_frame_alloc(); // ffmpeg单帧缓存 AVFrame *pAVFrameRGB32_video = av_frame_alloc(); // ffmpeg单帧缓存转换颜色空间后的缓存 AVCodecParserContext *pAVCodeParseContext_video = nullptr; struct SwsContext *pSwsContext_video = nullptr; // ffmpeg编码数据格式转换 AVDictionary * opts = nullptr; int ret = -1; int numBytes = 0; // 解码后的数据长度 u_char *outBuffer = nullptr; // 解码后的数据存放缓存区 // open rtsp: Open an input stream and read the header. The codecs are not opened //const char* url = "rtsp://admin:genepoint2020@192.168.100.14:554/cam/realmonitor?channel=1&subtype=0"; av_dict_set(&opts, "rtsp_transport", "tcp", 0); av_dict_set(&opts, "stimeout", "2000000", 0); // audio/video stream index int video_stream_index = -1; ret = avformat_open_input(&format_ctx, url, nullptr, &opts); if (ret != 0) { fprintf(stderr, "fail to open url: %s, return value: %d\n", url, ret); continue; } // Read packets of a media file to get stream information ret = avformat_find_stream_info(format_ctx, nullptr); if (ret < 0) { fprintf(stderr, "fail to get stream information: %d\n", ret); continue; } fprintf(stdout, "Number of elements in AVFormatContext.streams: %d\n", format_ctx->nb_streams); for (int i = 0; i < format_ctx->nb_streams; ++i) { const AVStream *stream = format_ctx->streams[i]; fprintf(stdout, "type of the encoded data: %d\n", stream->codecpar->codec_id); if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { video_stream_index = i; // 对找到的视频流寻解码器 pAVCodePar_video = stream->codecpar; pAVCodec_video = avcodec_find_decoder(stream->codecpar->codec_id); if (!pAVCodec_video) { video_stream_index = -1; break; } pAVCodeParseContext_video = av_parser_init(pAVCodec_video->id); if (!pAVCodeParseContext_video) { video_stream_index = -1; break; } pAVCodecContext_video = avcodec_alloc_context3(pAVCodec_video); if (!pAVCodecContext_video) { } if (avcodec_open2(pAVCodecContext_video, pAVCodec_video, NULL) < 0) { video_stream_index = -1; break; } fprintf(stdout, "dimensions of the video frame in pixels: width: %d, height: %d, pixel format: %d\n", stream->codecpar->width, stream->codecpar->height, stream->codecpar->format); } } if (video_stream_index == -1) { fprintf(stderr, "no video stream\n"); continue; } // 对拿到的原始数据格式进行缩放转换为指定的格式高宽大小 pSwsContext_video = sws_getContext( pAVCodePar_video->width, pAVCodePar_video->height, static_cast<AVPixelFormat>(pAVCodePar_video->format), pAVCodePar_video->width, pAVCodePar_video->height, AV_PIX_FMT_RGBA, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr ); numBytes = av_image_get_buffer_size( AV_PIX_FMT_RGBA, pAVCodePar_video->width, pAVCodePar_video->height, 1 ); outBuffer = (u_char *) av_malloc(numBytes); // pAVFrame32的data指针指向了outBuffer av_image_fill_arrays( pAVFrameRGB32_video->data, pAVFrameRGB32_video->linesize, outBuffer, AV_PIX_FMT_RGBA, pAVCodePar_video->width, pAVCodePar_video->height, 1 ); while (1) { ret = av_read_frame(format_ctx, pAVPacket); if (ret < 0) { fprintf(stderr, "error or end of file: %d\n", ret); continue; } if (pAVPacket->stream_index == video_stream_index) { // fprintf(stdout, "video stream, packet size: %d\n", pAVPacket->size); ret = avcodec_send_packet(pAVCodecContext_video,pAVPacket); if( 0 != ret){ continue; } while (avcodec_receive_frame(pAVCodecContext_video,pAVFrame_video) == 0){ sws_scale(pSwsContext_video, (const uint8_t * const *)pAVFrame_video->data, pAVFrame_video->linesize, 0, pAVCodePar_video->height, pAVFrameRGB32_video->data, pAVFrameRGB32_video->linesize); QImage image((u_char*)outBuffer,pAVCodePar_video->width,pAVCodePar_video->height,QImage::Format_RGBA8888); emit rtsp_image_sig(image); } } av_packet_unref(pAVPacket); } av_parser_close(pAVCodeParseContext_video); av_frame_free(&pAVFrame_video); av_frame_free(&pAVFrameRGB32_video); av_free(outBuffer); av_free(pSwsContext_video); avcodec_free_context(&pAVCodecContext_video); avformat_close_input(&format_ctx); }