如何用ffmpeg 解码延迟音频解码无延迟

PHP开发框架
开发工具/编程工具
服务器环境
ThinkSAAS商业授权:
ThinkSAAS为用户提供有偿个性定制开发服务
ThinkSAAS将为商业授权用户提供二次开发指导和技术支持
官方1群:【已满】
让ThinkSAAS更好,把建议拿来。
关注微信,更好学习& & 多媒体的时代,得多了解点编解码的技术才行,而ffmpeg为我们提供了一系列多媒体编解码的接口,如何用好这些接口达到自己所需要的目的,这也是一门重要的学问。
& & 要是了解得不够,总是会遇到一堆又一堆问题;网上关于ffmpeg的讲解,说少也不少,说多也不多,由于版本更新又更新,能找着的资料基本上都不大能对得上,需要进行一定量的修改才能正常工作;所以,我也借着这个机会,重新走一遍ffmpeg的入门,然后理清同步等问题。
本文主要讲的是ffmpeg解码最基本的步骤,以及其用到的接口,另附有完整的实例代码。
使用工具:FFMPEG(2.0.1)、VS2010
平台:WINDOWS
下面就开始吧&&
步骤一:初始化ffmpeg(必须的)
av_register_all();
avcodec_register_all();
  使用以上语句初始化ffmpeg的功能,简单,没什么好讲的。
步骤二:打开多媒体文件,检查头部信息
AVFormatContext *pFormatCtx = avformat_alloc_context();;
// Open video file
if(avformat_open_input(&pFormatCtx, filename, NULL, NULL)!=0)
return -1; // Couldn't open file
  avformat_open_input()这个函数读取文件的头部并且把信息保存到我们给的AVFormatContext结构体中,注意要先调用avformat_alloc_context()为我们的结构体申请空间,否则读取文件的信息无法保存,avformat_open_input会失败。
步骤三:检查文件中的流的信息
// Retrieve stream information
if(av_find_stream_info(pFormatCtx)&0)
return -1; // Couldn't find stream information
// Dump information about file onto standard error
av_dump_format(pFormatCtx, 0, filename, 0);
  av_find_stream_info()这个函数为pFormatCtx-&streams填充上正确的信息。av_dump_format()是一个手工调试的函数,能使我们看到pFormatCtx-&streams里面有什么内容。
