zoukankan      html  css  js  c++  java
  • 【秒懂音视频开发】20_视频录制02_编程

    本文的主要内容:演示如何通过编程采集摄像头的视频数据。
    整体的流程跟《音频录制02_编程》类似。

    依赖库

    需要依赖4个库。

    extern "C" {
    #include <libavdevice/avdevice.h>
    #include <libavformat/avformat.h>
    #include <libavutil/avutil.h>
    #include <libavutil/imgutils.h>
    #include <libavcodec/avcodec.h>
    }
    

    宏定义

    #ifdef Q_OS_WIN
        // 格式名称
        #define FMT_NAME "dshow"
        // 设备名称
        #define DEVICE_NAME "video=Integrated Camera"
        // YUV文件名
        #define FILENAME "F:/out.yuv"
    #else
        #define FMT_NAME "avfoundation"
        #define DEVICE_NAME "0"
        #define FILENAME "/Users/mj/Desktop/out.yuv"
    #endif
    
    #define ERROR_BUF(ret) 
        char errbuf[1024]; 
        av_strerror(ret, errbuf, sizeof (errbuf));
    

    权限申请

    在Mac平台,有2个注意点:

    • 需要在Info.plist中添加摄像头的使用说明,申请摄像头的使用权限
    • 使用Debug模式运行程序
    • 不然会出现闪退的情况
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
            <key>NSCameraUsageDescription</key>
            <string>使用摄像头采集您的靓照</string>
    </dict>
    </plist>
    

    注册设备

    在整个程序的运行过程中,只需要执行1次注册设备的代码。

    // 初始化libavdevice并注册所有输入和输出设备
    avdevice_register_all();
    

    获取输入格式对象

    // 获取输入格式对象
    AVInputFormat *fmt = av_find_input_format(FMT_NAME);
    if (!fmt) {
        qDebug() << "av_find_input_format error" << FMT_NAME;
        return;
    }
    

    打开输入设备

    // 格式上下文
    AVFormatContext *ctx = nullptr;
    
    // 传递给输入设备的参数
    AVDictionary *options = nullptr;
    av_dict_set(&options, "video_size", "640x480", 0);
    av_dict_set(&options, "pixel_format", "yuyv422", 0);
    av_dict_set(&options, "framerate", "30", 0);
    
    // 打开输入设备
    int ret = avformat_open_input(&ctx, DEVICE_NAME, fmt, &options);
    if (ret < 0) {
        ERROR_BUF(ret);
        qDebug() << "avformat_open_input error" << errbuf;
        return;
    }
    

    打开输出文件

    // 打开文件
    QFile file(FILENAME);
    if (!file.open(QFile::WriteOnly)) {
        qDebug() << "file open error" << FILENAME;
    
        // 关闭输入设备
        avformat_close_input(&ctx);
        return;
    }
    

    采集视频数据

    // 计算每一帧的大小
    AVCodecParameters *params = ctx->streams[0]->codecpar;
    int imageSize = av_image_get_buffer_size(
                        (AVPixelFormat) params->format,
                        params->width, params->height,
                        1);
    
    // 数据包
    AVPacket *pkt = av_packet_alloc();
    while (!isInterruptionRequested()) {
        // 不断采集数据
        ret = av_read_frame(ctx, pkt);
    
        if (ret == 0) { // 读取成功
            // 将数据写入文件
            file.write((const char *) pkt->data, imageSize);
            /*
             这里要使用imageSize,而不是pkt->size。
             pkt->size有可能比imageSize大(比如在Mac平台),
             使用pkt->size会导致写入一些多余数据到YUV文件中,
             进而导致YUV内容无法正常播放
            */
    
            // 释放资源
            av_packet_unref(pkt);
        } else if (ret == AVERROR(EAGAIN)) { // 资源临时不可用
            continue;
        } else { // 其他错误
            ERROR_BUF(ret);
            qDebug() << "av_read_frame error" << errbuf;
            break;
        }
    }
    

    释放资源

    // 释放资源
    av_packet_free(&pkt);
    
    // 关闭文件
    file.close();
    
    // 关闭设备
    avformat_close_input(&ctx);
    
  • 相关阅读:
    Oracle 11g安装过程工作Oracle数据库安装图解
    Anaconda和虚拟环境
    NLP(三)
    Spring Cloud
    Flink 更新中
    Hadoop(四)小项目练习 更新中
    大数据环境搭建
    zookeeper
    .net(四) winform应用程序
    负载均衡中间件(二)LVS负载均衡软件和基于云计算平台的架构
  • 原文地址:https://www.cnblogs.com/mjios/p/14717480.html
Copyright © 2011-2022 走看看