AVPacket结构以及一些API的使用
#include <iostream>
extern "C"
{
#include <libavcodec\packet.h>
}
// 1. 测试仅alloc不free会不会导致内存泄漏
void test01()
{
AVPacket* pkt = NULL;
while (true)
{
pkt = av_packet_alloc(); // 内存会一直增长(由此可见内部不会自己释放)
_sleep(1);
}
}
// 2. 测试alloc与free配合使用
void test02()
{
AVPacket* pkt = NULL;
while (true)
{
pkt = av_packet_alloc(); // 分配后释放,不会导致内存泄漏
_sleep(1);
av_packet_free(&pkt);
}
}
// 3. 使用new为pkt里的buff(AVBufferRef)分配内存,查看引用计数
void test03()
{
AVPacket* pkt = NULL;
pkt = av_packet_alloc(); // 申请packet内存(bufferRef 0x00)
av_new_packet(pkt, 1024); // 申请AVBufferRef内存 (引用计数初始化为1)
std::cout << "buffRef Cnt: " << av_buffer_get_ref_count(pkt->buf) << std::endl; // 1
// av_packet_unref(pkt); // 这里不需要调(av_packet_free调用一次av_packet_unref)
av_packet_free(&pkt);
}
// 4. 误使用init函数导致buffRef指向的内存无法被释放
void test04()
{
AVPacket* pkt = NULL;
while (true)
{
pkt = av_packet_alloc();
av_new_packet(pkt, 1024);
av_init_packet(pkt); // 指向AVBuffRef的buf指针被置空,导致内存咔咔漏
av_packet_free(&pkt); // AVBuffRef的buf内存无法释放
_sleep(1);
}
// 注意: 还有一个av_free_packet函数
// av_packet_free 清空buf,然后将pkt置空
// av_free_packet 清空buf,并不会将pkt置空
}
// 5. av_packet_move_ref的使用
void test05()
{
AVPacket* pkt1 = NULL;
AVPacket* pkt2 = NULL;
pkt1 = av_packet_alloc();
av_new_packet(pkt1, 1024);
pkt2 = av_packet_alloc(); // 必须先给pkt2分配内存
av_packet_move_ref(pkt2, pkt1); // 将pkt1的AVBuffRef以及其它参数移交给pkt2,将pkt1参数初始化init
av_packet_free(&pkt1); // 这里均要将pkt的内存释放掉
av_packet_free(&pkt2); // 因为此时引用计数为1,内部一次uref就能释放buf内存
}
// 6. av_packet_clone使用
void test06()
{
AVPacket* pkt1 = NULL;
AVPacket* pkt2 = NULL;
while (true)
{
pkt1 = av_packet_alloc();
av_new_packet(pkt1, 1024);
pkt2 = av_packet_clone(pkt1); // av_packet_alloc + av_packet_ref
av_packet_free(&pkt1); // 两次free会将引用计数为2的buf清除(不会造成内存泄漏)
av_packet_free(&pkt2);
}
}
// 7. av_packet_clone 后使用 av_init_packet 会导致buf内存无法释放
void test07()
{
AVPacket* pkt1 = NULL;
AVPacket* pkt2 = NULL;
while (true)
{
pkt1 = av_packet_alloc();
av_new_packet(pkt1, 1024);
pkt2 = av_packet_clone(pkt1);
av_init_packet(pkt1); // 导致av_packet_free(pkt1) 引用计数不减(导致无法释放) 内存咔咔漏
av_packet_free(&pkt1);
av_packet_free(&pkt2);
}
}
// 8. AVPacket整个结构体赋值, 和av_packet_move_ref类似
void test08()
{
AVPacket* pkt1 = NULL;
AVPacket* pkt2 = NULL;
while (true)
{
pkt1 = av_packet_alloc();
av_new_packet(pkt1, 1024);
pkt2 = av_packet_alloc();
*pkt2 = *pkt1;
av_init_packet(pkt1);
av_packet_free(&pkt1); // 需要将pkt1的内存释放掉(否则会导致内存泄漏)
av_packet_free(&pkt2);
}
}
// 9. 多次使用 av_packet_ref 导致内存无法释放的问题
void test09()
{
AVPacket* pkt1 = NULL;
AVPacket* pkt2 = NULL;
while (true)
{
pkt1 = av_packet_alloc();
av_new_packet(pkt1, 1024); // 引用计数加一
pkt2 = av_packet_alloc();
av_packet_ref(pkt2, pkt1);
av_packet_ref(pkt2, pkt1); // 此时引用计数为3
av_packet_free(&pkt1); // 但是仅仅引用计数减两次(导致内存泄漏)
av_packet_free(&pkt2);
}
}
// 10. 先uref一次呢???
void test10()
{
AVPacket* pkt1 = NULL;
AVPacket* pkt2 = NULL;
while (true)
{
pkt1 = av_packet_alloc();
av_new_packet(pkt1, 1024);
pkt2 = av_packet_alloc();
av_packet_ref(pkt2, pkt1);
av_packet_ref(pkt2, pkt1); // 此时引用计数为3
av_packet_unref(pkt1); // 内存还是会泄露,目前为两个pkt指向同一个AVBuffRef
av_packet_free(&pkt1); // 两次unref(pkt1) 会有一次无效
av_packet_free(&pkt2); // 从而导致内存咔咔漏
}
}
// 11. 正确使用
void test11()
{
AVPacket* pkt1 = NULL;
AVPacket* pkt2 = NULL;
while (true)
{
pkt1 = av_packet_alloc();
av_new_packet(pkt1, 1024);
pkt2 = av_packet_alloc();
av_packet_ref(pkt2, pkt1); // 增加引用
av_packet_unref(pkt1); // 减少引用(此时AVBuffRef被pkt2持有)
if (pkt1->buf)
{
std::cout << "pkt1 has buf" << std::endl;
}
if (pkt2->buf)
{
std::cout << "pkt2 has buf" << std::endl; // 被打印
}
av_packet_ref(pkt2, pkt1); // 此时引用计数为2
av_packet_free(&pkt1); // 两次释放将buf释放掉
av_packet_free(&pkt2);
}
}
AVFrame结构以及一些API的使用
#include <iostream>
extern "C"
{
#include <libavutil\frame.h>
#include <libavcodec\avcodec.h>
}
// 1. allo与free配对使用
void frame_test01()
{
AVFrame* frame = NULL;
while (true)
{
frame = av_frame_alloc();
av_frame_free(&frame); // 不配对使用会导致内存泄漏
}
}
// 2. 根据格式分配内存
void frame_test02()
{
AVFrame* frame = NULL;
while (true)
{
frame = av_frame_alloc();
frame->nb_samples = 1024;
frame->format = AV_SAMPLE_FMT_S16P; // AV_SAMPLE_FMT_S16P AV_SAMPLE_FMT_S16
frame->channel_layout = AV_CH_LAYOUT_STEREO; // AV_CH_LAYOUT_MONO AV_CH_LAYOUT_STEREO(立体音)
av_frame_get_buffer(frame, 0); // frame中的buf会根据格式自动分配内存
// buf有多个,因为数据排列的格式不一样(yuv pcm)
// 当为音频帧 平面模式且双声道时(左右声道数据会分开存储)为交错模式时(数据存储在一起)
if (frame->buf && frame->buf[0])
{
std::cout << "buf[0] size: " << frame->buf[0]->size << std::endl;
}
if (frame->buf && frame->buf[1])
{
std::cout << "buf[1] size: " << frame->buf[1]->size << std::endl;
}
// AV_SAMPLE_FMT_S16 AV_CH_LAYOUT_STEREO 交错立体音(一个 buf[0] size 1024 * 2 * 2 = 4096)
// AV_SAMPLE_FMT_S16P AV_CH_LAYOUT_STEREO 平面立体音(两个 buf[0] size:2048 buf[1]size:2048) 平面且双声道分开存储
// AV_SAMPLE_FMT_S16 AV_CH_LAYOUT_MONO 交错单声道(一个 buf[0] size 1024 * 2 = 2048)
// AV_SAMPLE_FMT_S16P AV_CH_LAYOUT_MONO 平面单声道(一个 buf[0] size:2048)
// 2. av_frame_make_writable (当frame本声为空时不能av_frame_make_writable)
if (frame)
{
av_frame_make_writable(frame); // 分配新缓冲,赋值frame数据,防止和解码器造成冲突
}
// av_frame_unref(frame); // av_frame_free内部有引用计数减一操作
av_frame_free(&frame);
}
}
int main_frame()
{
//frame_test01();
frame_test02();
getchar();
return 0;
}