FFmpeg-- c++实现:pcm和yuv编码

news/2024/7/10 18:56:22 标签: ffmpeg, c++, pcm

文章目录

      • 流程
        • 音频
        • 视频
      • api
      • 核心代码
        • audioencoder.h
        • audioencoder.cpp
        • videoencoder.h
        • videoencoder.cpp

pcm和yuv编码为aac和h264,封装为c++的AudioEncoder类和VideoEncoder类

流程

音频
  • 初始化音频参数
    int InitAAC(int channels, int sample_rate, int bit_rate);

  • 音频编码,pts需要转化为编码时的pts, 发送帧frame, 获取 packet
    AVPacket *Encode(AVFrame *farme, int stream_index, int64_t pts, int64_t time_base);

  • 获取一帧数据通道号的采样点
    int GetFrameSize()

  • 获取编码器需要的采样格式
    int GetSampleFormat()

  • 释放资源
    void DeInit();

视频
  • 初始化视频参数
    int InitH264(int width, int height, int fps, int bit_rate);

  • 视频编码,pts需要转化为编码时的pts, 需要初始化AVFrame结构体,发送帧frame, 获取 packet
    AVPacket *Encode(AVFrame *farme, int stream_index, int64_t pts, int64_t time_base);

  • 释放资源
    void DeInit();

api

  • 用于初始化一个AVFrame结构体,包括设置AVFrame中的各项参数,不需要重新分配buffer,需要传入一个指向AVFrame结构体的指针
int av_image_fill_arrays(uint8_t *dst_data[4], int dst_linesize[4],
                         const uint8_t *src,
                         enum AVPixelFormat pix_fmt, int width, int height, int align);

核心代码

audioencoder.h
#ifndef AUDIOENCODER_H
#define AUDIOENCODER_H

extern "C"
{
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
}
class AudioEncoder
{
public:
    AudioEncoder();
    ~AudioEncoder();
    int InitAAC(int channels, int sample_rate, int bit_rate);
//    int InitMP3(/*int channels, int sample_rate, int bit_rate*/);
    void DeInit();  // 释放资源
    AVPacket *Encode(AVFrame *farme, int stream_index, int64_t pts, int64_t time_base);
    int GetFrameSize(); // 获取一帧数据 每个通道需要多少个采样点
    int GetSampleFormat();  // 编码器需要的采样格式
private:
    int channels_ = 2;
    int sample_rate_ = 44100;
    int bit_rate_ = 128*1024;
    int64_t pts_ = 0;
    AVCodecContext * codec_ctx_ = NULL;
};

#endif // AUDIOENCODER_H

audioencoder.cpp
#include "audioencoder.h"

AudioEncoder::AudioEncoder()
{

}

AudioEncoder::~AudioEncoder()
{
    if(codec_ctx_) {
        DeInit();
    }
}

int AudioEncoder::InitAAC(int channels, int sample_rate, int bit_rate)
{
    channels_ = channels;
    sample_rate_ = sample_rate;
    bit_rate_ = bit_rate;

    AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
    if(!codec) {
        printf("avcodec_find_encoder AV_CODEC_ID_AAC failed\n");
        return -1;
    }
    codec_ctx_ = avcodec_alloc_context3(codec);
    if(!codec_ctx_) {
        printf("avcodec_alloc_context3 AV_CODEC_ID_AAC failed\n");
        return -1;
    }

    codec_ctx_->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
    codec_ctx_->bit_rate = bit_rate_;
    codec_ctx_->sample_rate = sample_rate_;
    codec_ctx_->sample_fmt = AV_SAMPLE_FMT_FLTP;
    codec_ctx_->channels = channels_;
    codec_ctx_->channel_layout = av_get_default_channel_layout(codec_ctx_->channels);

    int ret = avcodec_open2(codec_ctx_, NULL, NULL);
    if(ret != 0) {
        char errbuf[1024] = {0};
        av_strerror(ret, errbuf, sizeof(errbuf) - 1);
        printf("avcodec_open2 failed:%s\n", errbuf);
        return -1;
    }
    printf("InitAAC success\n");
    return 0;
}

void AudioEncoder::DeInit()
{
    if(codec_ctx_) {
        avcodec_free_context(&codec_ctx_);  // codec_ctx_被设置为NULL
//        codec_ctx_ = NULL;  // 不需要再写
    }
}

