ffmpeg解封装及解码实战


目录

  1. 封装格式相关函数
  2. 解封装流程
  3. 补充
  4. 分离AAC和H264

1. 封装格式相关函数

1. 基本概念

2. 相关函数

1. avformat_alloc_context();负责申请一个AVFormatContext结构的内存,并进行简单初始化
2. avformat_free_context();释放AVFormatContext及其所有流。
3. avformat_close_input();关闭解复用器。关闭后就不再需要使用avformat_free_context 进行释放
4. avformat_open_input();打开输入视频文件
  1. 打开一个输入流并读取报头。编解码器未打开。
  2. 流必须用avformat_close_input()关闭。
  3. ps指向用户提供的AVFormatContext(由avformat_alloc_context分配)的指针。可能是一个指向NULL的指针,在哪种情况下AVFormatContext是由这个分配的函数并写入ps。
  4. 内部有调用avformat_alloc_context()
5. avformat_find_stream_info():获取音视频文件信息
6. av_read_frame(); 读取音视频包
7. avformat_seek_file(); 定位文件
8. av_seek_frame():定位文件

2. 解封装流程

3. 补充

1. 区分不同的码流

  1. AVMEDIA_TYPE_VIDEO视频流:video_index = av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO,
    -1,-1, NULL, 0)
  2. AVMEDIA_TYPE_AUDIO音频流:audio_index = av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO,
    -1,-1, NULL, 0)
  3. AVPacket 里面也有一个index的字段

2. 补充点

  1. avformat_open_input和avformat_find_stream_info分别用于打开一个流和分析流信息。
  2. 在初始信息不足的情况下(比如FLV和H264文件),avformat_find_stream_info接口需要在内部调用read_frame_internal接口读取流数据(音视频帧),然后再分析后,设置核心数据结构AVFormatContext。
  3. 由于需要读取数据包, avformat_find_stream_info接口会带来很大的延迟

4. 分离AAC和H264

  1. 代码
