一、解封装基本流程

  ①av_register_All()////初始化解封装,注册解析和封装的格式。
  ②avformat_netword_init()//初始化网络,解析rtsp协议
  ③avformat_open_init()//打开
  ④avformat_find_stream_info()//探测
  ⑤av_find_best_stream() //获取音视频的索引
  ⑥av_read_Frame()//读一帧数据,音频可能好几帧、视频是I帧
  ⑦av_seek_frame()//跳转

二、函数介绍

  ①av_register_all();
    初始化解封装,注册解封装格式
    在最开始编译FFmpeg的时候,我们做了一个configure的配置,其中开启或者关闭了很多选项。configure的配置会生成两个文件:config.mk和config.h。
      config.mk:就是makefile文件需要包含进去的子模块,会作用在编译阶段,帮助开发者编译出正确的库。
      config.h:作用在运行阶段,主要是确定需要注册那些容器及编解码格式到FFmpeg框架中。
    调用 av_register_all 就可以注册config.h里面开发的编解码器,然后会注册所有的Muxer和Demuxer(封装格式),最后注册所有的Protocol(协议)。

  ②avformat_network_init();
    初始化网络,rtsp流

  ③avformat_open_input(&ic,path,0,0);
    打开文件并解析视频流、音频流、流的参数,
      参数:AVFormactContext **ps;
           const char *URL;
           AVInputFormat *fmt;
           AVDictionary *options;

  ④avformat_find_stream_info()
    探测

  ⑤av_find_best_stream()
    获取对应的视频流或者视频流 还有一种方式:遍历返回值的一个成员(Stream数组),根据标志位判断是音频还是视频。

  ⑥av_read_frame();
    从AVPacket中,读取帧信息,av_read_packet函数读出的是包,其可能是半帧或者多帧,不保证帧的完整性。
    av_read_frame对av_read_packet进行了封装,使其读出的数据总是完整的帧,av_read_frame函数调用了read_fram_internal。读取码流中若干个音频帧或者I帧视频。例如,在解码视频的时候,每解码一个视频,需要先调用av_read_frame获得一帧视频的压缩数据,然后才能对该数据进行解码
    返回值有三种结果:
      ①如果packet_buffer存在数据,根据PTS返回AVPacket。
      ②如果packet_buffer不存在数据,调用av_read_frame_internal函数。
      ③(待补充)

代码展示:

