windows下使用camera (ffmpeg dshow方式)

news/2025/2/25 18:44:22

方法概要:先读取camera支持的mode,然后用ffmpeg dshow打开camera并解码压缩流

一.  用相关代码读取本地camera当前支持的输出mode,方便后续选择mode来打开camera:

bool EnumerateCameras(vector<int>& camIdx)
{
    camIdx.clear();
    struct CapDriver {
        int enumValue; string enumName; string comment;
    };
    // list of all CAP drivers (see highgui_c.h)
    vector<CapDriver> drivers;
    drivers.push_back({ CV_CAP_MIL, "CV_CAP_MIL", "MIL proprietary drivers" });
    drivers.push_back({ CV_CAP_VFW, "CV_CAP_VFW", "platform native" });
    drivers.push_back({ CV_CAP_FIREWARE, "CV_CAP_FIREWARE", "IEEE 1394 drivers" });
    drivers.push_back({ CV_CAP_STEREO, "CV_CAP_STEREO", "TYZX proprietary drivers" });
    drivers.push_back({ CV_CAP_QT, "CV_CAP_QT", "QuickTime" });
    drivers.push_back({ CV_CAP_UNICAP, "CV_CAP_UNICAP", "Unicap drivers" });
    drivers.push_back({ CV_CAP_DSHOW, "CV_CAP_DSHOW", "DirectShow (via videoInput)" });
    drivers.push_back({ CV_CAP_MSMF, "CV_CAP_MSMF", "Microsoft Media Foundation (via videoInput)" });
    drivers.push_back({ CV_CAP_PVAPI, "CV_CAP_PVAPI", "PvAPI, Prosilica GigE SDK" });
    drivers.push_back({ CV_CAP_OPENNI, "CV_CAP_OPENNI", "OpenNI (for Kinect)" });
    drivers.push_back({ CV_CAP_OPENNI_ASUS, "CV_CAP_OPENNI_ASUS", "OpenNI (for Asus Xtion)" });
    drivers.push_back({ CV_CAP_ANDROID, "CV_CAP_ANDROID", "Android" });
    drivers.push_back({ CV_CAP_ANDROID_BACK, "CV_CAP_ANDROID_BACK", "Android back camera" }),
    drivers.push_back({ CV_CAP_ANDROID_FRONT, "CV_CAP_ANDROID_FRONT", "Android front camera" }),
    drivers.push_back({ CV_CAP_XIAPI, "CV_CAP_XIAPI", "XIMEA Camera API" });
    drivers.push_back({ CV_CAP_AVFOUNDATION, "CV_CAP_AVFOUNDATION", "AVFoundation framework for iOS" });
    drivers.push_back({ CV_CAP_GIGANETIX, "CV_CAP_GIGANETIX", "Smartek Giganetix GigEVisionSDK" });
    drivers.push_back({ CV_CAP_INTELPERC, "CV_CAP_INTELPERC", "Intel Perceptual Computing SDK" });

    std::string winName, driverName, driverComment;
    int driverEnum;
    Mat frame;
    bool found;
    qDebug() << "Searching for cameras IDs..." << endl << endl;
    for (int drv = 0; drv < drivers.size(); drv++)
    {
        driverName = drivers[drv].enumName;
        driverEnum = drivers[drv].enumValue;
        driverComment = drivers[drv].comment;
        qDebug() << "Testing driver " << QString(driverName.c_str()) << "...";
        found = false;

        int maxID = 100; //100 IDs between drivers
        if (driverEnum == CV_CAP_VFW)
            maxID = 10; //VWF opens same camera after 10 ?!?
        else if (driverEnum == CV_CAP_ANDROID)
            maxID = 98; //98 and 99 are front and back cam
        else if ((driverEnum == CV_CAP_ANDROID_FRONT) || (driverEnum == CV_CAP_ANDROID_BACK))
            maxID = 1;

        for (int idx = 0; idx < maxID; idx++)
        {
            VideoCapture cap(driverEnum + idx);  // open the camera
            if (cap.isOpened())                  // check if we succeeded
            {
                found = true;
                camIdx.push_back(driverEnum + idx);  // vector of all available cameras
                cap >> frame;
                if (frame.empty())
                    qDebug() <<  QString(driverName.c_str()) << "+" << idx << "\t opens: OK \t grabs: FAIL";
                else
                    qDebug() << QString(driverName.c_str()) << "+" << idx << "\t opens: OK \t grabs: OK";
                // display the frame
                // imshow(driverName + "+" + to_string(idx), frame); waitKey(1);
            }
            cap.release();
        }
        if (!found) qDebug() << "Nothing !" << endl;
        qDebug() << endl;
    }
    qDebug() << camIdx.size() << " camera IDs has been found ";
    qDebug() << "Press a key..." << endl; cin.get();

    return (camIdx.size() > 0); // returns success
}

 

