核心是一定要注意 有没有字节对齐问题。
从 yuv file 中读取数据到avframe 的data 中
核心是我们要知道 yuv file 的分辨率,假设是800x600的。还要知道 yuv file的 align,
那么create avframe的时候, 就能准备一个 好用的 avframe。
如下的例子是:我们要读取的yuv file 是 800x600 的,且align是1,align是1,对应的linesize[0] = 800
//1.创建avframe
AVFrame* avframe = av_frame_alloc();
avframe->width = 800;
avframe->height = 600;
avframe->format = AV_PIX_FMT_YUV420P;
avframe->linesize[0] = 800;
avframe->linesize[1] = 400;
avframe->linesize[2] = 400;
avframe->pts = 0;
ret = av_frame_get_buffer(avframe, 0);
//6.给avframe中写数据,数据要从 这里读
//ifstream readfileifs("./111/800_600_yuv420p_25.yuv", ios_base::binary);
//7. 通过 av_image_get_buffer_size 方法,获取一张图片的大小
int frame_bytes_bufsize = av_image_get_buffer_size(
(enum AVPixelFormat)avframe->format,
avframe->width,
avframe->height,
1);
//分配对应大小的空间
uint8_t* frame_bytes_buf = (uint8_t*)malloc(frame_bytes_bufsize);
memset(frame_bytes_buf, 0, frame_bytes_bufsize);
//从yuv中读取这么大的数据
readfileifs.read((char *)frame_bytes_buf, frame_bytes_bufsize);
//将 frame_bytes_buf 中的数据通过 av_image_fill_arrays方法,给avframe的data 和 avframe的linesize 赋值。这样就能得到
int need_size = av_image_fill_arrays(avframe->data,
avframe->linesize,
frame_bytes_buf,
(enum AVPixelFormat)avframe->format,
avframe->width,
avframe->height,
1);
将avfreame 的data 写入 yuvfile 中
NV12
if (send_avframe->linesize[0] == send_avframe->width) {
//没有字节对齐问题
writefstream.write((char*)send_avframe->data[0], send_avframe->linesize[0] * send_avframe->height);
writefstream.write((char*)send_avframe->data[1], send_avframe->linesize[1] * send_avframe->height / 2);
}
else {
//有字节对齐问题时候的处理
for (int j = 0; j < send_avframe->height; j++) {
writefstream.write((char*)(send_avframe->data[0] + j * send_avframe->linesize[0]), send_avframe->width);
}
for (int j = 0; j < avframe->height / 2; j++) {
writefstream.write((char*)(send_avframe->data[1] + j * send_avframe->linesize[1]), send_avframe->width);
}
}
yuv420p
if (send_avframe->linesize[0] == send_avframe->width) {
//没有字节对齐问题
writefstream.write((char*)send_avframe->data[0], send_avframe->linesize[0] * send_avframe->height);
writefstream.write((char*)send_avframe->data[1], send_avframe->linesize[1] * send_avframe->height / 2);
writefstream.write((char*)send_avframe->data[2], send_avframe->linesize[2] * send_avframe->height / 2);
}
else {
//有字节对齐问题时候的处理
// 先写完Y,再写U,再写V
for (int j = 0; j < send_avframe->height; j++) {
writefstream.write((char*)(send_avframe->data[0] + j * send_avframe->linesize[0]), send_avframe->width);
}
for (int j = 0; j < avframe->height / 2; j++) {
writefstream.write((char*)(send_avframe->data[1] + j * send_avframe->linesize[1]), send_avframe->width / 2);
}
for (int j = 0; j < avframe->height / 2; j++) {
writefstream.write((char*)(send_avframe->data[2] + j * send_avframe->linesize[2]), send_avframe->width / 2);
}
}
将avfreame 的data 写入 数组中
从 avframe 的data 中读取数据到 数组中
NV12_data_ = new uint8_t[4096 * 2160 * 1.5];
if (frame->linesize[0] == frame->width)
{
// 如果没有字节对齐问题,直接先copy avframe->data[0];然后再copy avframe->data[1]
memcpy(NV12_data_, frame->data[0], frame->linesize[0] * frame->height); //Y
memcpy(NV12_data_ + frame->linesize[0] * frame->height, frame->data[1], frame->linesize[1] * frame->height / 2); //UV
}
else //逐行复制
{
//这里字节有对齐问题的时候,为什么要这样 copy 呢?
//而且实验测试,当 avframe是 400 * 300 时候,字节对齐有问题时候,就是用这种方法就能解决。
for (int i = 0; i < frame->height; i++) //Y
{
memcpy(NV12_data_ + i * frame->width,
frame->data[0] + i * frame->linesize[0],
frame->width
);
}
for (int i = 0; i < frame->height / 2; i++) //UV
{
auto p = NV12_data_ + frame->height * frame->width;// 移位Y
memcpy(p + i * frame->width,
frame->data[1] + i * frame->linesize[1],
frame->width
);
}
}