H.264解码参考文章:H.264解码详解
视频编码经历了多个阶段,从最初的模拟时代发展到数字时代,不断提高了数据的压缩效率和视频质量。
最早期的视频编码是基于模拟信号的编码,主要用于模拟电视广播。这些编码系统采用了较为简单的压缩技术,但受到了模拟技术的限制。
随着数字技术的发展,数字视频编码开始崭露头角。在这一时期,出现了一些基于数字信号的视频编码标准,但它们的压缩效率相对较低。
1984年CCITT第15研究组发布了数字基群电视会议编码标准H.120建议。1988年CCITT通过了视像编码标准H.261建议,被称为视频压缩编码的一个里程碑。从此,ITU-T、ISO等公布的基于波形的一系列视频编码标准的编码方法都是基于H.261中的混合编码方法。
MPEG-1是第一个被广泛采用的数字视频编码标准,主要用于VCD(Video CD)的压缩。它在压缩效率和视频质量方面取得了一些进展。
MPEG-2进一步提高了视频压缩的效率,广泛应用于数字电视、DVD和广播领域。它支持更高的分辨率和比特率。
1995年,ITU-T推出H.263标准,用于低于64kbit/s的低码率视频传输,如PSTN信道中可视会议、多媒体通信等。1984年和2000年又分别公布了H.263+、H.263++等标准。
1998年11月被ISO/IEC批准为国际标准,其正式标准编号是ISO/IEC 14496。与MPEG-1和MPEG-2标准相比,MPEG-4更加注重多媒体系统的交互性和灵活性,主要应用于可视电话、视频会议等。
H.264是一项里程碑式的进展,引入了先进的视频编码技术,包括帧内和帧间预测、熵编码等。它在相同质量下显著减小了文件大小,广泛应用于互联网视频、蓝光光盘等。
H.265是H.264的继任者,引入了更高效的编码技术。它在维持相同质量的情况下,进一步减小了文件大小,适用于4K和8K视频。
VP9和AV1是Google和AOMedia联盟推出的开放源代码视频编码标准,旨在提供更高效的视频压缩。它们主要用于在线视频流服务。
随着技术的不断发展,视频编码仍在不断创新。未来的趋势会包括更高效的编码算法、更好的网络适应性、更广泛的4K和8K应用,以及更低的延迟。
H.264是一种高度压缩的视频编码标准,也被称为MPEG-4 AVC(Advanced Video Coding)。它是一种广泛使用的视频编码标准,通常用于视频压缩、存储和传输,支持高清视频等。
H.264并不直接地规定一个编解码器如何实现,而是规定了一个编码后的视频比特流的句法和该比特流的解码方法。
I帧是关键帧,包含完整的图像信息,解码出来就能完全显示。码流数据很大。
B帧是双向预测帧,相似度在95%以内。需要依赖于I帧和P帧进行编解码。码流数据很小。有一定的延迟。
P帧是向前预测帧,相似度在70%以内。需要依赖前一个I帧或者前一个P帧进行编解码。码流数据一般。只存储于前一帧不同的部分。
H.264编码器采用的是变换加预测的混合编码法。如下图,输入的帧以宏块为单位被编码器处理。首先,按帧内或帧间预测编码的方法进行处理。
如果采用帧间预测编码,当前帧和参考帧经过ME(运动估计)的数据和参考帧和数据作为输入,两者经过MC(运动补偿)得到预测值P。预测值P和当前块相减后,得到一个残差块Dn,经块变换、量化后产生一组量化后的变换系数X,再经重排序,熵编码,加上与解码所需的一些头信息一起组成一个压缩后的码流,经NAL(网络自适应层)供传输和存储用。这里的NAL是网络自适应层,不是NAL单元。
帧内预测是当前帧和未经滤波的重建帧之间得到预测值。未经滤波的重建帧是由残差块后的变换系数X经过反量化和反变换后与P值相加所得。同时未经滤波的重建中帧uFn经过滤波得到重建帧,作为进一步预测的参考帧。
H.264的功能分为两层:视频编码层(VCL,Video CodingLayer)和网络提取层(NAL,Network Abstraction Layer)。在视频编码层,编码的VCL数据,先被映射或封装进NAL单元中。VCL NAL单元(Video Coding Layer NAL Unit):包含视频编码的实际图像数据,如帧的关键信息、非关键信息等。视频数据被分割成一个个的NAL单元。每个NAL单元都包含了一部分编码数据,以及一些控制信息。这些NAL单元可以独立传输,接收端可以根据NAL单元的类型和顺序进行解码和播放。
H.264视频编码标准定义了一种复杂的语法结构,该结构用于描述视频数据的组织和编码。H.264的句法元素分层结构包括多个层次,如下。
extern "C" {
#include
#include
#include
}
int main() {
// 初始化FFmpeg
av_register_all();
// 创建AVFormatContext,用于保存编码后的视频数据
AVFormatContext *formatContext = avformat_alloc_context();
avformat_alloc_output_context2(&formatContext, nullptr, nullptr, "output.h264");
// 创建AVCodecContext,用于配置编码器参数
AVCodecContext *codecContext = avcodec_alloc_context3(nullptr);
AVCodec *codec = avcodec_find_encoder_by_name("libx264");
codecContext->bit_rate = 400000; // 设置比特率
codecContext->width = 640; // 设置视频宽度
codecContext->height = 480; // 设置视频高度
codecContext->time_base = {1, 25}; // 设置帧率
codecContext->framerate = {25, 1}; // 设置帧率
// 打开编码器
avcodec_open2(codecContext, codec, nullptr);
// 创建AVFrame,用于存储原始视频帧
AVFrame *frame = av_frame_alloc();
frame->width = codecContext->width;
frame->height = codecContext->height;
frame->format = AV_PIX_FMT_YUV420P;
av_frame_get_buffer(frame, 32); // 分配帧缓冲区
// 创建输出文件
avio_open(&formatContext->pb, "output.h264", AVIO_FLAG_WRITE);
// 写文件头
avformat_write_header(formatContext, nullptr);
// 准备图像数据(这里只是示例,实际需要从摄像头或文件中获取图像数据)
// ...
// 将图像数据编码并写入文件
// 这里的循环中,不断将原始图像数据编码成H.264格式并写入文件
for (int i = 0; i < num_frames; ++i) {
// 将图像数据拷贝到AVFrame中
// ...
// 发送原始图像帧给编码器
avcodec_send_frame(codecContext, frame);
// 接收编码后的数据
AVPacket pkt;
av_init_packet(&pkt);
pkt.data = nullptr;
pkt.size = 0;
avcodec_receive_packet(codecContext, &pkt);
// 将编码后的数据写入文件
av_write_frame(formatContext, &pkt);
av_packet_unref(&pkt);
}
// 写文件尾
av_write_trailer(formatContext);
// 释放资源
avcodec_free_context(&codecContext);
avformat_free_context(formatContext);
return 0;
}