二.  直接使用ffmpeg库的dshow来打开camera

    //1. 设置摄像头参数并打开,通过dshow从camera中读取h264流。如果是低分辨率可以直接读取yuv,如果中等分辨率可用MJPG,如果是高分辨率,选择使用h264,以确保camera能有足够带宽输出Raw或压缩数据。设置camera

     avdevice_register_all();

    AVCodecID id = AV_CODEC_ID_H264;
    AVInputFormat* input_format = av_find_input_format("dshow");
    AVFormatContext* format_context = avformat_alloc_context();
    format_context->video_codec_id = id;

    AVDictionary* dict = nullptr;

    char resolution[128], fps[128], deviceIndex[128];
    sprintf(resolution, "%dx%d", CAP_WIDTH, CAP_HEIGHT);
    sprintf(fps, "%d", CAP_FPS);
    sprintf(deviceIndex, "%d", count);
    if (av_dict_set(&dict, "vcodec", "h264", 0) < 0)          fprintf(stderr, "fail to av_dict_set: line: %d\n", __LINE__);
    if (av_dict_set(&dict, "video_size", resolution, 0) < 0) fprintf(stderr, "fail to av_dict_set: line: %d\n", __LINE__);
    if (av_dict_set(&dict, "r", fps, 0) < 0)                 fprintf(stderr, "fail to av_dict_set: line: %d\n", __LINE__);
    if (av_dict_set(&dict, "video_device_number", deviceIndex, 0) < 0) fprintf(stderr, "fail to av_dict_set: line: %d\n", __LINE__);
    if (av_dict_set(&dict, "rtbufsize", "10M", 0) < 0)       fprintf(stderr, "fail to av_dict_set: line: %d\n", __LINE__);
    int ret = avformat_open_input(&format_context, "video=HD Pro Webcam C920", input_format, &dict);
    if (ret != 0) {
        fprintf(stderr, "fail to avformat_open_input: %d\n", ret);
        return;
    }
    ret = avformat_find_stream_info(format_context, nullptr);
    if (ret < 0) {
        fprintf(stderr, "fail to get stream information: %d\n", ret);
        return;
    }
    int video_stream_index = -1;
    for (unsigned int i = 0; i < format_context->nb_streams; ++i) {
        const AVStream* stream = format_context->streams[i];
        if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            video_stream_index = i;
            fprintf(stdout, "type of the encoded data: %d, dimensions of the video frame in pixels: width: %d, height: %d, pixel format: %d\n",
                stream->codecpar->codec_id, stream->codecpar->width, stream->codecpar->height, stream->codecpar->format);
        }
    }
    if (video_stream_index == -1) {
        fprintf(stderr, "no video stream\n");
        return;
    }
    fprintf(stdout, "frame rate: %f\n", av_q2d(format_context->streams[video_stream_index]->r_frame_rate));

    // 2. 初始化 h264编解码器
    AVCodec* encoder_id = avcodec_find_encoder(id);
    AVCodec* decoder_id = avcodec_find_decoder(id);
    if (!encoder_id || !decoder_id) {
        fprintf(stderr, "codec not found: %d\n", id);
        return;
    }
    AVCodecParameters* codecpar = format_context->streams[video_stream_index]->codecpar;
    const AVCodec* codec = avcodec_find_decoder(codecpar->codec_id);
    if (!codec) {
        fprintf(stderr, "fail to avcodec_find_decoder\n");
        return ;
    }
    if (codecpar->codec_id != id) {
        fprintf(stderr, "this test code only support mjpeg encode: %d\n", codecpar->codec_id);
        return;
    }
    AVCodecContext* codec_context = avcodec_alloc_context3(codec);
    if (!codec_context) {
        fprintf(stderr, "fail to avcodec_alloc_context3\n");
        return ;
    }
    codec_context->pix_fmt = AVPixelFormat(codecpar->format);
    codec_context->height = codecpar->height;
    codec_context->width = codecpar->width;
    codec_context->thread_count = 16;
    ret = avcodec_open2(codec_context, codec, nullptr);
    if (ret != 0) {
        fprintf(stderr, "fail to avcodec_open2: %d\n", ret);
        return;
    }
    
    AVPixelFormat dst_pixel_format = AV_PIX_FMT_BGR24;
    AVFrame* frame = av_frame_alloc();
    AVPacket* packet = (AVPacket*)av_malloc(sizeof(AVPacket));
    SwsContext* sws_context = sws_getContext(codec_context->width, codec_context->height, codec_context->pix_fmt, 
                                             codec_context->width, codec_context->height, dst_pixel_format, 0,
                                             nullptr, nullptr, nullptr);
    if (!frame || !packet || !sws_context) {
        fprintf(stderr, "fail to alloc\n");
        return;
    }

    uint8_t* bgr_data[4];
    int bgr_linesize[4];
    av_image_alloc(bgr_data, bgr_linesize, codec_context->width, codec_context->height, dst_pixel_format, 1);
    cv::Mat mat(codec_context->height, codec_context->width, CV_8UC3);
    const char* winname = deviceIndex;
    cv::namedWindow(winname);

    while (captureEnabled) {
        ret = av_read_frame(format_context, packet);
        if (ret >= 0 && packet->stream_index == video_stream_index && packet->size > 0) {
            //fprintf(stderr, "avcodec_send_packet: pts:%lld, dts:%lld\n", packet->pts, packet->dts);
            ret = avcodec_send_packet(codec_context, packet);
            if (ret < 0) {
                fprintf(stderr, "##### fail to avcodec_send_packet: %d\n", ret);
                av_packet_unref(packet);
                continue;
            }

            ret = avcodec_receive_frame(codec_context, frame);
            if (ret < 0) {
                fprintf(stderr, "##### fail to avcodec_receive_frame: %d\n", ret);
                av_packet_unref(packet);
                continue;
            }

            sws_scale(sws_context, frame->data, frame->linesize, 0, codec_context->height, bgr_data, bgr_linesize);
            mat.data = bgr_data[0];
            cv::imshow(winname, mat);
            int waitTimeMs = 1000 / CAP_FPS - 10;  //encode consume 10 ms
            cv::waitKey(5);

            cv::Mat img_dst;
            cv::resize(mat, img_dst, cv::Size(CAP_WIDTH/8, CAP_HEIGHT/8), 0, 0, cv::INTER_LINEAR);
            QImage image = Mat2QImageNew(img_dst);
            emit thread_update_image(count, image);

        }else if (ret < 0 || packet->size <= 0) {
            fprintf(stderr, "##### fail to av_read_frame: %d, packet size: %d\n", ret, packet->size);
            continue;
        }
        av_packet_unref(packet);

        //int key = cv::waitKey(30);
        //if (key == 27) break;
    }

    if (!captureEnabled) {
        cv::destroyWindow(winname);
        sws_freeContext(sws_context);
        av_frame_free(&frame);
        av_freep(packet);
        av_freep(&bgr_data[0]);
        avformat_close_input(&format_context);
        av_dict_free(&dict);
    }