AVPacket *AudioEncoder::Encode(AVFrame *frame, int stream_index, int64_t pts, int64_t time_base)
{
    if(!codec_ctx_) {
        printf("codec_ctx_ null\n");
        return NULL;
    }
    pts = av_rescale_q(pts, AVRational{1, (int)time_base}, codec_ctx_->time_base);
    if(frame) {
        frame->pts = pts;
    }
    int ret = avcodec_send_frame(codec_ctx_, frame);
    if(ret != 0) {
        char errbuf[1024] = {0};
        av_strerror(ret, errbuf, sizeof(errbuf) - 1);
        printf("avcodec_send_frame failed:%s\n", errbuf);
        return NULL;
    }
    AVPacket *packet = av_packet_alloc();
    ret = avcodec_receive_packet(codec_ctx_, packet);
    if(ret != 0) {
        char errbuf[1024] = {0};
        av_strerror(ret, errbuf, sizeof(errbuf) - 1);
        printf("avcodec_receive_packet failed:%s\n", errbuf);
        av_packet_free(&packet);
        return NULL;
    }
    packet->stream_index = stream_index;
    return packet;
}

int AudioEncoder::GetFrameSize()
{
    if(codec_ctx_)
        return codec_ctx_->frame_size;
    return 0;
}

int AudioEncoder::GetSampleFormat()
{
    if(codec_ctx_)
        return codec_ctx_->sample_fmt;

    return -1;  // AV_SAMPLE_FMT_NONE
}

videoencoder.h
#ifndef VIDEOENCODER_H
#define VIDEOENCODER_H
extern "C"
{
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
}

class VideoEncoder
{
public:
    VideoEncoder();
    ~VideoEncoder();
    int InitH264(int width, int height, int fps, int bit_rate);
    void DeInit();
    AVPacket *Encode(uint8_t *yuv_data, int yuv_size,
                     int stream_index, int64_t pts, int64_t time_base);

private:
    int width_ = 0;
    int height_ = 0;
    int fps_ = 25;
    int bit_rate_ = 500*1024;
    int64_t pts_ = 0;
    AVCodecContext * codec_ctx_ = NULL;
    AVFrame *frame_ = NULL;
};

#endif // VIDEOENCODER_H

videoencoder.cpp
#include "videoencoder.h"
extern "C"
{
#include "libavutil/imgutils.h"
}
VideoEncoder::VideoEncoder()
{

}

VideoEncoder::~VideoEncoder()
{
    if(codec_ctx_) {
        DeInit();
    }
}

int VideoEncoder::InitH264(int width, int height, int fps, int bit_rate)
{
    width_ = width;
    height_ = height;
    fps_ = fps;
    bit_rate_ = bit_rate;

    AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);
    if(!codec) {
        printf("avcodec_find_encoder AV_CODEC_ID_H264 failed\n");
        return -1;
    }
    codec_ctx_ = avcodec_alloc_context3(codec);
    if(!codec_ctx_) {
        printf("avcodec_alloc_context3 AV_CODEC_ID_H264 failed\n");
        return -1;
    }

    codec_ctx_->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
    codec_ctx_->bit_rate = bit_rate_;
    codec_ctx_->width = width_;
    codec_ctx_->height = height_;
    codec_ctx_->framerate = {fps_, 1};
    codec_ctx_->time_base = {1, 1000000};   // 单位为微妙

    codec_ctx_->gop_size = fps_;
    codec_ctx_->max_b_frames = 0;
    codec_ctx_->pix_fmt = AV_PIX_FMT_YUV420P;

    int ret = avcodec_open2(codec_ctx_, NULL, NULL);
    if(ret != 0) {
        char errbuf[1024] = {0};
        av_strerror(ret, errbuf, sizeof(errbuf) - 1);
        printf("avcodec_open2 failed:%s\n", errbuf);
        return -1;
    }

    frame_ = av_frame_alloc();
    if(!frame_) {
        printf("av_frame_alloc failed\n");
        return -1;
    }
    frame_->width = width_;
    frame_->height = height_;
    frame_->format = codec_ctx_->pix_fmt;

    printf("Inith264 success\n");
    return 0;
}

void VideoEncoder::DeInit()
{
    if(codec_ctx_) {
        avcodec_free_context(&codec_ctx_);
    }
    if(frame_) {
        av_frame_free(&frame_);
    }
}

