0. 引言

最近一直在使用和学习ffmpeg. 工作中需要拉流解码, 获取音频和视频数据. 这些都是使用ffmpeg处理.

  因为对ffmpeg接触不多, 用的不深, 在使用的过程中经常遇到不太懂的地方, 就会花费很多时间去查阅资料. 所以自己对用到的知识点总结一下, 方便自己以后再重复用到时能够方便找到.

  环境: ubuntu16.04, 已安装ffmpeg依赖库. gcc编译工具.

ffmpeg解码过程中用到了两个很重要的结构体, 这两个结构体比较复杂, 用到的次数也非常多, 以后我单独写一篇进行总结.

    • AVPacket 保存未解码的数据.
    • AVFrame 保存解码后的数据.

1. 解码流程

2. 代码

 //***************************************************************
// @file: test.c
// @author: dingfang
// @date 2019-07-24 18:55:16
//*************************************************************** #include <stdio.h> #ifdef __cplusplus
extern "C"
{
#endif
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#ifdef __cplusplus
};
#endif int openCodecContext(const AVFormatContext *pFormatCtx, int *pStreamIndex, enum AVMediaType type, AVCodecContext **ppCodecCtx)
{
int streamIdx = -;
// 获取流下标
for (int i = ; i < pFormatCtx->nb_streams; i++)
{
if (pFormatCtx->streams[i]->codec->codec_type == type)
{
streamIdx = i;
break;
}
}
if (streamIdx == -)
{
printf("find video stream failed!\n");
exit(-);
}
// 寻找解码器
AVCodecContext *pCodecCtx = pFormatCtx->streams[streamIdx]->codec;
AVCodec *pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if (NULL == pCodec)
{
printf("avcode find decoder failed!\n");
exit(-);
} //打开解码器
if (avcodec_open2(pCodecCtx, pCodec, NULL) < )
{
printf("avcode open failed!\n");
exit(-);
}
*ppCodecCtx = pCodecCtx;
*pStreamIndex = streamIdx; return ;
} int main(void)
{
AVFormatContext *pInFormatCtx = NULL;
AVCodecContext *pVideoCodecCtx = NULL;
AVCodecContext *pAudioCodecCtx = NULL;
AVPacket *pPacket = NULL;
AVFrame *pFrame = NULL;
int ret;
/* 支持本地文件和网络url */
const char streamUrl[] = "./test.flv"; /* 1. 注册 */
av_register_all(); pInFormatCtx = avformat_alloc_context(); /* 2. 打开流 */
if(avformat_open_input(&pInFormatCtx, streamUrl, NULL, NULL) != )
{
printf("Couldn't open input stream.\n");
return -;
} /* 3. 获取流的信息 */
if(avformat_find_stream_info(pInFormatCtx, NULL) < )
{
printf("Couldn't find stream information.\n");
return -;
} int videoStreamIdx = -;
int audioStreamIdx = -;
/* 4. 寻找并打开解码器 */
openCodecContext(pInFormatCtx, &videoStreamIdx, AVMEDIA_TYPE_VIDEO, &pVideoCodecCtx);
openCodecContext(pInFormatCtx, &audioStreamIdx, AVMEDIA_TYPE_AUDIO, &pAudioCodecCtx); pPacket = av_packet_alloc();
pFrame = av_frame_alloc(); int cnt = ;
while (cnt--)
{
/* 5. 读流数据, 未解码的数据存放于pPacket */
ret = av_read_frame(pInFormatCtx, pPacket);
if (ret < )
{
printf("av_read_frame error\n");
break;
} /* 6. 解码, 解码后的数据存放于pFrame */
/* 视频解码 */
if (pPacket->stream_index == videoStreamIdx)
{
avcodec_decode_video2(pVideoCodecCtx, pFrame, &ret, pPacket);
if (ret == )
{
printf("video decodec error!\n");
continue;
}
printf("* * * * * * video * * * * * * * * *\n");
printf("___height: [%d]\n", pFrame->height);
printf("____width: [%d]\n", pFrame->width);
printf("pict_type: [%d]\n", pFrame->pict_type);
printf("___format: [%d]\n", pFrame->format);
printf("* * * * * * * * * * * * * * * * * * *\n\n");
} /* 音频解码 */
if (pPacket->stream_index == audioStreamIdx)
{
avcodec_decode_audio4(pAudioCodecCtx, pFrame, &ret, pPacket);
if (ret < )
{
printf("audio decodec error!\n");
continue;
}
printf("* * * * * * audio * * * * * * * * * *\n");
printf("____nb_samples: [%d]\n", pFrame->nb_samples);
printf("__samples_rate: [%d]\n", pFrame->sample_rate);
printf("channel_layout: [%lu]\n", pFrame->channel_layout);
printf("________format: [%d]\n", pFrame->format);
printf("* * * * * * * * * * * * * * * * * * *\n\n");
}
av_packet_unref(pPacket);
} av_frame_free(&pFrame);
av_packet_free(&pPacket);
avcodec_close(pVideoCodecCtx);
avcodec_close(pAudioCodecCtx);
avformat_close_input(&pInFormatCtx); return ;
}

该代码不能直接编译, 编译需要依赖ffmpeg库. 包含ffmpeg动态库和makefile文件的压缩包地址: 点我下载

解压后, 进入目录, 使用make命令即可编译.

3. 函数说明

这里就几个比较重要的函数简单介绍一下.

av_register_all()        /* 使用ffmpeg几乎都要调用这一个函数, 注册ffmpeg各种编解码器, 复用器等. */

avformat_open_input()      /* 该函数用于打开本地多媒体文件或者网络流媒体url */

