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. MongoDB-查询关键字/排序等

    查询关键字 并列查询$and # 条件都成立才可以查询到结果 db.stutent.find({$and:[{name:"小漩涡"},{age:30}]}) 或查询$or # 有一 ...

  2. CF1208C

    CF1208C 这场杜老师大战tourist的比赛怎么这么多人类智慧题... 题意: 构造一个 $ n \times n $ 的矩阵,使得该矩阵每一行与每一列的元素的异或和全部相等. 解法: 异或的神 ...

  3. iptables 查看对应规则及端口号

    iptables -L -n --line-number

  4. flask 中扩展 flask-login

  5. 记录linux 生成crash dump文件步骤

    执行文件编译时加入-g 命令 例如 g++ -g test.cpp 查看当前系统限制情况 ulimit -a 设置crash dump 文件大小 ulimit -c unlimited unlimit ...

  6. Eclipse添加Android library 错误的原因

    这两天把项目从本地转移到GIT上,本来我的Workspace是在D盘,现在因为感觉D盘不够用,就把GIT到的项目放到E盘了 按照以往的用法,GIT下来以后再往属性里添加依赖库就OK了,但是这次怎么也无 ...

  7. React开发环境配置

    本文以上一篇文章继续配置:npm安装及环境配置<https://www.cnblogs.com/hzb462606/p/11565275.html> 使用 create-react-app ...

  8. CSS3常用属性及效果汇总

    本文转载于<https://blog.csdn.net/lyznice/article/details/54575905> 一.2D效果属性 要使用这些属性,我们需要通过 transfor ...

  9. AppCode 2016.3 注册码

    43B4A73YYJ-eyJsaWNlbnNlSWQiOiI0M0I0QTczWVlKIiwibGljZW5zZWVOYW1lIjoibGFuIHl1IiwiYXNzaWduZWVOYW1lIjoiI ...

  10. Java连接阿里云HBase示例

    使用前要在阿里云的 HBase控制台中点击"修改网络白名单",然后将你的ip地址(会有提示的)添加到网络白名单中,这样以后才能访问. 所需依赖: <dependencies& ...