1.正常情况下一个封装好的视频文件,例如mp4或者mkv文件,其音频数据是经过了aac编码器编码的(如果是其他的编码器,那么提取的数据格式要和编码器一致),其视频数据是经过了h264编码器编码的,这时候如果你仅仅是提取出数据的话,音频文件格式要是AAC格式,比如test.aac,视频文件要是test.h264格式才行。如果要换成其他格式就必须经过解码,然后编码,再封装。
2.使用ffplay播放yuv和pcm数据的时候,要注意输入对应的参数,比如yuv数据的话,使用ffplay命令也要把视频的分辨率输入进去,pcm数据的时候也需要把采样率、通道数、存储数据的格式S16LE等这些参数输入进去才能正常播放。
3.ffmpeg中滤镜的使用一般是对解码后的数据进行处理然后再编码的,不可能直接对编码的数据进行处理。所以如果要使用滤镜,是一定要进行解码,然后再编码操作的。使用命令行的时候也要记得用设定好编码器。
4.用MKV转avi格式报错,例如ffmpeg.exe -i out.mkv -vcodec copy -acodec copy out1111.avi执行失败,是因为MKV格式中的音频是aac,视频是H264,但是avi格式中的视频格式是MPEG-4,音频格式是MP3,所以当你用原来的编解码器肯定是会报错的。正确命令行应该是ffmpeg.exe -i out.mkv -vcodec mpeg4 -acodec libmp3lame out333.avi或者ffmpeg.exe -i out.mkv out222.avi(ffmpeg默认会选择对应的编解码器)
5.时间基理解:每个视频文件的时间基都有可能是不一样的,并且在使用api编码过程中最好都要使用av_rescale_q_rnd来把输入文件的时间基转换成输出文件的时间基,我在有的项目中有过没有调用av_rescale_q_rnd也能使用的情况,也许是当时项目中没有这块要求吧,建议自己以后在使用av_interleaved_write_frame写入文件之前,最好用av_rescale_q_rnd转换下再写入。而输入的参数中,其中一个就是pts(视频渲染时间戳)。
6.gop_size参数作用:这个值是设置GOP用的。GOP:关键帧的周期,也就是两个关键帧之间的距离,一个帧组的最大帧数,一般而言,每一秒视频至少需要使用 1 个关键帧。增加关键帧个数可改善质量,但是同时增加带宽和网络负载。在一个GOP中,P、B帧是由I帧预测得到的,当I帧的图像质量比较差时,会影响到一个GOP中后续P、B帧的图像质量,直到下一个GOP 开始才有可能得以恢复,所以GOP值也不宜设置过大。如果设置gop_size小的话,那么码率就大了,设置大的话,码率会减小,但是一旦丢失关键帧,那么只有等下一组GOP帧过来才能恢复。
举个例子,假如你gop_size = 10;那么就表示10帧里有一个关键帧,那么下一个10帧中才有一个关键帧。
7.使用ffmpeg编码或者转码后生成的视频文件很模糊,视频质量很差。决定因素很多,这里先记录下我自己发现的4点因素:
1.通过设置编码速度来优化视频模糊,代码如下:
AVDictionary *options = nullptr;
av_dict_set(&options, "preset", "veryslow", 0);
result = avcodec_open2(outCodecContext, outEncoder, &options);
设置preset的参数值为veryslow或者更慢的参数来优化模糊。但是这种情况不能完全使生成的文件和原始文件一样清晰。
2.通过第一步知道不能完全和原始文件一样清晰,那么我们需要设置编码器上下文中的me_subpel_quality,如下:
AVCodecContext* outCodecContext = outStream->codec;
outCodecContext->me_subpel_quality = 7;
个人测试感觉在设置了第一步的情况下,又添加了这步me_subpel_quality设置,效果没有更进一步的提高。
3.后来在调试参数的时候发现把码率设置很高的话,画面清晰度就好很多了:
outCodecContext->bit_rate = 1000000;//原本正常的一般都是40 0000,但是这里我设置成100 0000甚至200 0000后画面清晰的不得了
但是生成的视频文件大概有3M多,原始视频yuv文件是300多M,所以如果是视频流媒体传输的话,设置到这里就差不多了。
4.修改qmin,qmax参数后,视频文件和原始文件一样清晰,代码如下:
outCodecContext->qmin = 0;
outCodecContext->qmax = 0;
但是生成的文件相对来说挺大的,将近60M(原始yuv文件是300多M)所以如果是用于视频传输不建议这么设置,如果仅仅是文件之间的相互转换可以这样设置。
8.关于使用ffmpeg提供的api如何设置pts问题,目前我自己总结出来有两种方法:
A)定义一个long long型变量,每次把这个变量的值赋值给编码后的packet.pts,然后这个变量要自加一次。这种方式主要在于packet中pts的值为0的情况下,一般原始yuv数据中会有这种情况,输入源是摄像头或者原始yuv数据,适用场景适合于推流,但是值得注意的是如果推流是24小时不间断的一直推流,那么就要考虑到long long型变量溢出的问题了。
B)还有一种是通过av_rescale_q_rnd来进行转换的,这种适合场景适合输入源是视频封装格式,本身就带有时间基的。原因是这种情况输入源是带有pts的,并且带有时间基。
9.今天把h264视频文件和MP3格式的音频文件合并mkv封装格式的视频文件时,发现设置音频编码器为AV_CODEC_ID_AAC时,输出文件用播放器黑屏并且不会显示视频,但是音频时正常的。如果设置成AV_CODEC_ID_MP3就正常。不知道是不是是不是因为输入的是MP3格式的音频文件。这里特此记录。
10.实际工作用有时候调接口api接口返回错误,目前我了解到的情况情况主要有两种:
A)你在使用这些api接口的时候,没有调用ffmpeg的注册函数,比如说av_register什么之类的。
B)你传入的参数有问题。
11.视频画面模糊、马赛克等可以试着提高码率来处理。
12.使用av_find_best_stream函数获取流信息失败的原因之一:
需要先调用avformat_find_stream_info函数,然后调用av_find_best_stream函数才不会失败。
13.FFMPEG使用第三方编码数据推流画面花屏卡着不动问题处理:视频帧数据用硬件编码输出,仅仅使用FFMPEG将硬件编码出的数据推流RTSP数据后严重花屏且画面卡住不动