步骤四:找出文件中的视频流
AVCodecContext *pCodecC
// Find the first video stream
int videoStream=-1;
for(i=0; i&pFormatCtx-&nb_ i++) {
if(pFormatCtx-&streams[i]-&codec-&codec_type==AVMEDIA_TYPE_VIDEO) {
videoStream=i;
if(videoStream==-1)
return -1; // Didn't find a video stream
// Get a pointer to the codec context for the video stream
pCodecCtx=pFormatCtx-&streams[videoStream]-&
  pFormatCtx-&streams仅仅是一组大小为pFormatCtx-&nb_streams的指针,所以让我们可以使用它找到一个视频流,并记录其在stream中的下标号(后面根据此标号可以与该视频匹配)。当然,视频流有可能不止一个,如果想要把所有视频流都找到,可以使用数组记录,就不需要break了。
& & & AVCodecContext,流中关于编解码器的信息就是被我们叫做"codec context"(编解码器上下文)的东西。这里面包含了流中所使用的关于编解码器的所有信息,现在我们有了一个指向他的指针。
步骤五:找到该视频流真正的编解码器并且打开它
AVCodec *pC
// Find the decoder for the video stream
pCodec=avcodec_find_decoder(pCodecCtx-&codec_id);
if(pCodec==NULL) {
fprintf(stderr, "Unsupported codec!\n");
return -1; // Codec not found
// Open codec
if(avcodec_open2(pCodecCtx, pCodec, NULL)&0)
return -1; // Could not open codec
  avcodec_find_decoder()根据找到的视频流格式,找到想应的编解码器;avcodec_open2()可以开启我们的解码器使其处于随时可工作的状态,因为ffmpeg版本更新过许多次,所以有些Function名字都会带一些数字。
步骤六:申请数据空间(保存帧数据用)
AVFrame *pFrame, *pFrameRGB;
// Allocate video frame
pFrame=avcodec_alloc_frame();
// Allocate an AVFrame structure
pFrameRGB=avcodec_alloc_frame();
if(pFrameRGB==NULL)
return -1;
// Determine required buffer size and allocate buffer
numBytes=avpicture_get_size(PIX_FMT_RGB24, pCodecCtx-&width,
pCodecCtx-&height);
buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
// Assign appropriate parts of buffer to image planes in pFrameRGB
// Note that pFrameRGB is an AVFrame, but AVFrame is a superset
// of AVPicture
avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24,
pCodecCtx-&width, pCodecCtx-&height);
  AVFrame就是用来保存帧数据的,之所以定义了两个,是因为解码后帧数据一般是YUV格式,我们转换成RGB的帧数据,还需要一个存储的地方。我们使用avpicture_get_size()来获得我们需要的大小,然后用av_malloc手工申请内存空间,avpicture_fill来把帧和我们新申请的内存来结合。
步骤七:读取数据并解码
int frameF
while(av_read_frame(pFormatCtx, &packet)&=0) {
// Is this a packet from the video stream?
if(packet.stream_index==videoStream) {
// Decode video frame
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
// Did we get a video frame?
if(frameFinished) {
// Convert the image from its native format to RGB
static struct SwsContext *img_convert_
img_convert_ctx = sws_getCachedContext(img_convert_ctx,
pCodecCtx-&width, pCodecCtx-&height, pCodecCtx-&pix_fmt,
pCodecCtx-&width, pCodecCtx-&height, PIX_FMT_RGB24,
SWS_FAST_BILINEAR, NULL, NULL, NULL);
if (!pCodecCtx)
printf("Cannot initialize sws conversion context\r\n");
return NULL;
sws_scale(img_convert_ctx,
(const uint8_t* const*)pFrame-&data, pFrame-&linesize, 0,
pCodecCtx-&height, pFrameRGB-&data, pFrameRGB-&linesize);
// Save the frame to disk
if(++i&=5)
SaveFrame(pFrameRGB, pCodecCtx-&width,
pCodecCtx-&height, i);
// Free the packet that was allocated by av_read_frame
av_free_packet(&packet);
  这个循环过程是比较简单的:av_read_frame()读取一个包并且把它保存到AVPacket结构体中。注意我们仅仅申请了一个包的结构体 ――ffmpeg为我们申请了内部的数据的内存并通过packet.data指针来指向它。这些数据可以在后面通过av_free_packet()来释放。
& & & 函数avcodec_decode_video2()把包转换为帧。然而当解码一个包的时候,我们可能没有得到我们需要的关于帧的信息。因此,当我们得到下一帧的时候,avcodec_decode_video2()为我们设置了帧结束标志frameFinished。
& & & 然后,我们使用sws_getCachedContext()函数设置格式转换器,sws_scale()函数来把帧从原始格式(pCodecCtx-&pix_fmt)转换成为RGB格式。最后,我们把帧和高度宽度信息传递给我们的SaveFrame()函数,保存成PPM的图片。
步骤八:清理一切,程序结束
// Free the RGB image
av_free(buffer);
av_free(pFrameRGB);
// Free the YUV frame
av_free(pFrame);
// Close the codec
avcodec_close(pCodecCtx);
// Close the video file
av_close_input_file(pFormatCtx);
  一旦我们开始读取完视频流,退出前需要释放所有申请的空间。
以上,就是ffmpeg解码的基本流程。最近也比较忙,时间也比较晚了,累了犯困,就不在此赘述环境的配置了,附上工程下载地址有兴趣的自行研究吧!
同时,欢迎广大志同道合的朋友讨论交流,要知道,You are not alone !
阅读(...) 评论()FFmpeg解码H264及swscale缩放详解 - 推酷
FFmpeg解码H264及swscale缩放详解
本文概要:
& & & & 本文介绍著名开源音视频编解码库ffmpeg如何解码h264码流,比较详细阐述了其h264码流输入过程,解码原理,解码过程。同时,大部分应用环境下,以原始码流视频大小展示并不是最佳方式,因此,开发者不仅仅需要对视频流解码,并且需要缩放图像以展示于不同窗体下。
& & & & 综上,本文除介绍ffmpeg解码h264,同时阐述如何使用swscale缩放视频流。 & & &&
& & & & 文章使用的开发环境Ubuntu12.04.。交流邮箱:。
转载请注明出处 CSDN--固本培元。
ffmpeg介绍:
& & & & & FFmpeg是一个开源免费跨平台的视频和
方案,属于自由
,采用LGPL或GPL许可证(依据你选择的组件)。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec,为了保证高可移植性和编解码质量,libavcodec里很多codec都是从头开发的。
& & & & &好了,不多说了。直接上工程和代码吧。(注意在链接工程时,引用库有连接顺序,因为他们有相互依赖关系,如果缺少将不能通过编译。)
& & & & 需要连接的库: VS代码如下
#pragma comment (lib,&..\\FFMPEG_lib\\avformat.lib&)
#pragma comment (lib,&..\\FFMPEG_lib\\avutil.lib&)
#pragma comment (lib,&..\\FFMPEG_lib\\swscale.lib&)
#pragma comment (lib,&..\\FFMPEG_lib\\avcodec.lib&)
#pragma comment (lib,&..\\FFMPEG_lib\\avdevice.lib&)
#pragma comment (lib,&..\\FFMPEG_lib\\avfilter.lib&)
& & & & & 需要的头文件:
#include &libavcodec\\avcodec.h&
#include &libswscale/swscale.h&
& & & & & 环境初始化代码:(参考了api-example.c)ubuntu上使用的ffmpeg版本是0.6
avcodec_init(); //首先,main函数中一开始会去调用avcodec_init()函数,该函数的作用是初始化libavcodec,而我们在使用avcodec编解码库时,该函数必须被调用。
avcodec_register_all();//注册所有的编解码器(codecs),解析器(parsers)以及码流过滤器(bitstream filters)。当然我们也可以使用个别的注册函数来注册我们所要支持的格式。
AVCodecContext *c= NULL;
int frame, size, got_picture,
FILE *fin, *
AVFrame *picture,*dst_
uint8_t inbuf[INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE], *inbuf_
char buf[1024];
/* set end of buffer to 0 (this ensures that no overreading happens for damaged mpeg streams) */
memset(inbuf + INBUF_SIZE, 0, FF_INPUT_BUFFER_PADDING_SIZE);
printf(&Video decoding\n&);
/* find the mpeg1 video decoder */
codec = avcodec_find_decoder(CODEC_ID_H264);
if (!codec){
fprintf(stderr, &codec not found\n&);
c= avcodec_alloc_context();
picture= avcodec_alloc_frame();
if(codec-&capabilities&CODEC_CAP_TRUNCATED){
c-&flags|= CODEC_FLAG_TRUNCATED; /* we dont send complete frames */
/* for some codecs, such as msmpeg4 and mpeg4, width and height
MUST be initialized there because these info are not available
in the bitstream */
/* open it */
if (avcodec_open(c, codec) & 0){
fprintf(stderr, &could not open codec\n&);
& & & & & avcodec_init和avcodec_register_all初始化了相关的解码器,申请了解码需要的空间等。
& & & & & 其他解码需要具备的是AVcontext、AVCodec、以及AVFrame。
& & & & & AVContext是解码需要的环境,其中存储了比如长宽,编码器算法,位图格式等信息。
& & & & &AVCondec就是你所选择的的编解码器了,使用枚举来索引,申请空间后与解码函数配合使用。
& & & & &AVFrame与AVPicture比较像,都存储解码后的位图信息。
& & & & &avcodec_decode_video需要输入参数,AVContext,AVFrame,数据首地址以及数据长度。同时传入一个int指针用于记录解码返回的解码成功帧数。
& & & & &len记录本次解码消耗的字节数。
len = avcodec_decode_video(c, picture, &got_picture,
inbuf_ptr, size);
& & & & &注意:在解码过程中不要清理contxt环境,以及解码器,如果有必要字节流空间有保存意义,因为,264传输过程中,有PTS以及DTS之分,播放时间以及解码时间如果不一致,可能导致,先到数据需要存储后到达他解码时间时解码。
& & & & & 同时,h264码流分IPB帧,只有I帧是比较全面的图像信息。如果在解码I帧完成后,清空解码环境context,后续解码将持续返回错误信息,直至下一个I帧出现。作者亲测,望看到此文的朋友在做解码时不会再走这条弯路。
& & & & & 自此,解码部分阐述完毕。
& & & & & &
利用ffmpeg进行图像数据格式的转换以及图片的缩放应用中,主要用到了swscale.h文件中的三个函数,分别是:
struct SwsContext *sws_getContext(int srcW, int srcH, enum AVPixelFormat srcFormat,
int dstW, int dstH, enum AVPixelFormat dstFormat,
int flags, SwsFilter *srcFilter,
SwsFilter *dstFilter, const double *param);
int sws_scale(struct SwsContext *c, const uint8_t *const srcSlice[],
const int srcStride[], int srcSliceY, int srcSliceH,
uint8_t *const dst[], const int dstStride[]);
void sws_freeContext(struct SwsContext *swsContext);
&sws_getContext
函数可以看做是初始化函数,它的参数定义分别为:
& & & int srcW,int srcH 为原始图像数据的高和宽;
& & & int dstW,int dstH 为输出图像数据的高和宽;
& & &&enum AVPixelFormat srcFormat 为输入和输出图片数据的类型;eg:AV_PIX_FMT_YUV420、PAV_PIX_FMT_RGB24;
& & & int flags 为scale算法种类;eg:SWS_BICUBIC、SWS_BICUBLIN、SWS_POINT、SWS_SINC;
& & &&SwsFilter *srcFilter&,SwsFilter *dstFilter,const double *param 可以不用管,全为NULL即可;
函数则为执行函数,它的参数定义分别为:
& & &&struct SwsContext *c 为sws_getContext函数返回的值;
& & &&const uint8_t *const srcSlice[],uint8_t *const dst[]&为输入输出图像数据各颜色通道的buffer指针数组;
& & &&const int srcStride[],const int dstStride[]&为输入输出图像数据各颜色通道每行存储的字节数数组;& & &
& & &&int srcSliceY 为从输入图像数据的第多少列开始逐行扫描,通常设为0;
& & &&int srcSliceH 为需要扫描多少行,通常为输入图像数据的高度;
&sws_freeContext
函数为结束函数,它的参数即为sws_getContext函数返回的值;
& & & & &做一个实际缩放YUV420函数打包实例如下:
int ScaleImg(AVCodecContext *pCodecCtx,AVFrame *src_picture,AVFrame *dst_picture,int nDstH ,int nDstW )
int nSrcStride[3];
int nDstStride[3];
int nSrcH = pCodecCtx-&
int nSrcW = pCodecCtx-&
struct SwsContext* m_pSwsC
uint8_t *pSrcBuff[3] = {src_picture-&data[0],src_picture-&data[1], src_picture-&data[2]};
nSrcStride[0] = nSrcW ;
nSrcStride[1] = nSrcW/2 ;
nSrcStride[2] = nSrcW/2 ;
dst_picture-&linesize[0] = nDstW;
dst_picture-&linesize[1] = nDstW / 2;
dst_picture-&linesize[2] = nDstW / 2;
printf(&nSrcW%d\n&,nSrcW);
m_pSwsContext = sws_getContext(nSrcW, nSrcH, PIX_FMT_YUV420P,
nDstW, nDstH, PIX_FMT_YUV420P,
SWS_BICUBIC,
NULL, NULL, NULL);
if (NULL == m_pSwsContext)
printf(&ffmpeg get context error!\n&);
exit (-1);
sws_scale(m_pSwsContext, src_picture-&data,src_picture-&linesize, 0, pCodecCtx-&height,dst_picture-&data,dst_picture-&linesize);
printf(&line0:%d line1:%d line2:%d\n&,dst_picture-&linesize[0] ,dst_picture-&linesize[1] ,dst_picture-&linesize[2]);
sws_freeContext(m_pSwsContext);
return 1 ;
& & & & 函数很简单,申请环境初始指针,后缩放即可。读到此文的朋友,这个函数可以直接拷贝使用哟。如果有疑问可以留言或者邮件:
& & & & 下面有一个缩放图像的效果图:
目的位图的空间申请:
& & & &注意:上面的缩放函数如果直接使用而在没有解码成功或者没有申请目的位图空间时,将报段错误。
& & & 原因:没有解码成功,位图源地址将是指向空的地址,目的位图地址同样。
& & & 申请目的位图的方式:
dst_picture = avcodec_alloc_frame();
if (!dst_picture){
if(avpicture_alloc((AVPicture *)dst_picture, c-&pix_fmt,c-&width*2, c-&height*2)&0){
printf(&dst_picture allocate failed\n&);
& & & & &初始化后即可以用于缩放了。
图像的内存Dump方法:
& & & & 上文已经比较详细的阐述了ffmpeg的解码以及缩放原理及流程,然而在实际运用环境中,无论是从实时播放或者是从历史回放来看,我们需要的是像素位图,而不是ffmpeg的结构体。那么怎么转换呢?下文介绍了相关的内容。
& & & & 作为实际运用环境中,像素位图格式,笔者使用的是比较常用的YUV格式。
& & & & 编解码图像格式
& & & & & 承接上文继续,在大部分现场环境下,为了节省传送带宽以及提高系统工作效率,视频原始位图格式以及解码后展示格式一般使用YUV420。
& & & & & 其中YV12以及IYUV是最常见的格式。
& & & & & 简单的说,YUV格式又分为平面格式以及打包格式。他们各有利弊。本文使用的是YUV平面格式即三通道分别使用不同入口地址存储,这样的好处是,与ffmpeg解码接口方面,AVFrame中数据结构可以便捷拷贝图像信息。
& & & & &YV12:
& & & & &IYUV&
& & & & & 这里做简单的叙述:详细可以参考:
& & &如何Dump
& & & & & &好了,对YUV格式又初步了解后,下面介绍如果导出这像素位图数据。ffmpeg将图像的亮度以及色差信息保存在AVFrame中的data[0]、data[1]、data[2]中。
& & & & & 详细参考:
AVFrame和AVPicture对比:
& & & & & &所有操作均是针对这三个指针展开的,如下:
pgm_save(picture-&data[0], picture-&linesize[0], //Y
c-&width, c-&height, outfilename);
pgm_save(picture-&data[1], picture-&linesize[1],
c-&width/2, c-&height/2, outfilename); //U
pgm_save(picture-&data[2], picture-&linesize[2],
c-&width/2, c-&height/2, outfilename);
void pgm_save(unsigned char *buf,int wrap, int xsize,int ysize,char *filename)
f=fopen(filename,&ab+&);
for(i=0;i&i++)
fwrite(buf + i * wrap, 1, xsize, f );
fclose(f);
& & & & & & & & 代码对YUV三个像素通道分开dump,读者可以根据自己的需要对函数进行包装。data[0] 是亮度信息入口指针,同时传入图像长宽,以及存储内存区域行宽。&data[1] &data[2] 类似。
& & & & & & & & 最后需要注意的是:linesize总是容易被遗忘,livesize[0]=height ,livesize[1]=height/2 ,livesize[2]=height /2,
& & & & & & & &&
& & & & & & & &此文到此结束,感谢阅读。
& & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & & ---------------------leoluopy
参考文章:
使用ffmpeg进行图像格式转换及缩放
AVFrame和AVPicture对比:
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致21183人阅读
ffmpeg(3)
音频和视频其实是一样的,在文件中寻找音频流,然后解压出来,得到音频帧的数据,同样也可以按照设定的编码格式进行压缩,我这里把音频的解码和编码做成了两个工程,也是直接上代码:
#include &stdio.h&
#include &stdlib.h&
extern &C&
#include &libavcodec\avcodec.h&
#include &libavformat\avformat.h&
#include &libswscale\swscale.h&
int main(char arg,char *argv[])
char *filename = argv[1];
av_register_all(); //注册所有可解码类型
AVFormatContext *pInFmtCtx=NULL; //文件格式
AVCodecContext *pInCodecCtx=NULL; //编码格式
if (av_open_input_file(&pInFmtCtx, filename, NULL, 0, NULL)!=0) //获取文件格式
printf(&av_open_input_file error\n&);
if (av_find_stream_info(pInFmtCtx) & 0) //获取文件内音视频流的信息
printf(&av_find_stream_info error\n&);
// Find the first audio stream
int audioStream = -1;
for (j=0; j&pInFmtCtx-&nb_ j++) //找到音频对应的stream
if (pInFmtCtx-&streams[j]-&codec-&codec_type == CODEC_TYPE_AUDIO)
audioStream =
if (audioStream == -1)
printf(&input file has no audio stream\n&);
return 0; // Didn't find a audio stream
printf(&audio stream num: %d\n&,audioStream);
pInCodecCtx = pInFmtCtx-&streams[audioStream]-& //音频的编码上下文
AVCodec *pInCodec = NULL;
pInCodec = avcodec_find_decoder(pInCodecCtx-&codec_id); //根据编码ID找到用于解码的结构体
if (pInCodec == NULL)
printf(&error no Codec found\n&);
return -1 ; // Codec not found
if(avcodec_open(pInCodecCtx, pInCodec)&0)//将两者结合以便在下面的解码函数中调用pInCodec中的对应解码函数
printf(&error avcodec_open failed.\n&);
return -1; // Could not open codec
static AVP
printf(& bit_rate = %d \r\n&, pInCodecCtx-&bit_rate);
printf(& sample_rate = %d \r\n&, pInCodecCtx-&sample_rate);
printf(& channels = %d \r\n&, pInCodecCtx-&channels);
printf(& code_name = %s \r\n&, pInCodecCtx-&codec-&name);
printf(& block_align = %d\n&,pInCodecCtx-&block_align);
int out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE*100;
uint8_t * inbuf = (uint8_t *)malloc(out_size);
pcm = fopen(&result.pcm&,&wb&);
long start = clock();
while (av_read_frame(pInFmtCtx, &packet) &= 0)//pInFmtCtx中调用对应格式的packet获取函数
if(packet.stream_index==audioStream)//如果是音频
pktdata = packet.
pktsize = packet.
while(pktsize&0)
out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE*100;
int len = avcodec_decode_audio2(pInCodecCtx, (short*)inbuf, &out_size, pktdata, pktsize);
if (len & 0)
printf(&Error while decoding.\n&);
if(out_size & 0)
fwrite(inbuf,1,out_size,pcm);//pcm记录
fflush(pcm);
pktsize -=
pktdata +=
av_free_packet(&packet);
long end = clock();
printf(&cost time :%f\n&,double(end-start)/(double)CLOCKS_PER_SEC);
free(inbuf);
fclose(pcm);
if (pInCodecCtx!=NULL)
avcodec_close(pInCodecCtx);
av_close_input_file(pInFmtCtx);
解码后的文件保存为result.pcm中,现在用这个文件压缩出新的音频文件,代码如下:
void main()
uint8_t *audio_
int audio_outbuf_
int audio_input_frame_
double audio_
const char* filename = &test.wav&;
FILE *fin = fopen(&result.pcm&, &rb&); //音频源文件
AVOutputFormat *
AVFormatContext *
AVStream * audio_
av_register_all();
fmt = guess_format(NULL, filename, NULL);
oc = av_alloc_format_context();
oc-&oformat =
snprintf(oc-&filename, sizeof(oc-&filename), &%s&, filename);
audio_st = NULL;
if (fmt-&audio_codec != CODEC_ID_NONE)
AVCodecContext *c;
audio_st = av_new_stream(oc, 1);
c = audio_st-&
c-&codec_id = fmt-&audio_
c-&codec_type = CODEC_TYPE_AUDIO;
c-&bit_rate = 128000;
c-&sample_rate = 44100;
c-&channels = 2;
if (av_set_parameters(oc, NULL) & 0)
dump_format(oc, 0, filename, 1);
if (audio_st)
AVCodecContext*
c = audio_st-&
codec = avcodec_find_encoder(c-&codec_id);
avcodec_open(c, codec);
audio_outbuf_size = 10000;
audio_outbuf = (uint8_t*)av_malloc(audio_outbuf_size);
if (c-&frame_size &= 1)
audio_input_frame_size = audio_outbuf_size / c-&
switch (audio_st-&codec-&codec_id)
case CODEC_ID_PCM_S16LE:
case CODEC_ID_PCM_S16BE:
case CODEC_ID_PCM_U16LE:
case CODEC_ID_PCM_U16BE:
audio_input_frame_size &&= 1;
audio_input_frame_size = c-&frame_
samples = (int16_t*)av_malloc(audio_input_frame_size*2*c-&channels);
if (!fmt-&flags & AVFMT_NOFILE)
if (url_fopen(&oc-&pb, filename, URL_WRONLY) & 0)
av_write_header(oc);
if (audio_st)
audio_pts = (double)audio_st-&pts.val * audio_st-&time_base.num / audio_st-&time_base.
audio_pts = 0.0;
if (!audio_st || audio_pts &= 360.0)
if (fread(samples, 1, audio_input_frame_size*2*audio_st-&codec-&channels, fin) &= 0)
AVCodecContext*
av_init_packet(&pkt);
c = audio_st-&
pkt.size = avcodec_encode_audio(c, audio_outbuf, audio_outbuf_size, samples);
pkt.pts = av_rescale_q(c-&coded_frame-&pts, c-&time_base, audio_st-&time_base);
pkt.flags |= PKT_FLAG_KEY;
pkt.stream_index = audio_st-&
pkt.data = audio_
if (av_write_frame(oc, &pkt) != 0)
if (audio_st)
avcodec_close(audio_st-&codec);
av_free(samples);
av_free(audio_outbuf);
av_write_trailer(oc);
for (int i=0; i&oc-&nb_ i++)
av_freep(&oc-&streams[i]-&codec);
av_freep(&oc-&streams[i]);
if (!(fmt-&flags & AVFMT_NOFILE))
url_fclose(oc-&pb);
av_free(oc);
fclose(fin);
对应的下载链接:
音频解码:
音频编码:
至此,我已经实现了视频的解码编码,音频的解码编码,相信有心人肯定可以在此基础上实现视频音频的同步压缩,不过要再看一些网上的资料,也是很轻松的。至于视频的显示播放,大多数是要结合SDL实现,由于我只是浅尝辄止,只实现了图片的显示和简单的视频播放,比起我之前推荐的几个链接是弱爆了的,就不写下去了,这个系列就到这里吧,希望能给像我一样的一些入门级选手点帮助。也欢迎大神来多多指教。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1731934次
积分:15708
积分:15708
排名:第435名
原创:83篇
评论:1451条
文章:55篇
阅读:1354947
(1)(3)(1)(1)(4)(5)(3)(3)(6)(4)(1)(13)(23)(13)(1)(1)
&a href=&http://blog.csdn.net/xiaowei_cqu/&xiaowei_cqu

我要回帖

更多关于 ffmpeg3.1 音频解码 的文章

 

随机推荐