FFmepg--视频编码流程--yuv编码为h264

2024-03-15 21:12

本文主要是介绍FFmepg--视频编码流程--yuv编码为h264,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

      • 基本概念
      • 流程
      • api
      • 核心代码

基本概念

YUV格式:是一种颜色编码方式,YUV分别为三个分量:‘Y’是明亮度,也就是灰度值;‘U’和‘V’是色度
YUV格式的分类:

  • planar的YUV格式:先存储planar的Y像素点,在依次存储U和V像素点
  • packed的YUV格式:交叉存储YUV像素点

YUV流的采样方式:

  • YUV4:4:4:表示一个Y分量对应一组UV分量。
  • YUV4:2:2:表示两个Y分量共用一组UV分量。
  • YUV4:2:0:表示四个Y分量共用一组UV分量。

流程

请添加图片描述

api

  • int av_frame_get_buffer(AVFrame *frame, int align);
    为⾳频或视频数据分配新的buffer,使用完成后,需要将引用计数-1

  • int av_image_alloc(uint8_t *pointers[4], int linesizes[4], int w, int h, enum AVPixelFormat pix_fmt,int align):
    按照指定的宽、高、像素格式来分配图像内存,第一个参数为Frame的数据

  • int av_frame_make_writable(AVFrame *frame):

  • 检查AVFrame->data是否可写

  • int av_image_get_buffer_size(enum AVPixelFormat pix_fmt, int width, int height, int align):
    计算1帧数据的大小,参数为像素格式、图像宽、图像⾼,字节对齐方式

  • av_image_fill_arrays: 存储⼀帧像素数据存储到AVFrame对应的data buffer

核心代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>#include <libavcodec/avcodec.h>
#include <libavutil/time.h>
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>int64_t get_time()
{return av_gettime_relative() / 1000;  // 换算成毫秒
}
static int encode(AVCodecContext *enc_ctx, AVFrame *frame, AVPacket *pkt,FILE *outfile)
{int ret;/* send the frame to the encoder */ret = avcodec_send_frame(enc_ctx, frame);if (ret < 0){return -1;}while (ret >= 0){ret = avcodec_receive_packet(enc_ctx, pkt);if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {return 0;} else if (ret < 0) {return -1;}fwrite(pkt->data, 1, pkt->size, outfile);}return 0;
}int main(int argc, char **argv)
{char *in_yuv_file = NULL;char *out_h264_file = NULL;FILE *infile = NULL;FILE *outfile = NULL;const char *codec_name = NULL;const AVCodec *codec = NULL;AVCodecContext *codec_ctx= NULL;AVFrame *frame = NULL;AVPacket *pkt = NULL;int ret = 0;in_yuv_file = argv[1];      // 输入YUV文件out_h264_file = argv[2];codec_name = argv[3];/* 查找指定的编码器 */codec = avcodec_find_encoder_by_name(codec_name);if (!codec) {fprintf(stderr, "Codec '%s' not found\n", codec_name);exit(1);}codec_ctx = avcodec_alloc_context3(codec);if (!codec_ctx) {fprintf(stderr, "Could not allocate video codec context\n");exit(1);}/* 设置分辨率*/codec_ctx->width = 1280;codec_ctx->height = 720;/* 设置time base */codec_ctx->time_base = (AVRational){1, 25};codec_ctx->framerate = (AVRational){25, 1};/* 设置I帧间隔* 如果frame->pict_type设置为AV_PICTURE_TYPE_I, 则忽略gop_size的设置,一直当做I帧进行编码*/codec_ctx->gop_size = 25;   // I帧间隔codec_ctx->max_b_frames = 2; // 如果不想包含B帧则设置为0codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;//if (codec->id == AV_CODEC_ID_H264) {// 相关的参数可以参考libx264.c的 AVOption optionsav_opt_set(codec_ctx->priv_data, "preset", "medium", 0);av_opt_set(codec_ctx->priv_data, "profile", "main", 0);av_opt_set(codec_ctx->priv_data, "tune","zerolatency",0);}/** 设置编码器参数*//* 设置bitrate */codec_ctx->bit_rate = 3000000;/* 将codec_ctx和codec进行绑定 */avcodec_open2(codec_ctx, codec, NULL);// 打开输入和输出文件infile = fopen(in_yuv_file, "rb");outfile = fopen(out_h264_file, "wb");// 分配pkt和framepkt = av_packet_alloc();frame = av_frame_alloc();// 为frame分配bufferframe->format = codec_ctx->pix_fmt;frame->width  = codec_ctx->width;frame->height = codec_ctx->height;ret = av_frame_get_buffer(frame, 0);// 计算出每一帧的数据 像素格式 * 宽 * 高// 1382400int frame_bytes = av_image_get_buffer_size(frame->format, frame->width,frame->height, 1);uint8_t *yuv_buf = (uint8_t *)malloc(frame_bytes);// 作用int64_t begin_time = get_time();int64_t end_time = begin_time;int64_t all_begin_time = get_time();int64_t all_end_time = all_begin_time;int64_t pts = 0;printf("start enode\n");for (;;) {memset(yuv_buf, 0, frame_bytes);size_t read_bytes = fread(yuv_buf, 1, frame_bytes, infile);ret = av_frame_make_writable(frame);int need_size = av_image_fill_arrays(frame->data, frame->linesize, yuv_buf,frame->format,frame->width, frame->height, 1);pts += 40;// 设置pts 计算frame->pts = pts;       // 使用采样率作为pts的单位,具体换算成秒 pts*1/采样率begin_time = get_time();encode(codec_ctx, frame, pkt, outfile);end_time = get_time();printf("encode time:%lldms\n", end_time - begin_time);}/* 冲刷编码器 */encode(codec_ctx, NULL, pkt, outfile);all_end_time = get_time();printf("all encode time:%lldms\n", all_end_time - all_begin_time);// 关闭文件fclose(infile);fclose(outfile);// 释放内存if(yuv_buf) {free(yuv_buf);}av_frame_free(&frame);av_packet_free(&pkt);avcodec_free_context(&codec_ctx);printf("main finish, please enter Enter and exit\n");getchar();return 0;
}