avformat_find_stream_info()   /* 该函数用于读取一部分音视频数据并且获得一些相关的信息 */

avcodec_find_decoder()    /* 由codec_id或者解码器名称来寻找对应的解码器 */

avcodec_open2()        /* 初始化解码器 */

av_read_frame()        /* 读流数据, 读出来的是压缩数据, 存放于AVPacket */

avcodec_decode_video2()    /* 视频解码 解码后数据为原始数据, 存放于AVFrame */

avcodec_decode_audio4()    /* 音频解码 解码后数据为原始数据, 存放于AVFrame */

ffmpeg解码音视频过程(附代码)的更多相关文章

  1. javaCV入门指南:调用FFmpeg原生API和JavaCV是如何封装了FFmpeg的音视频操作?

    通过"javaCV入门指南:序章 "大家知道了处理音视频流媒体的前置基本知识,基本知识包含了像素格式.编解码格式.封装格式.网络协议以及一些音视频专业名词,专业名词不会赘述,自行搜 ...

  2. FFmpeg处理音视频流程学习笔记

    原文作者:一叶知秋0830 链接:https://www.jianshu.com/p/1b715966af50 FFmpeg处理音视频完整流程包括5个阶段(输入文件—>编码数据包—>解码后 ...

  3. FFmpeg开发实战(五):FFmpeg 抽取音视频的视频数据

    如何使用FFmpeg抽取音视频的视频数据,代码如下: // FFmpegTest.cpp : 此文件包含 "main" 函数.程序执行将在此处开始并结束. // #include ...

  4. FFmpeg开发实战(四):FFmpeg 抽取音视频的音频数据

    如何使用FFmpeg抽取音视频的音频数据,代码如下: void adts_header(char *szAdtsHeader, int dataLen); // 使用FFmpeg从视频中抽取音频 vo ...

  5. iPhone调用ffmpeg2.0.2解码h264视频的示例代码

    iPhone调用ffmpeg2.0.2解码h264视频的示例代码 h264demo.zip 关于怎么在MAC下编译iOS下的ffmpeg请看 编译最新ffmpeg2.0.1(ffmpeg2.0.2)到 ...

  6. C#进程调用FFmpeg操作音视频

    项目背景 因为公司需要对音视频做一些操作,比如说对系统用户的发音和背景视频进行合成,以及对多个音视频之间进行合成,还有就是在指定的源背景音频中按照对应的规则在视频的多少秒钟内插入一段客户发音等一些复杂 ...

  7. FFmpeg Android 学习(一):Android 如何调用 FFMPEG 编辑音视频

    一.概述 在Android开发中,我们对一些音视频的处理比较无力,特别是编辑音视频这部分.而且在Android上对视频编辑方面,几乎没有任何API做支持,MediaCodec(硬编码)也没有做支持.那 ...

  8. ffmpeg 如何音视频同步

    转自:http://blog.csdn.net/yangzhiloveyou/article/details/8832516 output_example.c 中AV同步的代码如下(我的代码有些修改) ...

  9. 使用X264编码yuv格式的视频帧使用ffmpeg解码h264视频帧

    前面一篇博客介绍在centos上搭建点击打开链接ffmpeg及x264开发环境.以下就来问个样例: 1.利用x264库将YUV格式视频文件编码为h264格式视频文件 2.利用ffmpeh库将h264格 ...

随机推荐

  1. Doki Doki Literature Club ZOJ - 4035

    Doki Doki Literature Club ZOJ - 4035 题解:其实就是简单排序输出就没了. #include <cstdio> #include <cstring& ...

  2. windows游戏编程X86实模式和保护模式

    本系列文章由jadeshu编写,转载请注明出处.http://blog.csdn.net/jadeshu/article/details/22309359 作者:jadeshu   邮箱: jades ...

  3. ImportError: No module named pytz

    xxx@hostname:/opt/xx/cc$ python manage.py runserver Traceback (most recent call last): File , in < ...

  4. python 进程池和任务量变化测试

    今天闲,测试了下concurrent.futures 模块中的ThreadPoolExecutor,ProcessPoolExecutor. 对开不同的数量的进程池和任务量时,所耗时间. from c ...

  5. spring中文参考指南

    主要是4.x版本的 比较全面的:https://muyinchen.gitbooks.io/spring-framework-5-0-0-m3/content/3.5-bean/3.5.4-reque ...

  6. 初中知识回顾tan,sin,cos关系

    如果K=tan, sin 是X x=k/power(1+k*k,0.5)  开平方 cos是y y=1.0/power(1+k*k,0.5) 开平方 gisoracle总结 ============= ...

  7. 2.5 Go语言基础之map

    Go语言中提供的映射关系容器为map, Go中内置类型,其内部使用散列表(hash)实现,为引用类型. 无序键值对(key-value)集合,通过key(类似索引)快速检索数据 必须初始化才能使用. ...

  8. android java.util.Date和java.util.sql中Date的区别

    1.将java.util.Date 转换为 java.sql.Date java.sql.Date sd; java.util.Date ud; //initialize the ud such as ...

  9. 阶段5 3.微服务项目【学成在线】_day02 CMS前端开发_16-CMS前端工程创建-导入系统管理前端工程

    提供了基于脚手架封装好的前端工程 H:\BaiDu\黑马传智JavaEE57期 2019最新基础+就业+在职加薪\阶段5 3.微服务项目[学成在线]·\day02 CMS前端开发\资料\xc-ui-p ...

  10. PowerDesigner常用命令

    在Tools=>Execute Commands下的Edit/Run Scripts,或者通过Ctrl+Shift+X就可以运行脚本.如图: 1.将所有的表名和列名都修改为大写 '******* ...