AVPacket *VideoEncoder::Encode(uint8_t *yuv_data, int yuv_size, int stream_index, int64_t pts, int64_t time_base)
{
    if(!codec_ctx_) {
        printf("codec_ctx_ null\n");
        return NULL;
    }
    int ret = 0;

    pts = av_rescale_q(pts, AVRational{1, (int)time_base}, codec_ctx_->time_base);
    frame_->pts = pts;
    if(yuv_data) {

        //该函数用于初始化一个AVFrame结构体,包括设置AVFrame中的各项参数,不需要重新分配buffer
        //使用该函数需要传入一个指向AVFrame结构体的指针
        int ret_size = av_image_fill_arrays(frame_->data, frame_->linesize,
                                            yuv_data, (AVPixelFormat)frame_->format,
                                            frame_->width, frame_->height, 1);
        if(ret_size != yuv_size) {
            printf("ret_size:%d != yuv_size:%d -> failed\n", ret_size, yuv_size);
            return NULL;
        }
        ret = avcodec_send_frame(codec_ctx_, frame_);
    } else {
        ret = avcodec_send_frame(codec_ctx_, NULL);
    }

    if(ret != 0) {
        char errbuf[1024] = {0};
        av_strerror(ret, errbuf, sizeof(errbuf) - 1);
        printf("avcodec_send_frame failed:%s\n", errbuf);
        return NULL;
    }
    AVPacket *packet = av_packet_alloc();
    ret = avcodec_receive_packet(codec_ctx_, packet);
    if(ret != 0) {
        char errbuf[1024] = {0};
        av_strerror(ret, errbuf, sizeof(errbuf) - 1);
        printf("avcodec_receive_packet failed:%s\n", errbuf);
        av_packet_free(&packet);
        return NULL;
    }
    packet->stream_index = stream_index;
    return packet;
}


http://www.niftyadmin.cn/n/5438919.html

相关文章

【Micropython ESP32】RTC时钟

文章目录 前言一、RTC时钟的介绍1.1 RTC时钟的作用1.2 Micropython中时钟于硬件时钟的区别 二、machine.RTC 类2.1 machine.RTC 类的构造方法2.2 初始化 RTC 设备起始时间2.3 关闭 RTC 设备2.4 获取当前时间 三、示例代码总结 前言 在嵌入式设备开发中,实时时钟&am…

分布式砖题

雪花算法 变动位数,性能佳,灵活调整bit位划分,灵活 zk 临时节点和watch机制实现注册中心 ,数据都在内存,nio 多线程模型; cp注重一致性,集群数据不一致时集群不可用 数据一致性模型 cap 强…

ES代替品:轻量级搜索引擎MeiliSearch

痛点 虽然Elasticsearch足够灵活强大、扩展性和实时性也较好。但是对于中小型项目来说,Elasticsearch还是显得有些庞大,对硬件设备的要求也较高。那么,在要求不是很高的情况下,我们可以考虑另一种搜索引擎方案:MeiliSe…

PX4|基于FAST-LIO mid360的无人机室内自主定位及定点悬停

目录 前言环境配置运行fast-lio修改px4位置信息融合方式编写位置坐标转换及传输节点 前言 在配置mid360运行环境后,可使用mid360进行室内的精准定位。 环境配置 在livox_ros_driver2的上级目录src下保存fast-lio的工程 git clone https://github.com/hku-mars/F…

2024全国水科技大会【联合主办】福州水务集团有限公司

福州水务成立于2008年11月,AA信用评级,注册资本21.2亿元。下属各级企业70多家(包括3家国家级高新技术企业、1家A股上市企业)。集团主营供水、排水、环保、温泉文旅、综合服务五大板块,旗下运营自来水厂17座&#xff0c…

程序分享--排序算法--基数排序

关注我,持续分享逻辑思维&管理思维; 可提供大厂面试辅导、及定制化求职/在职/管理/架构辅导; 有意找工作的同学,请参考博主的原创:《面试官心得--面试前应该如何准备》,《面试官心得--面试时如何进行自…

ubuntu下samba匿名读写服务器

目的: 局域网内,ubuntu下,创建SAMBA文件共享服务器。匿名读写权限。为了开发项目组文件共享传输方便。 环境: X86_64电脑一台。 操作系统: Ubuntu 20.04 LTS 64位。 安装samba $ sudo apt-get install samba创建…

STM32CubeMX学习笔记24---FreeRTOS(消息队列)

一. 队列简介 队列是为了任务与任务、任务与中断之间的通信而准备的,可以在任务与任务、任务与中 断之间传递消息,队列中可以存储有限的、大小固定的数据项目。任务与任务、任务与中断之 间要交流的数据保存在队列中,叫做队列项目。队列…