• 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
    ", 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
    ", ret);
    continue;
            }
    
            fprintf(stdout, "Number of elements in AVFormatContext.streams: %d
    ", 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
    ", 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:  %d, height: %d, pixel format: %d
    ",
                            stream->codecpar->width, stream->codecpar->height, stream->codecpar->format);
                }
            }
            if (video_stream_index == -1) {
                fprintf(stderr, "no video stream
    ");
    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
    ", ret);
    continue;
            }
            if (pAVPacket->stream_index == video_stream_index) {
    //            fprintf(stdout, "video stream, packet size: %d
    ", 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);
    }
  • 相关阅读:
    Banner实现无线轮播
    二维码生成
    自定义View圆环
    百度地图
    OkHttp解析
    自定义控件生成随机数
    OkHttp中文文档
    Da购物车
    Angular过滤器
    popupWindow
  • 原文地址:https://www.cnblogs.com/ohsolong/p/14419291.html
Copyright © 2020-2023  润新知