视频基础知识介绍

一、图像的基本概念

视频:

  • 由一组图像组成
  • 为了传输/占用更小的空间而被压缩
  • 最终在显示设备上展示(未被压缩)

图像:

  • 图像由像素组成,像素由RGB组成
  • 分辨率:横向的像素点 * 纵向的像素点
    每个像素的位深:
  • RGB888(24位),每个颜色都是8位
  • RGBA(32位),其中A表示alpha(8位),表示透明度

屏幕指标:

  • PPI:屏幕的质量,一寸长的空间放了多少像素点
  • DPI:每英寸的点数,基本上 DPI = PPI
  • PPI>300就属于视网膜级别,人眼区分不出来,认为是一体的

二、码流的计算

分辨率:

  • X轴的像素个数*Y轴的像素个数
  • 常见的宽高比 16:9 / 4:3
  • 360P(640*360)/720P/1K/2K 16:9

帧率:

  • 每秒钟采集/播放的图像的个数
  • 动画的帧率是25帧/s
  • 常见的帧率:15帧/s,30帧/s,60帧/s

未编码的视频 RGB的码流:

  • RGB码率 = 分辨率(宽*高)x3(Byte)x 帧率(25帧)
  • 列如: 12807203*25 = 69120000 约69M
  • 通常我们说的码流是以位为单位的。即69M*8=552Mbit

三、什么是YUV

为什么使用YUV:

  • 显示器从黑白显示器演变过来的,为了和以前格式兼容
  • YUV存储的数据比RGB要少很多。

YUV:

  • YUV(也称YCbCr):Y表示明亮度,UV的作用是描述影像色彩及饱和度。
  • 主要的采样格式有YUV4:2:0、YUV4:2:2和YUV4:4:4,YUV420 是标准格式。

RGB与YUV的关系:

  • RGB用于屏幕图像的展示
  • YUV用于采集与编码

RGB转YUV:
在这里插入图片描述
YUV转RGB:
在这里插入图片描述

四、YUV的常见格式

  • YUV4:4:4
  • YUV4:2:2
  • YUV4:2:0
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

YUV4:2:0的数据量的计算:

  • YUV = Y * 1.5
  • YUV = RGB / 2

五、YUV的存储格式

在这里插入图片描述
YUV存储格式:

  • planar(平面)
    I420 : YYYYYYYY UU VV -> YUV420P
    YV12: YYYYYYYY VV UU -> YUV420P
  • packed(打包)
    **NV12:**YYYYYYYY UVUV -> YUV420SP
    **NV21:**YYYYYYYY VUVU -> YUV420SP
    以上两个的主要区别是先存U还是先存V。IOS是YV12格式存储的;android系统一般都是NV21存储。

未编码视频的YUV码流:

  • RGB码流 = 分辨率(宽 x 高)x 3 x 帧率
  • YUV码流 = 分辨率(宽 x 高)x 1.5 x 帧率(YUV420)

YUV 参考资料: https://en.wikipedia.org/wiki/YUV

六、YUV实战

生成 YUV:

ffmpeg -i input.mp4 \
-an \
-c:v rawvideo \
-pix_fmt yuv420p out.yuv

-i 输入文件
-an a表示音频,n关闭,过滤音频
-c:v rawvideo 使用rawvideo对视频处理
-pix_fmt: 像素格式
out.yuv 输出文件

播放YUV文件:

ffplay -pix_fmt yuv420p -s 1280*720 out.yuv

播放Y分量:

ffplay -pix_fmt yuv420p -s 1280*720 -vf extractplanes='y' out.yuv

提取各分量:

ffmpeg.exe -i "周深-大鱼 (《大鱼海棠》电影印象曲)(超清).mp4" 
-filter_complex 
"extractplanes=y+u+v[y][u][v]" 
-map "[y]" y.yuv 
-map "[u]" u.yuv 
-map "[v]" v.yuv

播放各分量:

ffplay.exe -s 1280*720 -pix_fmt gray y.yuv

ffplay.exe -s 640*360 -pix_fmt gray u.yuv

ffplay.exe -s 640*360 -pix_fmt gray v.yuv

完整的示例代码:

#include <iostream>

using namespace std;

//包含ffmpeg头文件
extern "C"
{
#include "libavutil/avutil.h"
#include "libavdevice/avdevice.h"
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libswresample/swresample.h"
#include "libavutil/audio_fifo.h"
}

#include <windows.h>
#include <vector>
#include <string>
#include <memory>

using std::vector;
using std::string;
using std::shared_ptr;

/**
 * @brief open audio device
 * @param audio device name
 * @return succ: AVFormatContext*, fail: nullptr
 */
AVFormatContext *open_dev(void)
{
    int ret = 0;
    char errors[1024];
    AVFormatContext *fmt_ctx = nullptr;
    AVDictionary *options = nullptr;

    //get format
    //录制摄像头
    string sDeviceName = "video=HD Camera";
    const AVInputFormat *iformat = av_find_input_format("dshow");

    //录制桌面
    //string sDeviceName = "desktop";
    //const AVInputFormat *iformat = av_find_input_format("gdigrab");

    //录制摄像头
    //string sDeviceName = "0";
    //const AVInputFormat *iformat = av_find_input_format("vfwcap");

    av_dict_set(&options, "video_size", "640x480", 0);
    av_dict_set(&options, "framerate", "30", 0);
    av_dict_set(&options, "pixel_format", "yuyv422", 0);

    //open device
    if ((ret = avformat_open_input(&fmt_ctx, sDeviceName.data(),
        iformat, &options)) < 0) {
        av_strerror(ret, errors, 1024);
        printf("Failed to open video device, [%d]%s\n", ret, errors);
        return nullptr;
    }

    return fmt_ctx;
}

void rec_video()
{
    AVFormatContext *fmt_ctx = nullptr;
    AVPacket pkt;
    int ret = 0;
    int count = 0;

    //set log level
    av_log_set_level(AV_LOG_DEBUG);

    //create file
    FILE *outfile = fopen("D:/Study/ffmpeg/av_base/video.yuv", "wb");
    if (! outfile) {
        printf("Error, Failed to open file!\n");
        goto __ERROR;
    }

    //register audio device
    avdevice_register_all();

    //打开设备
    fmt_ctx = open_dev();
    if (! fmt_ctx) {
        printf("Error, Failed to open device!\n");
        goto __ERROR;
    }

    //read data from device
    while((ret = av_read_frame(fmt_ctx, &pkt)) == 0) {
        av_log(nullptr, AV_LOG_INFO,
               "packet size is %d\n", pkt.size);

        fwrite(pkt.data, 1, static_cast<size_t>(pkt.size), outfile);
        fflush(outfile);
        av_packet_unref(&pkt);

        if ( count++ >= 50)
            break;
    }

__ERROR:
    //close device and release ctx
    if (fmt_ctx) {
        avformat_close_input(&fmt_ctx);
    }

    //close file
    if (outfile) {
        fclose(outfile);
    }

    av_log(nullptr, AV_LOG_DEBUG, "finish!\n");

    return;
}

int main()
{
    rec_video();

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值