简单地说。软解码是用软件方式进行解码,需要占用CPU资源,速度相当较慢。硬解码直接用硬件方式解决,不占用CPU资源,速度相对较快。
mov编码h264跟mp4编码h264的区别?mov和mp4是两种不同的封装格式,里面的h.264都是一样的
H264编码 H264编码器 哪个牌子好单位用的是视盈,几年来一直很稳定。推荐你联系视盈黄国耀。一三七,一一一四,六六九一。
MediaCodec编码可以获取到H264帧类型吗?仅转换可以使用命令,把任一mp4转换成ts
ffmpeg -i input.mp4 -c copy -bsf h264_mp4toannexb output.ts 很高兴为您解答!
有不明白的可以追问!如果您认可我的回答。
如何实时h264编码及aac编码1. 简单介绍
首先是捕获,这里采用了DirectShow的方式,对它进行了一定程度的封装,包括音视频。好处是直接使用native api,你可以做想做的任何修改,坏处是,不能跨平台,采集音视频这种应用,linux平台也是需要滴呀。有跨平台的做法,对视频,可以使用OpenCV,对音频,可以使用OpenAL或PortAudio等,这样就行了。
编码可以选择的余地比较大,对视频来讲,有H264, MPEG-4, WebM/VP8, Theora等,音频有Speex, AAC, Ogg/Vorbis等,它们都有相应的开源项目方案,我采用的是x264进行H264编码,libfaac进行aac编码,之后是否更改编码方案,等具体项目需求再说了。这里提一下WebM,Google牵头的项目,完全开放和自由,使用VP8和Vorbis编码,webm(mkv)封装,有多家巨头支持,目的是想要取代当前的H264视频编码,号称比后者更加优秀,我没有测试过实际效果。不过有商业公司牵头就是不一样,各项支持都很全面,有时间了关注一下。
2. 逻辑和流程
基本的思想是实现dshow ISampleGrabberCB接口,通过回调来保存每一个buffer。除了界面线程和dshow自己的线程之外,我们启动了两个线程,AudioEncoderThread和VideoEncoderThread,分别从SampleGrabber中取出数据,调用编码器进行编码,编码后的文件可以直接输出。看图:
程序是用VS2010构建的,看张工程截图:
Base下面的是对系统API的一些简单封装,主要是线程和锁。我这里简单也封装的了一下dshow的捕获过程,包括graph builder的创建,filter的连接等。directshow是出了名的难用,没办法,难用也得用。因为是VS2010,调用的Windows SDK 7.1中的dshow,没有qedit.h这个文件,而它正式定义ISampleGrabberCB的。不急,系统中还是有qedit.dll的,我们要做的就是从Windows SDK 6.0中,把它拷过来,然后在stdafx.h中加入这几行代码,就可以了
1 #pragma include_alias( "dxtrans.h", "qedit.h" )
2 #define __IDxtCompositor_INTERFACE_DEFINED__
3 #define __IDxtAlphaSetter_INTERFACE_DEFINED__
4 #define __IDxtJpeg_INTERFACE_DEFINED__
5 #define __IDxtKey_INTERFACE_DEFINED__
6 #include "qedit.h"
3. 音视频编码
相关文件:
Encoder下就是音视频编码相关的代码。X264Encoder封装了调用x264编码器的 *** 作,FAACEncoder封装了调用libfaac编码器的 *** 作,VideoEncoderThread和AudioEncoderThread负责主要的流程。下面我把关键代码贴出来,大家可以参考一下。
A. 视频编码线程
主要流程是首先初始化x264编码器,然后开始循环调用DSVideoGraph,从SampleGrabber中取出视频帧,调用x264进行编码,流程比较简单,调用的频率就是你想要获取的视频帧率。要注意的一点是,x264进行编码比较耗时,在计算线程Sleep时间时,要把这个过程消耗的时间算上,以免采集的视频帧率错误。
B. 音频编码线程
主要流程和视频编码线程相同,也是初始化FAAC编码器,然后循环调用DSAudioGraph,从SampleGrabber中取出视频帧,调用faac进行编码。和视频不同的是,音频的sample的频率是非常快的,所以几乎要不断的进行采集,但前提是SampleGrabber中捕获到新数据了才行,不然你的程序cpu就100%了,下面代码中IsBufferAvailaber()就是做这个检测的。
调用faac进行编码的时候,有点需要注意,大家特别注意下,不然编码出来的音频会很不正常,搞不好的话会很头疼的。先看下faac.h的相关接口
1 faacEncHandle FAACAPI faacEncOpen(unsigned long sampleRate, unsigned int numChannels,2 unsigned long *inputSamples, unsigned long *maxOutputBytes)3 4 int FAACAPI faacEncEncode(faacEncHandle hEncoder, int32_t * inputBuffer, unsigned int samplesInput,5 unsigned char *outputBuffer, unsigned int bufferSize)
faacEncEncode第三个参数指的是传入的sample的个数,这个值要和调用faacEncOpen返回的inputSamples相等。要做到这点,就要在dshow中设置好buffsize,公式是:
BufferSize = aac_frame_len * channels * wBytesPerSample aac_frame_len = 1024
如何让opencv支持h264编码h.264是一种视频压缩标准了,有专门的库对它进行压缩解压的。
我对opencv还算是比较熟悉的,它没有h264之类的库
H264编码DVD能直接播放吗?不能啊,不同格式的,H264跟DVD不一样啊
Adobe Pr的h264是啥编码器音频编辑器
1、运行Set-up.exe,会d出“遇到了以下问题”d窗,选择忽略;
2、之后会初始化安装程序,请不要进行任何 *** 作,稍等片刻;
3、有安装和试用两种选择,请点击试用
4、安装需要Adobe ID登录验证,没有的话选择"获取Adobe ID"注册一个,只需有邮箱和密码即可(您也可以选择断开网络连接,选择“以后再登录”),同样也能继续安装;这里为您演示登陆安装。
5、接受协议后,选择安装的语言和安装的目录。
6、之后只需耐心等待,软件需要组件已自带,无需另外安装,这样就等安装完Adobe Premiere Pro CC 2015。
7、安装完毕点击立即启动,启动后不是进入软件而是试用版界面,点击开始试用;
8、打开Premiere Pro CC 2015,选择新建项目才算是进入软件。
PS:若是不事先进入一次软件直接破解会导致软件无法打开。
Premiere Pro CC 2015::3322./soft/201507311409.
mediacodec取不出h264解码后数据吗需要调用av_parser_parse
进行帧查找分解后再送入解码器解码。
H264与MPEG中I,P,B帧编码一样吗编码是不一样的,H.264采用的帧内编码和帧间预测编码技术 比MPEG-2的都要先进,因此压缩效率更高
//第一步:注册组件->编码器、解码器等等…
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、设置编解码器上下文参数->必需设置->不可少
//目标:设置为是一个视频编码器上下文->指定的是视频编码器
//上下文种类:视频解码器、视频编码器、音频解码器、音频编码器
//2.1 设置视频编码器ID
avcodec_context->codec_id = avoutput_format->video_codec
//2.2 设置编码器类型->视频编码器
//视频编码器->AVMEDIA_TYPE_VIDEO
//音频编码器->AVMEDIA_TYPE_AUDIO
avcodec_context->codec_type = AVMEDIA_TYPE_VIDEO
//2.3 设置读取像素数据格式->编码的是像素数据格式->视频像素数据格式->YUV420P(YUV422P、YUV444P等等...)
//注意:这个类型是根据你解码的时候指定的解码的视频像素数据格式类型
avcodec_context->pix_fmt = AV_PIX_FMT_YUV420P
//2.4 设置视频宽高->视频尺寸
avcodec_context->width = 640
avcodec_context->height = 352
//2.5 设置帧率->表示每秒25帧
//视频信息->帧率 : 25.000 fps
//f表示:帧数
//ps表示:时间(单位:每秒)
avcodec_context->time_base.num = 1
avcodec_context->time_base.den = 25
//2.6 设置码率
//2.6.1 什么是码率?
//含义:每秒传送的比特(bit)数单位为 bps(Bit Per Second),比特率越高,传送数据速度越快。
//单位:bps,"b"表示数据量,"ps"表示每秒
//目的:视频处理->视频码率
//2.6.2 什么是视频码率?
//含义:视频码率就是数据传输时单位时间传送的数据位数,一般我们用的单位是kbps即千位每秒
//视频码率计算如下?
//基本的算法是:【码率】(kbps)=【视频大小 - 音频大小】(bit位) /【时间】(秒)
//例如:Test.mov时间 = 24,文件大小(视频+音频) = 1.73MB
//视频大小 = 1.34MB(文件占比:77%) = 1.34MB * 1024 * 1024 * 8 = 字节大小 = 468365字节 = 468Kbps
//音频大小 = 376KB(文件占比:21%)
//计算出来值->码率 : 468Kbps->表示1000,b表示位(bit->位)
//总结:码率越大,视频越大
avcodec_context->bit_rate = 468000
//2.7 设置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
//2.8 设置量化参数->数学算法(高级算法)->不讲解了
//总结:量化系数越小,视频越是清晰
//一般情况下都是默认值,最小量化系数默认值是10,最大量化系数默认值是51
avcodec_context->qmin = 10
avcodec_context->qmax = 51
//2.9 设置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源码->x264.c文件
//第一个值:预备参数
//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格式)
//8.1 定义一个缓冲区
//作用:缓存一帧视频像素数据
//8.1.1 获取缓冲区大小
int buffer_size = av_image_get_buffer_size(avcodec_context->pix_fmt,
avcodec_context->width,
avcodec_context->height,
1)
//8.1.2 创建一个缓冲区
int y_size = avcodec_context->width * avcodec_context->height
uint8_t *out_buffer = (uint8_t *) av_malloc(buffer_size)
//8.1.3 打开输入文件
const char *cinFilePath = [inFilePath UTF8String]
FILE *in_file = fopen(cinFilePath, "rb")
if (in_file == NULL) {
NSLog(@"文件不存在")
return
}
//8.2.1 开辟一块内存空间->av_frame_alloc
//开辟了一块内存空间
AVFrame *av_frame = av_frame_alloc()
//8.2.2 设置缓冲区和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
//9.2 接收一帧视频像素数据->编码为->视频压缩数据格式
AVPacket *av_packet = (AVPacket *) av_malloc(buffer_size)
int result = 0
int current_frame_index = 1
while (true) {
//8.1 从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
}
//8.2 将缓冲区数据->转成AVFrame类型
//给AVFrame填充数据
//8.2.3 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步:视频编码处理
//9.1 发送一帧视频像素数据
avcodec_send_frame(avcodec_context, av_frame)
//9.2 接收一帧视频像素数据->编码为->视频压缩数据格式
result =avcodec_receive_packet(avcodec_context, av_packet)
//9.3 判定是否编码成功
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)
在你的转码命令里面添加上-vf rotate=PI/2或者-vf rotate=3*PI/2,例如ffmpeg -i E:\ffmpeg\test.mp4 -y -vf rotate=PI/2 E:\ffmpeg\dest1.mp4
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)