问题的起源 在学习音视频的知识时,一直对编码格式和编码器两个概念有疑惑,总是感觉它们是同一个东西。今天在读阮一峰的《FFmpeg视频处理入门教程》时,才明白,编码格式和编码器是两个不同的概念:编码格式 视频和音频都需要经过编码,才能保存成文件。不同的编码格式(CODEC),有不同的压缩率,会导致文件大小和清晰度的差异。 查询命令 ffmpegcodecs编码器 编码器(encoders)是实现某种编码格式的库文件。只有安装了某种格式的编码器,才能实现该格式视频音频的编码和解码。 查询命令 ffmpegencoders概念的澄清 原来,编码格式是音视频数据的比特流格式,它定义了音视频数据压缩解压的方式,以及是如何存储到文件中的等等一系列问题。而编码器是一个工具库,它用来具体完成数据的压缩解压等一系列操作。打个比方,编码格式就是菜谱,而编码器就是厨师,他们两个配合才能真正做出一道美味的菜肴。 下面,详细查看了一下FFmpeg的代码,来验证我的理解是否正确:编码格式的代码intshowcodecs(voidoptctx,constcharopt,constchararg){constAVCodecDescriptorcodecs;unsignedi,nbcodecsgetcodecssorted(codecs);。。。省略非重要代码。。。}staticunsignedgetcodecssorted(constAVCodecDescriptorrcodecs){。。。省略非重要代码。。。while((descavcodecdescriptornext(desc)))nbcodecs;。。。省略非重要代码。。。}constAVCodecDescriptoravcodecdescriptornext(constAVCodecDescriptorprev){if(!prev)returncodecdescriptors〔0〕;。。。省略非重要代码。。。} 由代码可以看出,编码格式都存放到了codecdescription的全局变量中。staticconstAVCodecDescriptorcodecdescriptors〔〕{videocodecs{。idAVCODECIDMPEG1VIDEO,。typeAVMEDIATYPEVIDEO,。namempeg1video,。longnameNULLIFCONFIGSMALL(MPEG1video),。propsAVCODECPROPLOSSYAVCODECPROPREORDER,},。。。省略非重要代码。。。}编码器的代码intshowdecoders(voidoptctx,constcharopt,constchararg){printcodecs(0);return0;}staticvoidprintcodecs(intencoder){constAVCodecDescriptorcodecs;unsignedi,nbcodecsgetcodecssorted(codecs);。。。省略非重要代码。。。}staticunsignedgetcodecssorted(constAVCodecDescriptorrcodecs){。。。省略非重要代码。。。while((descavcodecdescriptornext(desc)))nbcodecs;。。。省略非重要代码。。。}constAVCodecDescriptoravcodecdescriptornext(constAVCodecDescriptorprev){if(!prev)returncodecdescriptors〔0〕;。。。省略非重要代码。。。} 这样看,编码器也存放在codecdescription这个全局变量中。 由此咱们可以得出,在FFmpeg中,编码格式和编码器是同一个东西。背后的关系 不对呀,不对呀。这和阮一峰老师的结论不一致呀?难道阮一峰老师的解释有问题吗? 阮老师是没有问题。咱们再来更深入地查看一下FFmpeg的代码。其实在FFmpeg中,编码格式和编码器被定义成了不同的结构AVCodecDescriptor为编码格式typedefstructAVCodecDescriptor{enumAVCodecIDid;enumAVMediaTypetype;constcharname;constcharlongname;intprops;constcharconstmimetypes;conststructAVProfileprofiles;}AVCodecDescriptor;AVCodec为编码器typedefstructAVCodec{constcharname;constcharlongname;enumAVMediaTypetype;enumAVCodecIDid;intcapabilities;uint8tmaxlowres;constAVRationalsupportedframerates;constenumAVPixelFormatpixfmts;constintsupportedsamplerates;constenumAVSampleFormatsamplefmts;constuint64tchannellayouts;constAVClassprivclass;constAVProfileprofiles;constcharwrappername;intcapsinternal;intprivdatasize;int(updatethreadcontext)(structAVCodecContextdst,conststructAVCodecContextsrc);int(updatethreadcontextforuser)(structAVCodecContextdst,conststructAVCodecContextsrc);constAVCodecDefaultdefaults;void(initstaticdata)(structAVCodeccodec);int(init)(structAVCodecContext);int(encodesub)(structAVCodecContext,uint8tbuf,intbufsize,conststructAVSubtitlesub);int(encode2)(structAVCodecContextavctx,structAVPacketavpkt,conststructAVFrameframe,intgotpacketptr);int(decode)(structAVCodecContextavctx,voidoutdata,intgotframeptr,structAVPacketavpkt);int(close)(structAVCodecContext);int(receivepacket)(structAVCodecContextavctx,structAVPacketavpkt);int(receiveframe)(structAVCodecContextavctx,structAVFrameframe);void(flush)(structAVCodecContext);constcharbsfs;conststructAVCodecHWConfigInternalconsthwconfigs;constuint32tcodectags;}AVCodec; 只不过,编码格式和编码器是一对一的关系,FFmpeg通过AVCodecIDid来建立它们的关联。 总结 这样来看,编码格式和编码器其实是一个概念的两种呈现方式:编码格式负责形,编码器负责体形体共同作用,完成音视频的编解码工作。