① FFmpeg音视频的基础名词解释
是指视频文件在单位时间内使用的数据流量,也叫码率或码流率,通俗一点的理解就是取样率,是视频编码中画面质量控制中最重要的部分,一般我们用的单位是kb/s或者Mb/s。一般来说同样分辨率下,视频文件的码流越大,压缩比就越小,画面质量就越高。码流越大,说明单位时间内取样率越大,数据流,精度就越高,处理出来的文件就越接近原始文件,图像质量越好,画质越清晰,要求播放设备的解码能力也越高。 当然,码流越大,文件体积也越大,其计算公式是文件体积=时间X码率/8。例如,网络上常见的一部90分钟1Mbps码流的720P RMVB文件,其体积就=5400秒×1Mb/8=675MB。通常来说,一个视频文件包括了画面及声音,例如一个RMVB的视频文件,里面包含了视频信息和音频信息,音频及视频都有各自不同的采样方式和比特率,也就是说,同一个视频文件音频和视频的比特率并不是一样的。而我们所说的一个视频文件码流率大小,一般是指视频文件中音频及视频信息码流率的总和。以以国内最流行,大家最熟悉的RMVB视频文件为例,RMVB中的VB,指的是VBR,即Variable Bit Rate的缩写,中文含义是可变比特率,它表示RMVB采用的是动态编码的方式,把较高的采样率用于复杂的动态画面(歌舞、飞车、战争、动作等),而把较低的采样率用于静态画面,合理利用资源,达到画质与体积可兼得的效果。 我的理解码流就是视频/音频文件的每秒的大小,码率越高文件越大,呈现出来的失帧也就越低
采样率(也称为采样速度或者采样频率)定义了每秒从连续信号中提取并组成离散信号的采样个数,它用 赫兹 (Hz)来表示。采样率是指将模拟信号转换成数字信号时的采样频率,也就是单位时间内采样多少点。一个采样点数据有多少个比特。比特率是指每秒传送的比特(bit)数。单位为 bps(Bit Per Second),比特率越高,传送的数据越大,音质越好.比特率 =采样率 x 采用位数 x声道数. 采样率类似于动态影像的帧数,比如电影的采样率是24赫兹,PAL制式的采样率是25赫兹,NTSC制式的采样率是30赫兹。当我们把采样到的一个个静止画面再以采样率同样的速度回放时,看到的就是连续的画面。同样的道理,把以44.1kHZ采样率记录的CD以同样的速率播放时,就能听到连续的声音。显然,这个采样率越高,听到的声音和看到的图像就越连贯。当然,人的听觉和视觉器官能分辨的采样率是有限的,基本上高于44.1kHZ采样的声音,绝大部分人已经觉察不到其中的分别了。而声音的位数就相当于画面的颜色数,表示每个取样的数据量,当然数据量越大,回放的声音越准确,不至于把开水壶的叫声和火车的鸣笛混淆。同样的道理,对于画面来说就是更清晰和准确,不至于把血和西红柿酱混淆。不过受人的器官的机能限制,16位的声音和24位的画面基本已经是普通人类的极限了,更高位数就只能靠仪器才能分辨出来了。比如电话就是3kHZ取样的7位声音,而CD是44.1kHZ取样的16位声音,所以CD就比电话更清楚。 我的理解采样率就是每秒采集音视频的点,比如我们通常说的8k 16k与44100
比特率是指每秒传送的比特(bit)数。单位为bps(Bit Per Second),比特率越高,传送的数据越大。在视频领域,比特率常翻译为码率 比特率是指每秒传送的比特(bit)数。单位为bps(Bit Per Second),比特率越高,传送的数据越大。在视频领域,比特率常翻译为码率 !!! 比特率表示经过编码(压缩)后的音、视频数据每秒钟需要用多少个比特来表示,而比特就是二进制里面最小的单位,要么是0,要么是1。比特率与音、视频压缩的关系,简单的说就是比特率越高,音、视频的质量就越好,但编码后的文件就越大;如果比特率越少则情况刚好相反。比特率是指将数字声音、视频由模拟格式转化成数字格式的采样率,采样率越高,还原后的音质、画质就越好。 我的理解是比特率与采样率概念相同,不过采样率是压缩前的比特率是压缩后的
VBR(Variable Bitrate)动态比特率 也就是没有固定的比特率,压缩软件在压缩时根据音频数据即时确定使用什么比特率,这是以质量为前提兼顾文件大小的方式,推荐编码模式;
ABR(Average Bitrate)平均比特率 是VBR的一种插值参数。LAME针对CBR不佳的文件体积比和VBR生成文件大小不定的特点独创了这种编码模式。ABR在指定的文件大小内,以每50帧(30帧约1秒)为一段,低频和不敏感频率使用相对低的流量,高频和大动态表现时使用高流量,可以做为VBR和CBR的一种折衷选择。
CBR(Constant Bitrate),常数比特率 指文件从头到尾都是一种位速率。相对于VBR和ABR来讲,它压缩出来的文件体积很大,而且音质相对于VBR和ABR不会有明显的提高。
帧速率也称为FPS(Frames PerSecond)的缩写——帧/秒。是指每秒钟刷新的图片的帧数,也可以理解为图形处理器每秒钟能够刷新几次。越高的帧速率可以得到更流畅、更逼真的动画。每秒钟帧数(FPS)越多,所显示的动作就会越流畅。 就是俗称的每秒多少帧,例如我们众所周知的动画24帧/每秒
就是帧大小每一帧就是一副图像。
在手机上呈现的画面,第一帧与第二帧的图像中肯定有很多相同的画面,比如在一个固定的场所,背景不动,只有人物移动的情况,这时只需要重新绘制人物的移动就可以,背景不用重新绘制。IPB帧就是用于处理这种情况。
I帧:帧内编码帧 ,I帧表示关键帧,你可以理解为这一帧画面的完整保留;解码时只需要本帧数据就可以完成(因为包含完整画面)
P帧:前向预测编码帧。P帧表示的是这一帧跟之前的一个关键帧(或P帧)的差别,解码时需要用之前缓存的画面叠加上本帧定义的差别,生成最终画面。(也就是差别帧,P帧没有完整画面数据,只有与前一帧的画面差别的数据)
P帧的预测与重构:P帧是以I帧为参考帧,在I帧中找出P帧“某点”的预测值和运动矢量,取预测差值和运动矢量一起传送。在接收端根据运动矢量从I帧中找出P帧“某点”的预测值并与差值相加以得到P帧“某点”样值,从而可得到完整的P帧。
B帧:双向预测内插编码帧。B帧是双向差别帧,也就是B帧记录的是本帧与前后帧的差别(具体比较复杂,有4种情况,但我这样说简单些),换言之,要解码B帧,不仅要取得之前的缓存画面,还要解码之后的画面,通过前后画面的与本帧数据的叠加取得最终的画面。B帧压缩率高,但是解码时CPU会比较累。
B帧的预测与重构
B帧以前面的I或P帧和后面的P帧为参考帧,“找出”B帧“某点”的预测值和两个运动矢量,并取预测差值和运动矢量传送。接收端根据运动矢量在两个参考帧中“找出(算出)”预测值并与差值求和,得到B帧“某点”样值,从而可得到完整的B帧。
1)B帧是由前面的I或P帧和后面的P帧来进行预测的;
2)B帧传送的是它与前面的I或P帧和后面的P帧之间的预测误差及运动矢量;
3)B帧是双向预测编码帧;
4)B帧压缩比最高,因为它只反映丙参考帧间运动主体的变化情况,预测比较准确;
5)B帧不是参考帧,不会造成解码错误的扩散。
我找了篇文章,可以更好的理解H264 H264基础简介
在视频编码序列中,GOP即Group of picture(图像组),指两个I帧之间的距离,Reference(参考周期)指两个P帧之间的距离(如下图3.1)。一个I帧所占用的字节数大于一个P帧,一个P帧所占用的字节数大于一个B帧(如下图3.1所示)。
所以在码率不变的前提下,GOP值越大,P、B帧的数量会越多,平均每个I、P、B帧所占用的字节数就越多,也就更容易获取较好的图像质量;Reference越大,B帧的数量越多,同理也更容易获得较好的图像质量。需要说明的是,通过提高GOP值来提高图像质量是有限度的,在遇到场景切换的情况时,H.264编码器会自动强制插入一个I帧,此时实际的GOP值被缩短了。另一方面,在一个GOP中,P、B帧是由I帧预测得到的,当I帧的图像质量比较差时,会影响到一个GOP中后续P、B帧的图像质量,直到下一个GOP开始才有可能得以恢复,所以GOP值也不宜设置过大。同时,由于P、B帧的复杂度大于I帧,所以过多的P、B帧会影响编码效率,使编码效率降低。另外,过长的GOP还会影响Seek操作的响应速度,由于P、B帧是由前面的I或P帧预测得到的,所以Seek操作需要直接定位,解码某一个P或B帧时,需要先解码得到本GOP内的I帧及之前的N个预测帧才可以,GOP值越长,需要解码的预测帧就越多,seek响应的时间也越长。
DTS(Decoding Time Stamp):即解码时间戳,这个时间戳的意义在于告诉播放器该在什么时候解码这一帧的数据。 PTS(Presentation Time Stamp):即显示时间戳,这个时间戳用来告诉播放器该在什么时候显示这一帧的数据。 这2个概念经常出现在音频视频编码和播放中,其实际意义是,PTS是真正录制和播放的时间戳,而DTS是解码的时间戳。 对于普通的无B桢视频(H264 Baseline或者VP8),PTS/DTS应该是相等的,因为没有延迟编码。 对于有B桢的视频,I桢的PTS依然等于DTS, P桢的PTS>DTS, B桢的PTS<DTS。 可以简单地这样理解: 若视频没有B帧,则I和P都是解码后即刻显示。 若视频含有B帧,则I是解码后即刻显示,P是先解码后显示,B是后解码先显示。(B 和P的先、后是相对的)。
上面说了视频帧、DTS、PTS 相关的概念。我们都知道在一个媒体流中,除了视频以外,通常还包括音频。音频的播放,也有 DTS、PTS 的概念,但是音频没有类似视频中 B 帧,不需要双向预测,所以音频帧的 DTS、PTS 顺序是一致的。 音频视频混合在一起播放,就呈现了我们常常看到的广义的视频。在音视频一起播放的时候,我们通常需要面临一个问题:怎么去同步它们,以免出现画不对声的情况。 要实现音视频同步,通常需要选择一个参考时钟,参考时钟上的时间是线性递增的,编码音视频流时依据参考时钟上的时间给每帧数据打上时间戳。在播放时,读取数据帧上的时间戳,同时参考当前参考时钟上的时间来安排播放。这里的说的时间戳就是我们前面说的 PTS。实践中,我们可以选择:同步视频到音频、同步音频到视频、同步音频和视频到外部时钟。
② ffmpeg.exe命令转换的为h264编码的MP4视频文件无法在播放软件中播放,求解
这个和来MP4的内置的软件有关。1、早源期的MP4,只能播放divx和xvid等比较早的mpeg4编码的视频。那时候,这些视频的扩展名是avi。2、新的MP4,才能识别后缀为mp4的视频。这些mp4视频,目前主要是h.264的编码。3、所以,mp4只是一个封装格式,实际上必须能解码其中的编码才可以。如果没有相应的解码器,那就播放不了。4、简言之,虽然视频都叫mp4,但封装格式和视频编码都不一样,存在着不兼容的问题。通常发生在老一些的设备上。
③ FFmpeg的视频解码详解
第一步:组册组件 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)); //3.2 解码一帧视频压缩数据->进行解码(作用:用于解码操作) //开辟一块内存空间 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; //5.2 将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 //3.1 发送一帧视频压缩数据 avcodec_send_packet(avcodec_context, packet); //3.2 解码一帧视频压缩数据->进行解码(作用:用于解码操作) 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文件中 //5.1 计算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; //5.2 写入.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);
④ ffmpeg怎么批量处理任意类型的视频文件
@echooffcd/d%~dp0::设置要处理的视频格式setExt=*.avi,*.mp4,*.wmv,*.flv,*.mkv,*.rmvb,*.rm,*.3gpfor%%ain(%Ext%)do(rem这里写ffmpeg处理视频的命令,ffmpeg.exe不和脚本在一起话,请添加完整的路径rem参数中需要加入原文件路径的,请用%%a代替。ffmpeg参数1参数2参数3参数4……….)pause
大致的写法就是这样。
⑤ 使用ffmpeg 将多个音频插入到视频中
最近有一个需求,需要将多个音频文件延时插入到一段视频中,经过学习,得到以下命令: -y -i videoSource.mp4 -i test1.mp3 -i test2.mp3 -i test3.mp3 -filter_complex [1]adelay=5000|5000=[s1];[2]adelay=15000|15000=[s2];[3]adelay=25000|25000=[s3];[0:a][s1][s2][s3]amix=4[a] -map 0:v -map [a] -c:v result.mp4 如果不需要视频原声,则修改命令为: -y -i videoSource.mp4 -i test1.mp3 -i test2.mp3 -i test3.mp3 -filter_complex [1]adelay=5000|5000=[s1];[2]adelay=15000|15000=[s2];[3]adelay=25000|25000=[s3];[s1][s2][s3]amix=3[a] -map 0:v -map [a] -c:v result.mp4 以上命令为Android使用,如果需要在windows使用,则需要修改为: -y -i videoSource.mp4 -i test1.mp3 -i test2.mp3 -i test3.mp3 -filter_complex "[1]adelay=5000|5000=[s1];[2]adelay=15000|15000=[s2];[3]adelay=25000|25000=[s3];[s1][s2][s3]amix=3[a]" -map 0:v -map "[a]" -c:v result.mp4 其中 [1]adelay=5000|5000=[s1]的意思为:取第二个输入文件的音轨(下标从0开始)并延时5000毫秒 [0:a]的意思为:第一个输入文件的音频资源
⑥ 如何用ffmpeg播放抓包下来的pcap文件,是播放远端视频服务器时抓的UDP包
视频源没问题 也没丢包 那就是解码器的问题
⑦ 音视频 | 项目中导入FFmpeg
1.用Xcode创建一个用Swift语言开发的Mac项目。 2.在项目中创建两个文件夹。 3.将FFmpeg项目中的include和lib文件内容拷贝到刚刚创建的文件夹中。 4.将需要用到的动态库添加到项目中。 按住command可以多选。 5.设置include文件夹的路径。 6.关闭沙箱。 7.设置info.plist权限,做音频就导入麦克风权限,做视频就导入麦克风和相机权限。 8.创建一个文件名为demo的C文件,生成桥接文件,在桥接文件中导入C的头文件,最后在ViewController中调用test(),控制台输出成功就代表FFmpeg导入成功。 本文如有侵犯隐私或其他请联系我,我将在第一时间整改或删除。
⑧ Android使用FFmpeg播放视频(二):音频播放
Android使用FFmpeg播放视频(一):视频播放 Android NDK开发:利用OpenSL ES实现声音播放 这里我创建了两个JNI函数,一个是播放的,一个是释放的如下: 这里我在用于播放的JNI函数中依次初始化了FFmpeg和OpenSLES 其中初始化FFmpeg的函数中的逻辑其实和使用FFmpeg播放视频画面中的逻辑差不多,主要区别就是要找到音频的索引以及后面对于解析音频的一些配置;而初始化OpenSLES基本就和之前使用OpenSLES播放PCM数据是一样的,具体如下: 最后再加入释放资源的逻辑即可 这里的案例源码是和之前播放视频画面的分开了 https://gitee.com/itfitness/ffmpeg-audio-demo
⑨ 怎么通过rtp协议播放ffmpeg采集到的视频
rtp://192.168.1.105:5060 这个是接收端的ip和端口你可以用vlc 来进行接受和播放
⑩ 移动视频时,出现文件在ffmpeg中打开,怎么办
正常。尚未添加来ffmpeg程序路径到用户或源系统环境变量中,是只能在包含ffmpeg主程序的bin文件夹里进行编解码操作。其次,输出的结果,如未指定自定义路径,也是默认输出在包含ffmpeg主程序的bin文件夹里的。
事实上,在日常工作中,这非常不方便,为了保证在任意文件路径下都可以使用ffmpeg程序,建议还是将ffmpeg程序路径添加到用户或系统环境变量中。
解决方法:
1、将手机上的文件与电脑进行相连,可以直接用数据线,也可以下载一个360手机助手,直接扫码链接