这篇关于FFmepg--视频编码流程--yuv编码为h264的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/813273

相关文章

Python使用OpenCV实现获取视频时长的小工具

《Python使用OpenCV实现获取视频时长的小工具》在处理视频数据时,获取视频的时长是一项常见且基础的需求,本文将详细介绍如何使用Python和OpenCV获取视频时长,并对每一行代码进行深入解析... 目录一、代码实现二、代码解析1. 导入 OpenCV 库2. 定义获取视频时长的函数3. 打开视频文

Spring Security中用户名和密码的验证完整流程

《SpringSecurity中用户名和密码的验证完整流程》本文给大家介绍SpringSecurity中用户名和密码的验证完整流程,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定... 首先创建了一个UsernamePasswordAuthenticationTChina编程oken对象,这是S

Android ViewBinding使用流程

《AndroidViewBinding使用流程》AndroidViewBinding是Jetpack组件,替代findViewById,提供类型安全、空安全和编译时检查,代码简洁且性能优化,相比Da... 目录一、核心概念二、ViewBinding优点三、使用流程1. 启用 ViewBinding (模块级

SpringBoot整合Flowable实现工作流的详细流程

《SpringBoot整合Flowable实现工作流的详细流程》Flowable是一个使用Java编写的轻量级业务流程引擎,Flowable流程引擎可用于部署BPMN2.0流程定义,创建这些流程定义的... 目录1、流程引擎介绍2、创建项目3、画流程图4、开发接口4.1 Java 类梳理4.2 查看流程图4

java Long 与long之间的转换流程

《javaLong与long之间的转换流程》Long类提供了一些方法,用于在long和其他数据类型(如String)之间进行转换,本文将详细介绍如何在Java中实现Long和long之间的转换,感... 目录概述流程步骤1:将long转换为Long对象步骤2:将Longhttp://www.cppcns.c

spring-gateway filters添加自定义过滤器实现流程分析(可插拔)

《spring-gatewayfilters添加自定义过滤器实现流程分析(可插拔)》:本文主要介绍spring-gatewayfilters添加自定义过滤器实现流程分析(可插拔),本文通过实例图... 目录需求背景需求拆解设计流程及作用域逻辑处理代码逻辑需求背景公司要求,通过公司网络代理访问的请求需要做请

使用JavaConfig配置Spring的流程步骤

《使用JavaConfig配置Spring的流程步骤》JavaConfig是Spring框架提供的一种基于Java的配置方式,它通过使用@Configuration注解标记的类来替代传统的XML配置文... 目录一、什么是 JavaConfig?1. 核心注解2. 与 XML 配置的对比二、JavaConf

基于Go语言实现Base62编码的三种方式以及对比分析

《基于Go语言实现Base62编码的三种方式以及对比分析》Base62编码是一种在字符编码中使用62个字符的编码方式,在计算机科学中,,Go语言是一种静态类型、编译型语言,它由Google开发并开源,... 目录一、标准库现状与解决方案1. 标准库对比表2. 解决方案完整实现代码(含边界处理)二、关键实现细

Java对接Dify API接口的完整流程

《Java对接DifyAPI接口的完整流程》Dify是一款AI应用开发平台,提供多种自然语言处理能力,通过调用Dify开放API,开发者可以快速集成智能对话、文本生成等功能到自己的Java应用中,本... 目录Java对接Dify API接口完整指南一、Dify API简介二、准备工作三、基础对接实现1.

解决IDEA报错:编码GBK的不可映射字符问题

《解决IDEA报错:编码GBK的不可映射字符问题》:本文主要介绍解决IDEA报错:编码GBK的不可映射字符问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录IDEA报错:编码GBK的不可映射字符终端软件问题描述原因分析解决方案方法1:将命令改为方法2:右下jav