FFmpeg将图像数据编码为H264视频

图片数据编码为视频的步骤如下:
1、 BGR数据转换为YUV格式;
2.、YUV格式进行编码;

其中对YUV格式进行编码又分为以下步骤:

  1. 通过avcodec_find_encoder函数找到需要的编码器;
  2. 通过avcodec_alloc_context3初始化编码器上下文,并设置编码器上下文的参数(包括码率、时间基、视频宽高等);
  3. 通过avcodec_open2函数打开编码器;
  4. 通过avformat_alloc_output_context2函数初始化输出文件上下文;
  5. 通过avformat_new_stream函数新建一个视频流,并通过avcodec_parameters_from_context函数拷贝编码器的参数;
  6. 通过avio_open函数打开输出文件;
  7. 通过avformat_write_header写文件头;
  8. 循环处理YUV数据:
    ①将YUV帧通过avcodec_send_frame发送给编码器;
    ②并通过avcodec_receive_packet取出编码后的数据;
    ③通过函数av_packet_rescale_ts将时间戳缩放到输出流的时间基上;
    ④并将处理后的包通过av_interleaved_write_frame函数写入文件;
  9. 通过av_write_trailer函数写入文件尾,并关闭编码器等。

完整代码如下:

// muxer.h
#pragma once
#include <memory>

class AVFrame;
class AVStream;
class AVCodecContext;
class AVFormatContext;

class muxer
{
   
public:
	muxer();
	~muxer();

	bool init(int w, int h, int fps, int bit_rate, char* outfile_name);
	void uninit();
	bool write_image(const uint8_t* bgr);
	bool write_yuv(const uint8_t* yuv_data);
	bool write_frame(const AVFrame* frame);
	bool flush();

private:
	bool bgr_to_yuv420p(const uint8_t* const buf_bgr, uint8_t* const buf_420p);

private:
	int width_;
	int height_;
	int y_size_;
	int uv_size_;
	int pts_;
	AVCodecContext* codec_ctx_;
	AVFormatContext* fmt_ctx_;
	AVStream* out_stream_;
	AVFrame* yuv_frame_;
};

// muxer.cpp
#include "muxer.h"
#include <tuple>
#include <array>
#include <vector>
extern "C" {
   
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/opt.h>
#include <libavutil/timestamp.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
}


muxer::muxer()
	:width_{
   },
	height_{
   },
	y_size_{
   },
	uv_size_{
   },
	pts_{
   },
	codec_ctx_{
    nullptr },
	fmt_ctx_{
    nullptr },
	out_stream_{
    nullptr },
	yuv_frame_{
    nullptr }
{
   
}

muxer::~muxer()
{
   
	uninit();
}


bool muxer::init(int w, int h, int fps, int bit_rate, char* outfile_name)
{
   
	uninit();

	width_ = w
  • 3
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是使用CUDA将摄像头读取的数据编码H264流的示例代码,使用了NVIDIA Video Codec SDK和OpenCV库: ```cpp #include <iostream> #include <opencv2/opencv.hpp> #include "NvEncoder/NvEncoderCuda.h" using namespace std; using namespace cv; int main(int argc, char* argv[]) { // 从摄像头读取数据 VideoCapture cap(0); if (!cap.isOpened()) { cout << "Failed to open camera!" << endl; return -1; } // 设置编码器参数 int nWidth = 640, nHeight = 480; int nBitrate = 1000000; int nFps = 30; int nGopSize = 30; int nMaxConcurrentSessions = 1; int nCodec = NV_ENC_H264; std::string sPreset = "hq"; std::string sProfile = "high"; NvEncoderInitParam encodeParams = { 0 }; encodeParams.width = nWidth; encodeParams.height = nHeight; encodeParams.bitrate = nBitrate; encodeParams.fps = nFps; encodeParams.gopSize = nGopSize; encodeParams.codec = nCodec; encodeParams.preset = const_cast<char*>(sPreset.c_str()); encodeParams.profile = const_cast<char*>(sProfile.c_str()); encodeParams.maxConcurrentSessions = nMaxConcurrentSessions; NvEncoderCuda enc(encodeParams); // 分配编码器缓冲区 int nFrameSize = enc.GetFrameSize(); uint8_t* pFrame = new uint8_t[nFrameSize]; uint8_t* pBitstream = new uint8_t[nFrameSize]; // 编码并输出h264流 Mat frame; while (true) { // 读取一帧图像 cap >> frame; if (frame.empty()) { break; } // 将帧数据复制到CUDA缓冲区 uint8_t* dpFrame = NULL; int nPitch = 0; enc.GetDeviceFrameBuffer(&dpFrame, &nPitch); cudaMemcpy2D(dpFrame, nPitch, frame.data, frame.step, nWidth * 3, nHeight, cudaMemcpyHostToDevice); // 编码一帧图像 int nBytes = 0; enc.EncodeFrame(pFrame, &nBytes, dpFrame); // 将编码后的数据复制回主机内存 cudaMemcpy(pBitstream, enc.GetBitstreamBuffer(), nBytes, cudaMemcpyDeviceToHost); // 输出h264流 fwrite(pBitstream, sizeof(uint8_t), nBytes, stdout); } // 释放资源 enc.DestroyEncoder(); delete[] pFrame; delete[] pBitstream; return 0; } ``` 在编译时需要链接NVIDIA Video Codec SDK和OpenCV库。执行程序后,它将从摄像头读取数据并将其编码为H264流输出到标准输出。你可以将输出重定向到文件中,例如: ``` ./encode | ffmpeg -i - output.mp4 ``` 这将从标准输入读取H264流,并将其换为MP4文件。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值