上一篇我们学习了Android投屏开发过程中所用到的ADB命令,本篇我们将继续学习Android投屏软件开发过程中所需要的视频编解码方面的知识。
关于FFMPEG
FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。它提供了录制、转换以及流化音视频的完整解决方案,包含了非常先进的音频/视频编解码库libavcodec,以保证高可移植性和编解码质量。此外,FFmpeg可以使用GPU加速,并且提供了多种媒体格式的封装和解封装,包括多种音视频编码、多种协议的流媒体、多种色彩格式转换、多种采样率转换等。它还提供了丰富的插件模块,包括封装和解封装的插件、编码与解码的插件等,可以方便地扩展其功能。
除了上述功能外,FFmpeg还提供了播放器相关功能,其avformat和avcode可以播放各种媒体文件或者流。此外,通过libavformat中的接口,可以实现音频布局转换和布局调整等功能。
总之,FFmpeg是一款功能强大的多媒体处理工具和开发套件,被广泛应用于音视频处理、流媒体传输等领域.
关键知识点
-
AVCodecContext
AVCodecContext 是一个描述编解码器上下文的结构体,它包含了编解码器需要的许多参数信息,这些参数信息在打开编解码器时设置。对于解码器来说,AVCodecContext 通常包含了输入数据的格式、解码后的数据格式以及其他解码相关的设置。 -
AVCodecParameters
AVCodecParameters 是一个描述编解码器参数的结构体,它包含了流的编解码器信息,比如编解码器的类型(视频、音频等)、编解码器的ID(指定具体的编解码器,如H.264)、位宽、帧率等。在FFmpeg中,每个流(AVStream)都有一个与之关联的 AVCodecParameters 实例,用于描述该流的编解码器参数。 -
AVCodec
AVCodec 是一个描述编解码器的结构体,它包含了编解码器的信息,比如编解码器的名字、类型(编码器或解码器)、支持的像素格式等。FFmpeg通过 AVCodec 结构体来注册和管理所有的编解码器。 -
AVPacket
AVPacket 是一个描述压缩数据的结构体,它包含了压缩数据的引用计数、数据、数据大小、时间戳等信息。在解码过程中,AVPacket 用于存储从输入流中读取的压缩数据。 -
AVFrame
AVFrame 是一个描述解码后原始数据的结构体,它包含了原始数据的引用计数、数据、线条数、宽度、高度等信息。在解码过程中,AVFrame 用于存储解码后的数据。
一个H.264视频解码示例
以下是一个简单的使用FFmpeg库进行H.264视频解码的示例代码。注意,这段代码只是一个基本示例,并没有进行错误处理,实际使用时需要添加适当的错误处理逻辑。
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libavutil/opt.h>
int main(int argc, char* argv[]) {
if (argc < 2) {
printf(“Usage: %s \n”, argv[0]);
return -1;
}
const char* filePath = argv[1];
// Initialize libavformat and register all muxers, demuxers, and protocols.
av_register_all();
// Allocate an AVFormatContext.
AVFormatContext* pFormatContext = avformat_alloc_context();
if (!pFormatContext)
return -1;
// Open the input stream. Read the header. No AVFormatContext yet.
if (avformat_open_input(&pFormatContext, filePath, NULL, NULL) != 0) {
printf("Could not open input file '%s'\n", filePath);
avformat_free_context(pFormatContext);
return -1;
}
// Retrieve stream information.
if (avformat_find_stream_info(pFormatContext, NULL) < 0) {
printf("Could not find stream information\n");
avformat_close_input(&pFormatContext);
return -1;
}
int videoStreamIndex = av_find_best_stream(pFormatContext, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
if (videoStreamIndex < 0) {
printf("Did not find a video stream in the input file\n");
avformat_close_input(&pFormatContext);
return -1;
}
// Find the decoder for the video stream.
AVCodecParameters* pCodecParameters = pFormatContext->streams[videoStreamIndex]->codecpar;
AVCodec* pCodec = avcodec_find_decoder(pCodecParameters->codec_id);
if (!pCodec) {
printf("Unsupported codec\n");
avformat_close_input(&pFormatContext);
return -1;
}
// Allocate codec context.
AVCodecContext* pCodecContext = avcodec_alloc_context3(pCodec);
if (!pCodecContext) {
printf("Could not allocate video codec context\n");
avformat_close_input(&pFormatContext);
return -1;
}
// Copy codec parameters from input stream to output codec context.
if (avcodec_parameters_to_context(pCodecContext, pCodecParameters) < 0) {
printf("Could not copy codec parameters\n");
avcodec_free_context(&pCodecContext);
avformat_close_input(&pFormatContext);
return -1;
}
// Open the codec.
if (avcodec_open2(pCodecContext, pCodec, NULL) < 0) {
printf("Could not open codec\n");
avcodec_free_context(&pCodecContext);
avformat_close_input(&pFormatContext);
return -1;
}
AVFrame* frame = av_frame_alloc();
if (!frame) {
printf("Could not allocate frame\n");
avcodec_free_context(&pCodecContext);
avformat_close_input(&pFormatContext);
return -1;
}
AVPacket packet;
while (av_read_frame(pFormatContext, &packet) >= 0) {
if (packet.stream_index == videoStreamIndex) {
if (avcodec_send_packet(pCodecContext, &packet) == 0) {
while (avcodec_receive_frame(pCodecContext, frame) == 0) {
// Process decoded frame here.
printf("Decoded frame with size: %d x %d\n", frame->width, frame->height);
}
}
}
av_packet_unref(&packet);
}
// Flush the decoder (some frames might be buffered).
avcodec_send_packet(pCodecContext, NULL);
while (avcodec_receive_frame(pCodecContext, frame) == 0) {
// Process decoded frame here.
printf("Flushed frame with size: %d x %d\n", frame->width, frame->height);
}
// Clean up.
av_frame_free(&frame);
avcodec_free_context(&pCodecContext);
avformat_close_input(&pFormatContext);
return 0;
}
更多内容请关注 github: linkedbyte