/*****************************FILE INFOMATION***********************************
** av_register_all();
//初始化解封装,注册解封装格式
在最开始编译FFmpeg的时候,我们做了一个configure的配置,其中开启或者关闭了很多选项。configure的配置会生成两个文件:config.mk和config.h。
config.mk:就是makefile文件需要包含进去的子模块,会作用在编译阶段,帮助开发者编译出正确的库。
config.h:作用在运行阶段,主要是确定需要注册那些容器及编解码格式到FFmpeg框架中。
调用 av_register_all 就可以注册config.h里面开发的编解码器,然后会注册所有的Muxer和Demuxer(封装格式),最后注册所有的Protocol(协议)。 avformat_network_init();
//初始化网络,rtsp流 avformat_open_input(&ic,path,0,0);
//打开文件并解析视频流、音频流、流的参数,
参数:AVFormactContext **ps;
const char *URL;
AVInputFormat *fmt;
AVDictionary *options; avformat_find_stream_info()
//探测 av_find_best_stream()
//获取对应的视频流或者视频流 还有一种方式:遍历返回值的一个成员(Stream数组),根据标志位判断是音频还是视频。 av_read_frame();
从AVPacket中,读取帧信息,av_read_packet函数读出的是包,其可能是半帧或者多帧,不保证帧的完整性。
av_read_frame对av_read_packet进行了封装,使其读出的数据总是完整的帧,av_read_frame函数调用了read_fram_internal。
读取码流中若干个音频帧或者I帧视频。例如,在解码视频的时候,每解码一个视频,需要先调用av_read_frame获得一帧视频的压缩数据,然后才能对该数据进行解码
返回值有三种结果:
①如果packet_buffer存在数据,根据PTS返回AVPacket。
②如果packet_buffer不存在数据,调用av_read_frame_internal函数。
③不够清晰?(android视频开发书) **
*******************************************************************************/ #include <jni.h>
#include <string>
#include <android/log.h>
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,"testff",__VA_ARGS__) extern "C"{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
}
#include<iostream>
using namespace std; static double r2d(AVRational r)
{
return r.num==||r.den == ? :(double)r.num/(double)r.den;
} extern "C"
JNIEXPORT jstring
JNICALL
Java_aplay_testffmpeg_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++ ";
hello += avcodec_configuration();
//初始化解封装
av_register_all();
//初始化网络
avformat_network_init(); //打开文件
AVFormatContext *ic = NULL;
char path[] = "/sdcard/1080.mp4";
//char path[] = "/sdcard/video.flv";
int re = avformat_open_input(&ic,path,,);
if(re != )
{
LOGW("avformat_open_input failed!:%s",av_err2str(re));
return env->NewStringUTF(hello.c_str());
}
LOGW("avformat_open_input %s success!",path);
//获取流信息
re = avformat_find_stream_info(ic,);
if(re != )
{
LOGW("avformat_find_stream_info failed!");
}
LOGW("duration = %lld nb_streams = %d",ic->duration,ic->nb_streams); int fps = ;
int videoStream = ;
int audioStream = ; for(int i = ; i < ic->nb_streams; i++)
{
AVStream *as = ic->streams[i];
if(as->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
{
LOGW("视频数据");
videoStream = i;
fps = r2d(as->avg_frame_rate); LOGW("fps = %d,width=%d height=%d codeid=%d pixformat=%d",fps,
as->codecpar->width,
as->codecpar->height,
as->codecpar->codec_id,
as->codecpar->format
);
}
else if(as->codecpar->codec_type ==AVMEDIA_TYPE_AUDIO )
{
LOGW("音频数据");
audioStream = i;
LOGW("sample_rate=%d channels=%d sample_format=%d",
as->codecpar->sample_rate,
as->codecpar->channels,
as->codecpar->format
);
}
}
//ic->streams[videoStream];
//获取音频流信息
audioStream = av_find_best_stream(ic,AVMEDIA_TYPE_AUDIO,-,-,NULL,);
LOGW("av_find_best_stream audioStream = %d",audioStream); //读取帧数据
AVPacket *pkt = av_packet_alloc();
for(;;)
{
int re = av_read_frame(ic,pkt);
if(re != )
{ LOGW("读取到结尾处!");
int pos = * r2d(ic->streams[videoStream]->time_base);
av_seek_frame(ic,videoStream,pos,AVSEEK_FLAG_BACKWARD|AVSEEK_FLAG_FRAME );
continue;
}
LOGW("stream = %d size =%d pts=%lld flag=%d",
pkt->stream_index,pkt->size,pkt->pts,pkt->flags
);
////////////////////// av_packet_unref(pkt);
} //关闭上下文
avformat_close_input(&ic);
return env->NewStringUTF(hello.c_str());
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_aplay_testffmpeg_MainActivity_Open(JNIEnv *env, jobject instance, jstring url_,
jobject handle) {
const char *url = env->GetStringUTFChars(url_, ); // TODO
FILE *fp = fopen(url,"rb");
if(!fp)
{
LOGW("File %s open failed!",url);
}
else
{
LOGW("File %s open succes!",url);
fclose(fp);
}
env->ReleaseStringUTFChars(url_, url);
return true;
}
												

FFmpeg(二) 解封装相关函数理解的更多相关文章

  1. FFmpeg4.0笔记:封装ffmpeg的解封装功能类CDemux

    Github https://github.com/gongluck/FFmpeg4.0-study/tree/master/Cff CDemux.h /*********************** ...

  2. FFmpeg(三) 编解码相关函数理解

    一.编解码基本流程 主要流程: 打开视频解码器(音频一样) 软解码.硬解码 进行编解码 下面先来看打开视频解码器 ①avcodec_register_all()//初始化解码 ②先找到解码器. 找解码 ...

  3. FFmpeg(四) 像素转换相关函数理解

    一.基本流程 1.sws_getCachedContext();//得到像素转换的上下文 2.sws_scale()://进行转换 二.函数说明 1.SwsContext *vctx = NULL;  ...

  4. FFmpeg音视频解封装

    一 . 解封装用到的函数和结构体 1.av_register_all() : open 一次就调用一次 2.avformat_network_init() : 网络模块初始化 3.avformat_o ...

  5. 深入理解MVC C#+HtmlAgilityPack+Dapper走一波爬虫 StackExchange.Redis 二次封装 C# WPF 用MediaElement控件实现视频循环播放 net 异步与同步

    深入理解MVC   MVC无人不知,可很多程序员对MVC的概念的理解似乎有误,换言之他们一直在错用MVC,尽管即使如此软件也能被写出来,然而软件内部代码的组织方式却是不科学的,这会影响到软件的可维护性 ...

  6. 《手把手教你》系列基础篇(九十七)-java+ selenium自动化测试-框架设计篇-Selenium方法的二次封装和页面基类(详解教程)

    1.简介 上一篇宏哥介绍了如何设计支持不同浏览器测试,宏哥的方法就是通过来切换配置文件设置的浏览器名称的值,来确定启动什么浏览器进行脚本测试.宏哥将这个叫做浏览器引擎类.这个类负责获取浏览器类型和启动 ...

  7. FFmpeg软硬解和多线程解码

    一. AVCodecContext解码上下文 1.avcodec_register_all() : 注册所有的解码器 2.AVCodec *avcodec_find_decoder(enum AVCo ...

  8. ffmpeg 详解

    来源:http://blog.itpub.net/9399028/viewspace-1242300/ FFMPEG详解   认识FFMPEG FFMPEG堪称自由软件中最完备的一套多媒体支持库,它几 ...

  9. element el-table表格的vue组件二次封装(附表格高度自适应)

    基于vue的el-table表格二次封装组件方法 前言 在公司实习使用vue+element-ui框架进行前端开发,使用表格el-table较为多,有些业务逻辑比较相似,有些地方使用的重复性高,如果多 ...

随机推荐

  1. bzoj 1146 网络管理Network (CDQ 整体二分 + 树刨)

    题目传送门 题意:求树上路径可修改的第k大值是多少. 题解:CDQ整体二分+树刨. 每一个位置上的数都会有一段持续区间 根据CDQ拆的思维,可以将这个数拆成出现的时间点和消失的时间点. 然后通过整体二 ...

  2. 字符编码与gcc 编译器的编码问题

    最近在 vscode 中借助 gcc 编译器来配置 c 语言开发环境时,发现中文编码存在乱码问题.再加上最近学习到多字节字符与宽字符,搅在一起,搞得很乱,就把自己的理解写下来,供有需者参考吧. 1. ...

  3. Flask源码浅析

    前言 学习一样东西,要先知其然,然后知其所以然. 这次,我们看看Flask Web框架的源码.我会以Flask 0.1的源码为例,把重点放在Flask如何处理请求上,看一看从一个请求到来到返回响应都经 ...

  4. 【Offer】[4] 【二维数组中的查找】

    题目描述 思路分析 Java代码 代码链接 题目描述 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数 ...

  5. Intro to Machine Learning

    本节主要用于机器学习入门,介绍两个简单的分类模型: 决策树和随机森林 不涉及内部原理,仅仅介绍基础的调用方法 1. How Models Work 以简单的决策树为例 This step of cap ...

  6. HashMap面试必问的数据结构相关知识

    如果在看这篇文章时,对HashMap的结构还不是很了解,建议你参考前段时间写的<刨死你系列——HashMap剖析(基于jdk1.8)>,可能会对下面的提及到知识点有些帮助. 1:HashM ...

  7. git:clone 本地克隆的几种情况

    环境 当前文件夹 d:\mygit\ clone到当前文件 git clone http://x.com/mytest.git /* 结果: 会在当前文件夹下生成 mytest 默认文件夹 完整路径 ...

  8. F#周报2019年第37期

    新闻 宣告ML.NET 1.4的预览版及更新模型构建器 .NET展示会:一系列的活动! Octopus入门版:对于小团队免费 宣告.NET Core 3.0预览版9 使用IntelliCode更简单地 ...

  9. HTML5为什么只需要写<!DOCTYPE HTML>?

    HTML4.01中的doctype需要对DTD进行引用,因为HTML4.01基于SGML.而HTML5不基于SGML,因此不需要对DTD进行引用,但是需要doctype来规范浏览器的行为.其中,SGM ...

  10. Winforn中使用代码动态生成控件

    场景 有时候需要根据配置文件在窗体中使用代码动态生成控件. 比如读取xml配置文件中的节点数量,然后在窗体中生成指定数量的RadioGroup控件. 实现 新建一个窗体,在窗体的加载完之后的事件中 p ...