#include <stdio.h>
#include <libavformat/avformat.h>int main(int argc, char **argv) {//打开网络流。这里如果只需要读取本地媒体文件,不需要用到网络功能,可以不用加上这一句
//    avformat_network_init();const char *default_filename = "believe.mp4";char *in_filename = NULL;if (argv[1] == NULL) {in_filename = default_filename;} else {in_filename = argv[1];}printf("in_filename = %s\n", in_filename);//AVFormatContext是描述一个媒体文件或媒体流的构成和基本信息的结构体AVFormatContext *ifmt_ctx = NULL;           // 输入文件的demuxint videoindex = -1;        // 视频索引int audioindex = -1;        // 音频索引// 打开文件,主要是探测协议类型,如果是网络文件则创建网络链接int ret = avformat_open_input(&ifmt_ctx, in_filename, NULL, NULL);if (ret < 0)  //如果打开媒体文件失败,打印失败原因{char buf[1024] = {0};av_strerror(ret, buf, sizeof(buf) - 1);printf("open %s failed:%s\n", in_filename, buf);goto failed;}ret = avformat_find_stream_info(ifmt_ctx, NULL);if (ret < 0)  //如果打开媒体文件失败,打印失败原因{char buf[1024] = {0};av_strerror(ret, buf, sizeof(buf) - 1);printf("avformat_find_stream_info %s failed:%s\n", in_filename, buf);goto failed;}//打开媒体文件成功printf_s("\n==== av_dump_format in_filename:%s ===\n", in_filename);av_dump_format(ifmt_ctx, 0, in_filename, 0);printf_s("\n==== av_dump_format finish =======\n\n");// url: 调用avformat_open_input读取到的媒体文件的路径/名字printf("media name:%s\n", ifmt_ctx->url);// nb_streams: nb_streams媒体流数量printf("stream number:%d\n", ifmt_ctx->nb_streams);// bit_rate: 媒体文件的码率,单位为bpsprintf("media average ratio:%lldkbps\n", (int64_t)(ifmt_ctx->bit_rate / 1024));// 时间int total_seconds, hour, minute, second;// duration: 媒体文件时长,单位微妙total_seconds = (ifmt_ctx->duration) / AV_TIME_BASE;  // 1000us = 1ms, 1000ms = 1秒hour = total_seconds / 3600;minute = (total_seconds % 3600) / 60;second = (total_seconds % 60);//通过上述运算,可以得到媒体文件的总时长printf("total duration: %02d:%02d:%02d\n", hour, minute, second);printf("\n");/** 老版本通过遍历的方式读取媒体文件视频和音频的信息* 新版本的FFmpeg新增加了函数av_find_best_stream,也可以取得同样的效果*/for (uint32_t i = 0; i < ifmt_ctx->nb_streams; i++) {AVStream *in_stream = ifmt_ctx->streams[i];// 音频流、视频流、字幕流//如果是音频流,则打印音频的信息if (AVMEDIA_TYPE_AUDIO == in_stream->codecpar->codec_type) {printf("----- Audio info:\n");// index: 每个流成分在ffmpeg解复用分析后都有唯一的index作为标识printf("index:%d\n", in_stream->index);// sample_rate: 音频编解码器的采样率,单位为Hzprintf("samplerate:%dHz\n", in_stream->codecpar->sample_rate);// codecpar->format: 音频采样格式if (AV_SAMPLE_FMT_FLTP == in_stream->codecpar->format) {printf("sampleformat:AV_SAMPLE_FMT_FLTP\n");} else if (AV_SAMPLE_FMT_S16P == in_stream->codecpar->format) {printf("sampleformat:AV_SAMPLE_FMT_S16P\n");}// channels: 音频信道数目printf("channel number:%d\n", in_stream->codecpar->channels);// codec_id: 音频压缩编码格式if (AV_CODEC_ID_AAC == in_stream->codecpar->codec_id) {printf("audio codec:AAC\n");} else if (AV_CODEC_ID_MP3 == in_stream->codecpar->codec_id) {printf("audio codec:MP3\n");} else {printf("audio codec_id:%d\n", in_stream->codecpar->codec_id);}// 音频总时长,单位为秒。注意如果把单位放大为毫秒或者微妙,音频总时长跟视频总时长不一定相等的if (in_stream->duration != AV_NOPTS_VALUE) {int duration_audio = (in_stream->duration) * av_q2d(in_stream->time_base);//将音频总时长转换为时分秒的格式打印到控制台上printf("audio duration: %02d:%02d:%02d\n",duration_audio / 3600, (duration_audio % 3600) / 60, (duration_audio % 60));} else {printf("audio duration unknown");}printf("\n");audioindex = i; // 获取音频的索引} else if (AVMEDIA_TYPE_VIDEO == in_stream->codecpar->codec_type)  //如果是视频流,则打印视频的信息{printf("----- Video info:\n");printf("index:%d\n", in_stream->index);// avg_frame_rate: 视频帧率,单位为fps,表示每秒出现多少帧printf("fps:%lffps\n", av_q2d(in_stream->avg_frame_rate));if (AV_CODEC_ID_MPEG4 == in_stream->codecpar->codec_id) //视频压缩编码格式{printf("video codec:MPEG4\n");} else if (AV_CODEC_ID_H264 == in_stream->codecpar->codec_id) //视频压缩编码格式{printf("video codec:H264\n");} else {printf("video codec_id:%d\n", in_stream->codecpar->codec_id);}// 视频帧宽度和帧高度printf("width:%d height:%d\n", in_stream->codecpar->width,in_stream->codecpar->height);//视频总时长,单位为秒。注意如果把单位放大为毫秒或者微妙,音频总时长跟视频总时长不一定相等的if (in_stream->duration != AV_NOPTS_VALUE) {int duration_video = (in_stream->duration) * av_q2d(in_stream->time_base);printf("video duration: %02d:%02d:%02d\n",duration_video / 3600,(duration_video % 3600) / 60,(duration_video % 60)); //将视频总时长转换为时分秒的格式打印到控制台上} else {printf("video duration unknown");}printf("\n");videoindex = i;}}AVPacket *pkt = av_packet_alloc();int pkt_count = 0;int print_max_count = 10;printf("\n-----av_read_frame start\n");while (1) {ret = av_read_frame(ifmt_ctx, pkt);if (ret < 0) {printf("av_read_frame end\n");break;}if (pkt_count++ < print_max_count) {if (pkt->stream_index == audioindex) {printf("audio pts: %lld\n", pkt->pts);printf("audio dts: %lld\n", pkt->dts);printf("audio size: %d\n", pkt->size);printf("audio pos: %lld\n", pkt->pos);printf("audio duration: %lf\n\n",pkt->duration * av_q2d(ifmt_ctx->streams[audioindex]->time_base));} else if (pkt->stream_index == videoindex) {printf("video pts: %lld\n", pkt->pts);printf("video dts: %lld\n", pkt->dts);printf("video size: %d\n", pkt->size);printf("video pos: %lld\n", pkt->pos);printf("video duration: %lf\n\n",pkt->duration * av_q2d(ifmt_ctx->streams[videoindex]->time_base));} else {printf("unknown stream_index:\n", pkt->stream_index);}}av_packet_unref(pkt);}if (pkt)av_packet_free(&pkt);failed:if (ifmt_ctx)avformat_close_input(&ifmt_ctx);getchar(); //加上这一句,防止程序打印完信息马上退出return 0;
}
  1. 结果