http://www.niftyadmin.cn/n/4598698.html

相关文章

根据匹配词个数排序

法一&#xff1a; select title,(case when CHARINDEX(Log4net,title)>0 then 1 else 0 end )(case when CHARINDEX(oracle,title)>0 then 1 else 0 end ) counts from T_KNOWLEDGE where title like %Log4net% or title like %oracle% order by counts desc 法二&#x…

流媒体服务器原理和架构解析

原文&#xff1a; https://blog.csdn.net/xuheazx/article/details/52020933 一个完整的多媒体文件是由音频和视频两部分组成的&#xff0c;H264、Xvid等就是视频编码格式&#xff0c;MP3、AAC等就是音频编码格式&#xff0c;字幕文件只是附加文件。目前大部分的播放器产品对于…

ffmepg 音频重采样

因为业务需要&#xff0c;直播推流过程中&#xff0c;pcm的音频需要从48k采样率&#xff0c;重采样到44.1k&#xff0c;然后再编码程aac&#xff0c;封装成rtmp推送出去。这里只描述如何做pcm数据的重采样。 整个过程中&#xff0c;音频输入&#xff1a;PCM/S16/48000/2 重采…

webrtc 学习要点

总结一下webrtc的关键技术&#xff0c;如果搞懂了以下问题&#xff0c;webrtc应该算基本掌握了 1. 通话建立的大概流程。 a&#xff09;收集建立点对点的 IP candidates &#xff08;local&#xff0c; srvReflex&#xff0c;peerReflex&#xff0c; relay&#xff09;&#…

linux bash启动停止脚本,第二弹

本文是之前的watchdate的shell脚本的改进wdate,同样先上图:1)脚本加入chkconfig管理head -5 /etc/init.d/wdate #!/bin/bash #auth:chentp0601qq.com # #wdate Start/Stop the watchdate daemon # # chkconfig: 2345 71 55chkconfig --add wdate2)开始贴代码#!/bin/bas…

《实时控制软件设计》第一个编程作业

题目&#xff1a; 第一步&#xff1a; 写一个根据输入坐标生成一个平面图形&#xff08;点、线段和三角形&#xff09;并能对该几何图形进行平移和旋转操作的命令行 “软件”&#xff0c;要求&#xff1a;a) 通过命令行输入图形的名称&#xff0c;端点数&#xff08;1为点&…

ubuntutu下adb环境变量设置

2019独角兽企业重金招聘Python工程师标准>>> Ubuntu 下设置adb环境变量 分类: 同Windows一样&#xff0c;Ubuntu Linux系统包含两类环境变量&#xff1a;系统环境变量和用户环境变量。系统环境变量对所有系统用户都有效&#xff0c;用户环境变量仅仅对当前的用户有效…

Could not create the view An unexpected exception……的问题

问题&#xff1a; 电脑突然断电&#xff0c;myeclipse非正常关闭&#xff0c;“Package Explorer”非正常显示&#xff0c;出现错误“Could not create the view: An unexpected exception was thrown.”。但是项目中的文件可以通过命令查看。 解决方式&#xff1a; 关闭myec…