
第一步:组册组件
av_register_all()
例如:编码器、解码器等等…
第二步:打开封装格式->打开文件
例如:mp4、mov、wmv文件等等
avformat_open_input();
第三步:查找视频流
如果是视频解码,那么查找视频流,如果是音频解码,那么就查找音频流
avformat_find_stream_info();
第四步:查找视频解码器
1、查找视频流索引位置
2、根据视频流索引,获取解码器上下文
3、根据解码器上下文,获得解码器ID,然后查找解码器
第五步:打开解码器
avcodec_open2();
第六步:读取视频压缩数据->循环读取
没读取一帧数据,立马解码一帧数据
第七步:视频解码->播放视频->得到视频像素数据
第八步:关闭解码器->解码完成
//第一步:组册组件
av_register_all();
//第二步:打开封装格式->打开文件
//参数一:封装格式上下文
//作用:保存整个视频信息(解码器、编码器等等)
//信息:码率、帧率等
AVFormatContext avformat_context = avformat_alloc_context();
//参数二:视频路径
const char url = [jinFilePath UTF8String]
//参数三:指定输入的格式
//参数四:设置默认参数
int avformat_open_input_result = avformat_open_input(&avformat_context, url,NULL, NULL);
if (avformat_open_input_result !=0){
NSLog("打开文件失败");
//不同的平台替换不同平台log日志
return;
}
//第三步:查找视频流->拿到视频信息
//参数一:封装格式上下文
//参数二:指定默认配置
int avformat_find_stream_info_result = avformat_find_stream_info(avformat_context,NULL);
if (avformat_find_stream_info_result <0){
NSLog(" 查找失败");
return;
}
//第四步:查找视频解码器
//1、查找视频流索引位置
int av_stream_index = -1;
for (int i =0; i < avformat_context->nb_streams; ++i) {
//判断流类型:视频流、音频流、字母流等等
if (avformat_context->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){
av_stream_index = i;
break;
}
}
//2、根据视频流索引,获取解码器上下文
AVCodecContext avcodec_context = avformat_context->streams[av_stream_index]->codec;
//3、根据解码器上下文,获得解码器ID,然后查找解码器
AVCodec avcodec = avcodec_find_decoder(avcodec_context->codec_id);
//第五步:打开解码器
int avcodec_open2_result = avcodec_open2(avcodec_context, avcodec,NULL);
if (avcodec_open2_result !=0){
NSLog("打开解码器失败");
return;
}
//第六步:读取视频压缩数据->循环读取
//1、分析av_read_frame参数
//参数一:封装格式上下文
//参数二:一帧压缩数据 = 一张
//av_read_frame()
//结构体大小计算:字节对齐原则
AVPacket packet = (AVPacket)av_malloc(sizeof(AVPacket));
//32 解码一帧视频压缩数据->进行解码(作用:用于解码 *** 作)
//开辟一块内存空间
AVFrame avframe_in = av_frame_alloc();
int decode_result =0;
//4、注意:在这里我们不能够保证解码出来的一帧视频像素数据格式是yuv格式
//参数一:源文件->原始视频像素数据格式宽
//参数二:源文件->原始视频像素数据格式高
//参数三:源文件->原始视频像素数据格式类型
//参数四:目标文件->目标视频像素数据格式宽
//参数五:目标文件->目标视频像素数据格式高
//参数六:目标文件->目标视频像素数据格式类型
SwsContext swscontext = sws_getContext(avcodec_context->width,
avcodec_context->height,
avcodec_context->pix_fmt,
avcodec_context->width,
avcodec_context->height,
AV_PIX_FMT_YUV420P,
SWS_BICUBIC,
NULL,
NULL,
NULL);
//创建一个yuv420视频像素数据格式缓冲区(一帧数据)
AVFrame avframe_yuv420p = av_frame_alloc();
//给缓冲区设置类型->yuv420类型
//得到YUV420P缓冲区大小
//参数一:视频像素数据格式类型->YUV420P格式
//参数二:一帧视频像素数据宽 = 视频宽
//参数三:一帧视频像素数据高 = 视频高
//参数四:字节对齐方式->默认是1
int buffer_size = av_image_get_buffer_size(AV_PIX_FMT_YUV420P,
avcodec_context->width,
avcodec_context->height,
1);
//开辟一块内存空间
uint8_t out_buffer = (uint8_t )av_malloc(buffer_size);
//向avframe_yuv420p->填充数据
//参数一:目标->填充数据(avframe_yuv420p)
//参数二:目标->每一行大小
//参数三:原始数据
//参数四:目标->格式类型
//参数五:宽
//参数六:高
//参数七:字节对齐方式
av_image_fill_arrays(avframe_yuv420p->data,
avframe_yuv420p->linesize,
out_buffer,
AV_PIX_FMT_YUV420P,
avcodec_context->width,
avcodec_context->height,
1);
int y_size, u_size, v_size;
//52 将yuv420p数据写入yuv文件中
//打开写入文件
const char outfile = [joutFilePath UTF8String];
FILE file_yuv420p = fopen(outfile,"wb+");
if (file_yuv420p ==NULL){
NSLog("输出文件打开失败");
return;
}
int current_index =0;
while (av_read_frame(avformat_context, packet) >=0){
//>=:读取到了
//<0:读取错误或者读取完毕
//2、是否是我们的视频流
if (packet->stream_index == av_stream_index){
//第七步:解码
//学习一下C基础,结构体
//3、解码一帧压缩数据->得到视频像素数据->yuv格式
//采用新的API
//31 发送一帧视频压缩数据
avcodec_send_packet(avcodec_context, packet);
//32 解码一帧视频压缩数据->进行解码(作用:用于解码 *** 作)
decode_result = avcodec_receive_frame(avcodec_context, avframe_in);
if (decode_result ==0){
//解码成功
//4、注意:在这里我们不能够保证解码出来的一帧视频像素数据格式是yuv格式
//视频像素数据格式很多种类型: yuv420P、yuv422p、yuv444p等等
//保证:我的解码后的视频像素数据格式统一为yuv420P->通用的格式
//进行类型转换: 将解码出来的视频像素点数据格式->统一转类型为yuv420P
//sws_scale作用:进行类型转换的
//参数一:视频像素数据格式上下文
//参数二:原来的视频像素数据格式->输入数据
//参数三:原来的视频像素数据格式->输入画面每一行大小
//参数四:原来的视频像素数据格式->输入画面每一行开始位置(填写:0->表示从原点开始读取)
//参数五:原来的视频像素数据格式->输入数据行数
//参数六:转换类型后视频像素数据格式->输出数据
//参数七:转换类型后视频像素数据格式->输出画面每一行大小
sws_scale(swscontext,
(const uint8_t const )avframe_in->data,
avframe_in->linesize,
0,
avcodec_context->height,
avframe_yuv420p->data,
avframe_yuv420p->linesize);
//方式一:直接显示视频上面去
//方式二:写入yuv文件格式
//5、将yuv420p数据写入yuv文件中
//51 计算YUV大小
//分析一下原理
//Y表示:亮度
//UV表示:色度
//有规律
//YUV420P格式规范一:Y结构表示一个像素(一个像素对应一个Y)
//YUV420P格式规范二:4个像素点对应一个(U和V: 4Y = U = V)
y_size = avcodec_context->width avcodec_context->height;
u_size = y_size /4;
v_size = y_size /4;
//52 写入yuv文件
//首先->Y数据
fwrite(avframe_yuv420p->data[0], 1, y_size, file_yuv420p);
//其次->U数据
fwrite(avframe_yuv420p->data[1], 1, u_size, file_yuv420p);
//再其次->V数据
fwrite(avframe_yuv420p->data[2], 1, v_size, file_yuv420p);
current_index++;
NSLog("当前解码第%d帧", current_index);
}
}
}
//第八步:释放内存资源,关闭解码器
av_packet_free(&packet);
fclose(file_yuv420p);
av_frame_free(&avframe_in);
av_frame_free(&avframe_yuv420p);
free(out_buffer);
avcodec_close(avcodec_context);
avformat_free_context(avformat_context);
表示上游节点的传出边缘;可以用来创建更多的下游节点。
输入文件 URL (ffmpeg -i option)
在一个 ffmpeg 命令行中包含所有给定的输出
输出文件地址
不询问就覆盖输出文件(ffmpeg -y 选项)
在指定文件上运行 ffprobe 并返回输出的 JSON 表示。
构建用于调用 ffmpeg 的命令行。
构建要传递给 ffmpeg 的命令行参数。
为提供的节点图调用 ffmpeg 。
参数
为提供的节点图异步调用 ffmpeg。
参数
例子
运行和流式输入:
运行并捕获输出:
使用 numpy 逐帧处理视频:
通过重新混合颜色通道来调整视频输入帧。
连接音频和视频流,将它们一个接一个地连接在一起。
筛选器适用于同步视频和音频流的片段。所有段必须具有每种类型的相同数量的流,这也是输出时的流数。
参数
裁剪输入视频。
参数
在输入图像上绘制一个彩色框。
参数
使用 libfreetype 库从视频顶部的指定文件中绘制文本字符串或文本。
要启用此过滤器的编译,您需要使用 --enable-libfreetype 要启用默认字体回退和字体选项,您需要使用 --enable-libfontconfig 要启用 text_shaping 选项,您需要使用 --enable-libfribidi
参数
· box - 用于使用背景颜色在文本周围绘制一个框。该值必须是 1(启用)或 0(禁用)。框的默认值为 0。
· boxborderw – 使用 boxcolor 设置要在框周围绘制的边框宽度。boxborderw 的默认值为 0。
· boxcolor - 用于在文本周围绘制框的颜色。有关此选项的语法,请查看 ffmpeg-utils 手册中的“颜色”部分。 boxcolor 的默认值为“white”。
· line_spacing – 使用 box 设置要在框周围绘制的边框的行间距(以像素为单位)。line_spacing 的默认值为 0。
· borderw – 使用边框颜色设置要在文本周围绘制的边框宽度。边框的默认值为 0。
· bordercolor – 设置用于在文本周围绘制边框的颜色。有关此选项的语法,请查看 ffmpeg-utils 手册中的“颜色”部分。边框颜色的默认值为“黑色”。
· 扩展- 选择文本的扩展方式。可以是 none、strftime(已弃用)或 normal(默认)。有关详细信息,请参阅下面的文本扩展部分。
· basetime – 设置计数的开始时间。值以微秒为单位。仅适用于已弃用的 strftime 扩展模式。要在正常扩展模式下进行模拟,请使用 pts 函数,提供开始时间(以秒为单位)作为第二个参数。
· fix_bounds - 如果为 true,检查并修复文本坐标以避免剪切。
· fontcolor - 用于绘制字体的颜色。有关此选项的语法,请查看 ffmpeg-utils 手册中的“颜色”部分。fontcolor 的默认值为“黑色”。
· fontcolor_expr – 与文本相同的扩展字符串以获得动态字体颜色值。默认情况下,此选项具有空值并且不被处理。设置此选项时,它会覆盖 fontcolor 选项。
· font - 用于绘制文本的字体系列。默认情况下无。
· fontfile – 用于绘制文本的字体文件。必须包含路径。如果禁用了 fontconfig 支持,则此参数是必需的。
· alpha – 绘制应用 alpha 混合的文本。该值可以是介于 00 和 10 之间的数字。该表达式也接受相同的变量 x、y。默认值为 1。请参阅 fontcolor_expr。
· fontsize – 用于绘制文本的字体大小。字体大小的默认值为 16。
· text_shaping – 如果设置为 1,则在绘制文本之前尝试对文本进行整形(例如,反转从右到左文本的顺序并加入阿拉伯字符)。否则,只需按照给定的方式绘制文本。默认为 1(如果支持)。
· ft_load_flags –用于加载字体的标志。这些标志映射了 libfreetype 支持的相应标志,并且是以下值的组合:
默认值为“默认”。有关更多信息,请参阅 FT_LOAD_ libfreetype 标志的文档。
· shadowcolor – 用于在已绘制文本后面绘制阴影的颜色。有关此选项的语法,请查看 ffmpeg-utils 手册中的“颜色”部分。shadowcolor 的默认值为“黑色”。
· shadowx – 文本阴影位置相对于文本位置的 x 偏移量。它可以是正值或负值。默认值为“0”。
· shadowy – 文本阴影位置相对于文本位置的 y 偏移量。它可以是正值或负值。默认值为“0”。
· start_number – n/frame_num 变量的起始帧号。默认值为“0”。
· tabsize - 用于呈现选项卡的空格数大小。默认值为 4。
· timecode – 以“hh:mm:ss[:;]ff”格式设置初始时间码表示。它可以带或不带文本参数使用。必须指定 timecode_rate 选项。
· rate – 设置时间码帧率(仅限时间码)。
· timecode_rate – 的别名rate。
· r – 的别名rate。
· tc24hmax – 如果设置为 1,时间码选项的输出将在 24 小时左右回绕。默认值为 0(禁用)。
· text -- 要绘制的文本字符串。文本必须是 UTF-8 编码字符序列。如果没有使用参数 textfile 指定文件,则此参数是必需的。
· textfile – 包含要绘制的文本的文本文件。文本必须是 UTF-8 编码字符序列。如果没有使用参数 text 指定文本字符串,则此参数是必需的。如果同时指定了 text 和 textfile,则会引发错误。
· reload – 如果设置为 1,文本文件将在每一帧之前重新加载。一定要自动更新它,否则它可能会被部分读取,甚至失败。
· x – 指定将在视频帧内绘制文本的偏移量的表达式。它相对于输出图像的左边框。默认值为“0”。
· y - 指定将在视频帧内绘制文本的偏移量的表达式。它相对于输出图像的上边框。默认值为“0”。有关接受的常量和函数的列表,请参见下文。
表达式常量:
x 和 y 的参数是包含以下常量和函数的表达式:
· dar:输入显示纵横比,同 (w / h) sar
· hsub:水平色度子样本值。例如,对于像素格式“yuv422p”,hsub 为 2,vsub 为 1。
· vsub:垂直色度子样本值。例如,对于像素格式“yuv422p”,hsub 为 2,vsub 为 1。
· line_h:每个文本行的高度
· lh:别名为line_h
· main_h:输入高度
· h: 的别名main_h。
· H: 的别名main_h。
· main_w:输入宽度
· w: 的别名main_w。
· W: 的别名main_w。
· ascent:对于所有渲染的字形,从基线到用于放置字形轮廓点的最高/上网格坐标的最大距离。这是一个正值,因为网格的 Y 轴向上。
· max_glyph_a: 的别名ascent。
· 下降:对于所有渲染的字形,从基线到用于放置字形轮廓点的最低网格坐标的最大距离。由于网格的方向,这是一个负值,Y 轴向上。
· max_glyph_d: 的别名descent。
· max_glyph_h:最大字形高度,即渲染文本中包含的所有字形的最大高度,相当于上升-下降。
· max_glyph_w:最大字形宽度,即渲染文本中包含的所有字形的最大宽度。
· n:输入帧数,从0开始
· rand(min, max):返回一个包含在 min 和 max 之间的随机数
· sar:输入样本纵横比。
· t:时间戳,以秒为单位,如果输入时间戳未知,则为 NAN
· text_h:渲染文本的高度
· th: 的别名text_h。
· text_w:渲染文本的宽度
· tw: 的别名text_w。
· x:绘制文本的 x 偏移坐标。
· y:绘制文本的 y 偏移坐标。
这些参数允许 x 和 y 表达式相互引用,因此您可以例如指定 y=x/dar
应用自定义过滤器。
filter通常由更高级别的过滤器函数使用,例如 hflip ,但如果缺少过滤器实现 ffmpeg-python ,您可以 filter 直接调用以 ffmpeg-python 将过滤器名称和参数逐字传递给 ffmpeg 。
参数
函数名称后缀_是为了避免与标准 pythonfilter 函数混淆。
例子
替代名称 filter ,以免与内置的 pythonfilter 运算符冲突。
应用具有一个或多个输出的自定义过滤器。
这 filter 与过滤器可以产生多个输出相同。
要引用输出流,请使用 stream 运算符或括号简写:
例子
水平翻转输入视频。
修改输入的色调和/或饱和度。
参数
将一个视频叠加在另一个视频之上。
参数
更改输入帧的 PTS(表示时间戳)。
FFmpeg里有两种时间戳:DTS(Decoding Time Stamp)和PTS(Presentation Time Stamp)。 顾名思义,前者是解码的时间,后者是显示的时间。
参数
修剪输入,使输出包含输入的一个连续子部分。
参数
垂直翻转输入视频。
应用缩放和平移效果。
参数
转换压缩视频,要求视频通过 ffmpeg 压缩后视频清晰不卡顿,并且视频体积要求比较小
-r 帧率 -r 12 一秒12帧,一秒15帧可以看到比较流畅。
-vf scale=1366:768 分辨率可以设置小一点,为了清晰可以适当调整,同时也会影响到视频体积大小。
-crf 这里设置36, 一般18-28 就差不多了,这里因为要求视频压缩后越小越好,因此调整为36。
以上三条把握好,就可以压缩出来体积小清晰流畅的视频了,具体压缩效果以及参数可以根据现场情况自己进行测试。
//第一步:注册组件->编码器、解码器等等…
av_register_all();
//第二步:初始化封装格式上下文->视频编码->处理为视频压缩数据格式
AVFormatContext avformat_context = avformat_alloc_context();
//注意事项:FFmepg程序推测输出文件类型->视频压缩数据格式类型
const char coutFilePath = [outFilePath UTF8String];
//得到视频压缩数据格式类型(h264、h265、mpeg2等等)
AVOutputFormat avoutput_format = av_guess_format(NULL, coutFilePath, NULL);
//指定类型
avformat_context->oformat = avoutput_format;
//第三步:打开输出文件
//参数一:输出流
//参数二:输出文件
//参数三:权限->输出到文件中
if (avio_open(&avformat_context->pb, coutFilePath, AVIO_FLAG_WRITE) < 0) {
NSLog(@"打开输出文件失败");
return;
}
//第四步:创建输出码流->创建了一块内存空间->并不知道他是什么类型流->希望他是视频流
AVStream av_video_stream = avformat_new_stream(avformat_context, NULL);
//第五步:查找视频编码器
//1、获取编码器上下文
AVCodecContext avcodec_context = av_video_stream->codec;
//2、设置编解码器上下文参数->必需设置->不可少
//目标:设置为是一个视频编码器上下文->指定的是视频编码器
//上下文种类:视频解码器、视频编码器、音频解码器、音频编码器
//21 设置视频编码器ID
avcodec_context->codec_id = avoutput_format->video_codec;
//22 设置编码器类型->视频编码器
//视频编码器->AVMEDIA_TYPE_VIDEO
//音频编码器->AVMEDIA_TYPE_AUDIO
avcodec_context->codec_type = AVMEDIA_TYPE_VIDEO;
//23 设置读取像素数据格式->编码的是像素数据格式->视频像素数据格式->YUV420P(YUV422P、YUV444P等等)
//注意:这个类型是根据你解码的时候指定的解码的视频像素数据格式类型
avcodec_context->pix_fmt = AV_PIX_FMT_YUV420P;
//24 设置视频宽高->视频尺寸
avcodec_context->width = 640;
avcodec_context->height = 352;
//25 设置帧率->表示每秒25帧
//视频信息->帧率 : 25000 fps
//f表示:帧数
//ps表示:时间(单位:每秒)
avcodec_context->time_basenum = 1;
avcodec_context->time_baseden = 25;
//26 设置码率
//261 什么是码率?
//含义:每秒传送的比特(bit)数单位为 bps(Bit Per Second),比特率越高,传送数据速度越快。
//单位:bps,"b"表示数据量,"ps"表示每秒
//目的:视频处理->视频码率
//262 什么是视频码率
//含义:视频码率就是数据传输时单位时间传送的数据位数,一般我们用的单位是kbps即千位每秒
//视频码率计算如下?
//基本的算法是:码率(kbps)=视频大小 - 音频大小(bit位) /时间(秒)
//例如:Testmov时间 = 24,文件大小(视频+音频) = 173MB
//视频大小 = 134MB(文件占比:77%) = 134MB 1024 1024 8 = 字节大小 = 468365字节 = 468Kbps
//音频大小 = 376KB(文件占比:21%)
//计算出来值->码率 : 468Kbps->表示1000,b表示位(bit->位)
//总结:码率越大,视频越大
avcodec_context->bit_rate = 468000;
//27 设置GOP->影响到视频质量问题->画面组->一组连续画面
//MPEG格式画面类型:3种类型->分为->I帧、P帧、B帧
//I帧->内部编码帧->原始帧(原始视频数据)
// 完整画面->关键帧(必需的有,如果没有I,那么你无法进行编码,解码)
// 视频第1帧->视频序列中的第一个帧始终都是I帧,因为它是关键帧
//P帧->向前预测帧->预测前面的一帧类型,处理数据(前面->I帧、B帧)
// P帧数据->根据前面的一帧数据->进行处理->得到了P帧
//B帧->前后预测帧(双向预测帧)->前面一帧和后面一帧
// B帧压缩率高,但是对解码性能要求较高。
//总结:I只需要考虑自己 = 1帧,P帧考虑自己+前面一帧 = 2帧,B帧考虑自己+前后帧 = 3帧
// 说白了->P帧和B帧是对I帧压缩
//每250帧,插入1个I帧,I帧越少,视频越小->默认值->视频不一样
avcodec_context->gop_size = 250;
//28 设置量化参数->数学算法(高级算法)->不讲解了
//总结:量化系数越小,视频越是清晰
//一般情况下都是默认值,最小量化系数默认值是10,最大量化系数默认值是51
avcodec_context->qmin = 10;
avcodec_context->qmax = 51;
//29 设置b帧最大值->设置不需要B帧
avcodec_context->max_b_frames = 0;
//第二点:查找编码器->h264
//找不到编码器->h264
//重要原因是因为:编译库没有依赖x264库(默认情况下FFmpeg没有编译进行h264库)
//第一步:编译h264库
AVCodec avcodec = avcodec_find_encoder(avcodec_context->codec_id);
if (avcodec == NULL) {
NSLog(@"找不到编码器");
return;
}
NSLog(@"编码器名称为:%s", avcodec->name);
//第六步:打开h264编码器
//缺少优化步骤?
//编码延时问题
//编码选项->编码设置
AVDictionary param = 0;
if (avcodec_context->codec_id == AV_CODEC_ID_H264) {
//需要查看x264源码->x264c文件
//第一个值:预备参数
//key: preset
//value: slow->慢
//value: superfast->超快
av_dict_set(¶m, "preset", "slow", 0);
//第二个值:调优
//key: tune->调优
//value: zerolatency->零延迟
av_dict_set(¶m, "tune", "zerolatency", 0);
}
if (avcodec_open2(avcodec_context, avcodec, ¶m) < 0) {
NSLog(@"打开编码器失败");
return;
}
//第七步:写入文件头信息
avformat_write_header(avformat_context, NULL);
//第8步:循环编码yuv文件->视频像素数据(yuv格式)->编码->视频压缩数据(h264格式)
//81 定义一个缓冲区
//作用:缓存一帧视频像素数据
//811 获取缓冲区大小
int buffer_size = av_image_get_buffer_size(avcodec_context->pix_fmt,
avcodec_context->width,
avcodec_context->height,
1);
//812 创建一个缓冲区
int y_size = avcodec_context->width avcodec_context->height;
uint8_t out_buffer = (uint8_t ) av_malloc(buffer_size);
//813 打开输入文件
const char cinFilePath = [inFilePath UTF8String];
FILE in_file = fopen(cinFilePath, "rb");
if (in_file == NULL) {
NSLog(@"文件不存在");
return;
}
//821 开辟一块内存空间->av_frame_alloc
//开辟了一块内存空间
AVFrame av_frame = av_frame_alloc();
//822 设置缓冲区和AVFrame类型保持一直->填充数据
av_image_fill_arrays(av_frame->data,
av_frame->linesize,
out_buffer,
avcodec_context->pix_fmt,
avcodec_context->width,
avcodec_context->height,
1);
int i = 0;
//92 接收一帧视频像素数据->编码为->视频压缩数据格式
AVPacket av_packet = (AVPacket ) av_malloc(buffer_size);
int result = 0;
int current_frame_index = 1;
while (true) {
//81 从yuv文件里面读取缓冲区
//读取大小:y_size 3 / 2
if (fread(out_buffer, 1, y_size 3 / 2, in_file) <= 0) {
NSLog(@"读取完毕");
break;
}else if (feof(in_file)) {
break;
}
//82 将缓冲区数据->转成AVFrame类型
//给AVFrame填充数据
//823 void restrict->->转成->AVFrame->ffmpeg数据类型
//Y值
av_frame->data[0] = out_buffer;
//U值
av_frame->data[1] = out_buffer + y_size;
//V值
av_frame->data[2] = out_buffer + y_size 5 / 4;
av_frame->pts = i;
//注意时间戳
i++;
//总结:这样一来我们的AVFrame就有数据了
//第9步:视频编码处理
//91 发送一帧视频像素数据
avcodec_send_frame(avcodec_context, av_frame);
//92 接收一帧视频像素数据->编码为->视频压缩数据格式
result =avcodec_receive_packet(avcodec_context, av_packet);
//93 判定是否编码成功
if (result == 0) {
//编码成功
//第10步:将视频压缩数据->写入到输出文件中->outFilePath
av_packet->stream_index = av_video_stream->index;
result =av_write_frame(avformat_context, av_packet);
NSLog(@"当前是第%d帧", current_frame_index);
current_frame_index++;
//是否输出成功
if (result < 0) {
NSLog(@"输出一帧数据失败");
return;
}
}
}
//第11步:写入剩余帧数据->可能没有
flush_encoder(avformat_context, 0);
//第12步:写入文件尾部信息
av_write_trailer(avformat_context);
//第13步:释放内存
avcodec_close(avcodec_context);
av_free(av_frame);
av_free(out_buffer);
av_packet_free(&av_packet);
avio_close(avformat_context->pb);
avformat_free_context(avformat_context);
fclose(in_file);
以上就是关于FFmpeg的视频解码详解全部的内容,包括:FFmpeg的视频解码详解、ffmpeg-python中文文档(三)——API参考、C# 使用神器ffmpeg.exe 压缩视频,流畅清晰体积小等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)