zoukankan      html  css  js  c++  java
  • 音视频之视频录制(十)

    MAC端录制视频

    命令行录制

    avfoundation支持的设备

    ffmpeg -f avfoundation -list_devices true -i ' '

    输出结果大致如下所示:

    [AVFoundation indev @ 0x7fd2d1804400] AVFoundation video devices:
    [AVFoundation indev @ 0x7fd2d1804400] [0] FaceTime HD Camera
    [AVFoundation indev @ 0x7fd2d1804400] [1] Capture screen 0
    [AVFoundation indev @ 0x7fd2d1804400] AVFoundation audio devices:
    [AVFoundation indev @ 0x7fd2d1804400] [0] Built-in Microphone
    [AVFoundation indev @ 0x7fd2d1804400] [1] 江波的AirPods


    0号设备就是Mac自带的摄像头

    avfoundation支持的参数

    ffmpeg -h demuxer=avfoundation

    输出结果大致如下所示:

    AVFoundation indev AVOptions:
      -list_devices      <boolean>    .D......... list available devices (default false)
      -video_device_index <int>        .D......... select video device by index for devices with same name (starts at 0) (from -1 to INT_MAX) (default -1)
      -audio_device_index <int>        .D......... select audio device by index for devices with same name (starts at 0) (from -1 to INT_MAX) (default -1)
      -pixel_format      <pix_fmt>    .D......... set pixel format (default yuv420p)
      -framerate         <video_rate> .D......... set frame rate (default "ntsc")
      -video_size        <image_size> .D......... set video size
      -capture_cursor    <boolean>    .D......... capture the screen cursor (default false)
      -capture_mouse_clicks <boolean>    .D......... capture the screen mouse clicks (default false)
      -capture_raw_data  <boolean>    .D......... capture the raw data from device connection (default false)
      -drop_late_frames  <boolean>    .D......... drop frames that are available later than expected (default true)
    • -video_size: 分辨率
    • -pixel_format: 像素格式
      • 默认是yuv420p
    • -framerate: 帧率(每秒菜鸡多少帧画面)
      • 默认是ntsc,也就是30000/1001,约等于29.970030
    • -list_device: true表示列出avfoundation支持的所有设备

    录制

    使用0号视频设备录制

    ffmpeg -f avfoundation -i 0 out.yuv

    然后你可能会遇到一个错误: 这个设备(摄像头)不支持29.970030的帧率

    Selected framerate (29.970030) is not supported by the device

    重新设置30的帧率试试 

    ffmpeg -f avfoundation -framerate 30 -i 0 out.yuv
    • 这个设备(摄像头)不支持yuv420p
    • 只支持uyvy422、yuyv422、nv12、0rgb、bgr0
    • 并且自动选择使用uyvy422替代yuv420p  
    Selected pixel format (yuv420p) is not supported by the input device.
    Supported pixel formats:
      uyvy422
      yuyv422
      nv12
      0rgb
      bgr0
    Overriding selected pixel format to use uyvy422 instead.

    与此同时,也成功开始采集摄像头的视频数据了。

    • 像素格式: uyvy422
    • 分辨率: 1280x720
    • 帧率: 30    
    Input #0, avfoundation, from '0':
        Stream #0:0: Video: rawvideo, uyvy422, 1280x720
    
    Output #0, rawvideo, to 'out.yuv':
        Stream #0:0: Video: rawvideo, uyvy422, 1280x720, 30 fps

    播放录制好的YUV

    ffplay -video_size 1280x720 -pixel_format uyvy422 -framerate 30 out.yuv

    编程录制视频

    依赖库

    需要依赖5个库

    extern "C" {
    // 设备相关API
    #include <libavdevice/avdevice.h>
    // 格式相关API
    #include <libavformat/avformat.h>
    // 工具(比如错误处理)
    #include <libavutil/avutil.h>
    // 编码相关的API
    #include <libavcodec/avcodec.h>
    #include <libavutil/imgutils.h>
    }

    宏定义

    #ifdef Q_OS_WIN
        // 格式名称
        #define FMT_NAME "dshow"
        // 设备名称
        #define DEVICE_NAME ""
        // PCM文件名
        #define FILEPATH "F:/"
    #else
        #define FMT_NAME "avfoundation"
        #define DEVICE_NAME ":0"
        #define FILEPATH "/Users/muzi/Desktop/out.yuv"
    #endif

    权限申请

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

    <?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>
            <key>NSMicrophoneUsageDescription</key>
            <string>申请使用您的麦克风权限</string>
    </dict>
    </plist>
    • 需要在Info.plist中添加摄像头、麦克风的使用说明,申请摄像头、麦克风的使用权限
    • 使用Debug模式运行程序
    • 不然会出现闪退的情况

    注册设备

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

     // 注册设备
     avdevice_register_all();

    获取输入格式对象

    // 获取输入格式对象
        AVInputFormat *fmt = av_find_input_format(FMT_NAME);
        if (!fmt) {
            qDebug() << "获取输入格式对象失败" << 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) {
            char errbuf[1024];
            av_strerror(ret, errbuf, sizeof (errbuf));
            qDebug() << "打开设备失败" << errbuf;
            return;
        }

    打开输出文件

    // 文件名
        QFile file(FILEPATH);
    
        // 打开文件
        // WriteOnly:只写模式。如果文件不存在,就创建文件;如果文件存在,就会清空文件内容
        if (!file.open(QFile::WriteOnly)) {
            qDebug() << "文件打开失败" ;
    
            // 关闭设备
            avformat_close_input(&ctx);
            return;
        }

    采集视频数据

    // 计算一帧的大小
        AVCodecParameters *params = ctx->streams[0]->codecpar;
        AVPixelFormat pixFmt = (AVPixelFormat) params->format;
    
        int imageSize = av_image_get_buffer_size(pixFmt,
                                                 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);
    
                // 释放资源
                av_packet_unref(pkt);
            } else if (ret == AVERROR(EAGAIN)) { // 资源临时不可用
                continue;
            } else { // 其他错误
                char errbuf[1024];
                av_strerror(ret, errbuf, sizeof (errbuf));
                qDebug() << "av_read_frame error" << errbuf << ret;
                break;
            }
    
            // 必须要加,释放pkt内部的资源
            av_packet_unref(pkt);
        }

    释放资源

    // 释放资源
        // 关闭文件
        file.close();
    
        // 释放资源
        av_packet_free(&pkt);
    
        // 关闭设备
        avformat_close_input(&ctx);
    
        qDebug() << this << "正常结束----------";
  • 相关阅读:
    mpvue: stylus定义主题色
    mpvue: 单个页面自定义导航栏或隐藏
    mpvue: fsevents is not a constructor
    Nginx:taro h5 Nginx代理配置
    git: 替换remote origin
    taro3.x: h5地图兼容组件封装
    taro3.x: h5地图兼容
    taro3.x: 使用taro-router在H5浏览器返回报错
    taro3.x: tarojs-router
    java线程与线程安全的单例模式
  • 原文地址:https://www.cnblogs.com/muzichenyu/p/15541730.html
Copyright © 2011-2022 走看看