XEncode.h

作用:继承于XCodec,用于编码

1
2
3
4
5
6
7
8
9
10
#pragma once
#include "xcodec.h"

class XEncode:public XCodec
{
public:
AVPacket *Encode(const AVFrame* frame);

std::vector<AVPacket *> End();
};

AVPacket

  • 是 FFmpeg 库中的一个数据结构,主要用于存储编码后的音频或视频数据包。

  • 在多媒体处理中,数据包通常包含一个完整的编码帧或部分编码帧的比特流数据。

  • 这些数据包可以用于传输、存储或进一步处理,如解码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
typedef struct AVPacket 
{
uint8_t *data; // 指向实际存储编码数据的缓冲区
int size; // 缓冲区中数据的大小,以字节为单位

int64_t pts; // 显示时间戳
int64_t dts; // 解码时间戳

int stream_index; // 数据包所属的流索引

int flags; // 数据包标志,用于标识关键帧等信息
int64_t duration; // 数据包的持续时间

void *opaque; // 私有数据指针,用于用户扩展
AVBufferRef *buf; // 引用计数的缓冲区

...
} AVPacket;

XEncode.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include "xencode.h"
#include <iostream>
#include "xtools.h"

using namespace std;

extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
}

AVPacket* XEncode::Encode(const AVFrame* frame)
{
if (!frame) return nullptr;
unique_lock<mutex> lock(mux_);
if (!c_) return false;

auto re = avcodec_send_frame(c_, frame);
if (re != 0) return nullptr;
auto pkt = av_packet_alloc();

re = avcodec_receive_packet(c_, pkt);

if (re == 0) return pkt;

av_packet_free(&pkt);
if (re == AVERROR(EAGAIN) || re == AVERROR_EOF)
{
return nullptr;
}
if (re < 0)
{
PrintErr(re);
return nullptr;
}

return pkt;
}


std::vector<AVPacket *> XEncode::End()
{
std::vector<AVPacket*> res;
unique_lock<mutex> lock(mux_);
if (!c_) return res;

auto re = avcodec_send_frame(c_, NULL);

if (re != 0) return res;
while (re >= 0)
{
auto pkt = av_packet_alloc();
re = avcodec_receive_packet(c_, pkt);
if (re != 0)
{
av_packet_free(&pkt);
break;
}

res.push_back(pkt);
}

return res;
}

Encode()

作用:

  • 将原始的音视频帧(AVFrame)编码成压缩的数据包(AVPacket)。这是编码过程的核心步骤。
  • 线程安全
  • @para frame 空间由用户维护
  • @return 失败范围nullptr 返回的AVPacket用户需要通过av_packet_free清理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
AVPacket* XEncode::Encode(const AVFrame* frame)
{
if (!frame) return nullptr;
unique_lock<mutex> lock(mux_);

// 父类XCodec中的解码器上下文
if (!c_) return false;

// 发送到编码器线程
auto re = avcodec_send_frame(c_, frame);
if (re != 0) return nullptr;
auto pkt = av_packet_alloc(); // 申请一个AVPacket用于存储编码后的数据

// 从编码器接收编码后的数据包。
// 将编码后的数据写入 pkt。
re = avcodec_receive_packet(c_, pkt);

if (re == 0) return pkt; // ==0表示成功

// 没有成功则释放pkt
av_packet_free(&pkt);

// AVERROR(EAGAIN)(表示当前数据不足以生成一个完整的数据包)
// AVERROR_EOF(表示编码器已经结束)
if (re == AVERROR(EAGAIN) || re == AVERROR_EOF)
{
return nullptr;
}

// 如果返回值小于 0,表示发生了其他错误
if (re < 0)
{
PrintErr(re);
return nullptr;
}

return pkt;
}

End()

作用:用于编码结束时处理剩余的编码数据并将其存储在 std::vector<AVPacket *>,在完成编码操作后获取所有剩余的编码数据包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
std::vector<AVPacket *> XEncode::End()
{
std::vector<AVPacket*> res;
unique_lock<mutex> lock(mux_);
if (!c_) return res;

// 送一个空的帧到编码器,表示编码结束。这是为了让编码器输出缓冲区中的剩余数据。
auto re = avcodec_send_frame(c_, NULL);

if (re != 0) return res;
while (re >= 0)
{
// 分配一个新的数据包
auto pkt = av_packet_alloc();

// 从编码器接收一个数据包
re = avcodec_receive_packet(c_, pkt);
if (re != 0)
{
// 释放分配的数据包内存
av_packet_free(&pkt);
break;
}

// 将接收到的数据包添加到结果向量中
res.push_back(pkt);
}

return res;
}