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. Java 使用线程池分批插入或者更新数据

    需求:在开发业务报表时,需要从MySQL数据库读取数据后进行操作,然后写入数据库,使用定时任务跑批. 分析:①兼顾性能,②  MySQL没有Oracle那么方便.强大的存储过程.综上所述,使用线程池以 ...

  2. AtomicInteger原理

    AtomicInteger的原理 java的并发原子包里面提供了很多可以进行原子操作的类,比如: AtomicInteger AtomicBoolean AtomicLong AtomicRefere ...

  3. Handler常见两种用法

    1.Handler在Android的两个功能 1.1表示未来某时做某事 1.2线程间通信 2.演示源码如下: package com.example.datastrorage; import andr ...

  4. [maven]scope之test

    <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit ...

  5. [Scikit-learn] *2.3 Clustering - DBSCAN: Density-Based Spatial Clustering of Applications with Noise

    http://scikit-learn.org/stable/modules/generated/sklearn.cluster.DBSCAN.html#sklearn.cluster.DBSCAN ...

  6. Cobbler安装报错--dhcpd -t failed Exception occured: <class 'cobbler.cexceptions.CX'>

    最近想玩一下自动化安装,就研究了一下cobbler,测试环境本来是想用CentOS6.X的,但是后来一想,还是想用CentOS7.X.然后就碰到坑了. 在同步cobbler配置的时候,发现了以下错误: ...

  7. find_player 不查找已经晕到玩家的问题

    问题场景: 游戏中出现个BUG,是关于登陆后出现分身的问题. 查找当前登陆者的身份 是否之前存在相同的角色实例,当玩家昏迷状态时 使用 find_player是找不到这个玩家的,所以 玩家利用角色昏迷 ...

  8. JS创建类和对象,看完了,头就不大了

    JavaScript 创建类/对象的几种方式 在JS中,创建对象(Create Object)并不完全是我们时常说的创建类对象,JS中的对象强调的是一种复合类型,JS中创建对象及对对象的访问是极其灵活 ...

  9. Flutter 的异步机制Future

    Dart是一个单线程语言,可以理解成物理线路中的串联,当其遇到有延迟的运算(比如IO操作.延时执行)时,线程中按顺序执行的运算就会阻塞,用户就会感觉到卡顿,于是通常用异步处理来解决这个问题. Dart ...

  10. webdriervAPI(多表单切换)

    讲三个方法 driver.switch_to.frame("第一个iframe标签属性值") driver.switch_to.frame(" 第二个iframe标签属性 ...