ffmpeg解封装及解码实战相关推荐

  1. FFmpeg解封装、解码音频和视频(分别使用OpenGL和OpenAL播放)

    1 ffmpeg解码大致流程   下图是ffmpeg解码播放音视频的基本流程: 首先是网络媒体解协议,解协议之后得到对应的媒体文件比如mp4,ts等,这些格式是媒体文件的封装格式,也就是将音频,视频, ...

  2. 【FFmpeg】详解FFmpeg解封装、解码流程

    目录 1.获取媒体信息头 2.获取媒体流信息 3.准备解码器 3.1 获取视频.音频.字幕流在解封装上下文 AVFormatContext 的流列表 AVStream **streams 中的索引 3 ...

  3. FFmpeg入门详解之43:FFmpeg解封装的原理与实战

    FFMpeg 解封装 本例子实现的是将音视频分离,例如将封装格式为 FLV.MKV.MP4.AVI 等封装格式的文件,将音频.视频分离开来. 大致的解封装流程: 1.首先要对解复用器进行初始化. 2. ...

  4. 解封装(一):ffmpeg解封装

    1.注意:什么是解封装,就是将二进制音视频文件,开始音视频文件分离,解码的具体操作. 2.解封装没有严格的性能问题.它的开销非常小. 3.解封装使用的一些接口 (1)av_register_all() ...

  5. ffmpeg解封装代码示例

    视频封装概述 MP4 格式分析 解封装流程 AVFormatContext nb_streams: 有多少条流,比如视频流.音频流 streams: 流的相关信息 AVStream AVCodecPa ...

  6. ffmpeg解复用编解码 常用API大全给出详细中文解释

    int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags); 将你给出的条目设置进入你给到的 p ...

  7. ffmpeg解封装出来的h264裸流设置SPS、PPS

    注:本文转自https://blog.csdn.net/qingkongyeyue/article/details/54023323 SPS:H.264码流第一个 NALU是 SPS(序列参数集Seq ...

  8. FFmpeg解封装通用代码

    先定义好需要的类型 AVFormatContext *ifmt_ctx = NULL;int video_index = -1;int audio_index = -1;AVPacket *packe ...

  9. 如何利用ffmpeg提供的API函数进行多媒体文件的解封装

    多媒体已经无处不在,程序员必须知道的一些多媒体封装知识 如何利用ffmpeg提供的API函数进行多媒体文件的解封装. 上一篇文章我们搭好了环境并编译出所需的ffmpeg库,本篇我们讨论如何利用ffmp ...

最新文章

  1. Python最常用的函数、基础语句有哪些?
  2. 下拉刷新:继承listView控件
  3. [洛谷 1883]函数 三分法
  4. c语言程序设计电大形考作业答案,2016年电大-电大c语言程序设计形成性考核册答案(-).doc...
  5. 带通滤波器中心频率计算公式中R是哪个值_LCC-HVDC 交流滤波器选择策略
  6. 外键设置中的CASCADE、NO ACTION、RESTRICT、SET NULL的区别
  7. Veeam备份的虚拟机恢复后遇到磁盘问题无法打开虚拟机
  8. 山东省软件设计大赛-比赛经历
  9. 008_SSSS_ Improved Denoising Diffusion Probabilistic Models
  10. CSS:让图片保持长宽比 自适应缩小放大 解决方案
  11. 山海演武传·黄道·第一卷 雏龙惊蛰 第二章 修闵本饰邪
  12. SqlSugar.SqlSugarException: English Message : Connection open error . 给定关键字不在字典中
  13. synchronized锁升级那点事
  14. 暑期实习Day7---SpringMVC
  15. CATIA CAA二次开发专题(四)------创建自己的Addin
  16. java线程池介绍(一)
  17. opencv4.5.1 包含了BEBLID算子,一个新的局部特征描述符,超越ORB
  18. 90后准程序猿写给前辈们的一封信
  19. 一种MVVM风格的Android项目架构浅析
  20. 看了100%会做艺术二维码的制作教程

热门文章

  1. top.location.href和localtion.href有什么不同
  2. spring boot(二):web综合开发
  3. 如何提问问题?--《提问的智慧》再次推荐
  4. 给vs2010安装上cocos2d-x的模版
  5. 分享几款linux的歌词插件
  6. CodeForces - 528D Fuzzy Search(多项式匹配字符串)
  7. 牛客 - Elo mountains(AC自动机+可持久化数组优化)
  8. POJ - 1226 Substrings(后缀数组+二分)
  9. 关于ax+by+cz的最大不可表数
  10. 朴素容斥原理[ZJOI2016][bzoj4455]小星星