Windows下实现Mencoder+FFMPEG视频转换和截图的功能

Mencoder是Mplayer自带的编码工具(Mplayer是Linux下的播放器,开源,支持几乎所有视频格式的播放,现在有windows和Mac版本)。

 

Mplayer的获得与配置:

Mplayer windows版本下载列表:http://www5.mplayerhq.hu/MPlayer/releases/win32/

 

列表中会有版本发布日期,可以挑选最新的版本,也可以选择old/去下载老的版本,笔者用的是6月份的版本。下载后解压到某个文件夹中即可。

Codecs下载列表:http://www5.mplayerhq.hu/MPlayer/releases/codecs/ 

 

[个人批注]补充:由于以上两个文件地址不存在了,我已经下载到"环境配置"的MPlayer的文件夹里面了!

 

自动解压缩文件MPlayer-mingw32-1.0rc1.zip,生成MPlayer文件夹,

 

 

选择window-all-20071007.tar.bz2(*表示年月日,将该压缩包中的文件夹下所有文件,包括*.dll、*.acm、*.ax等等全部copy到Mplayer根目录下的codecs文件夹中。

 

此时最好把Mplayer.exe所在路径"D:\web\mplayer ",同时也是Mencoder.exe所在路径添加到环境变量path中。

 

现在可以试试用Mplayer播放视频,比如有个视频位于D:\music\APerfectMatch.wmv,那么可以打开一个cmd窗口,输入:

引用:

 

mplayer D:\music\APerfectMatch.wmv

感受一下来自Linux的播放器吧,可以通过键盘来操纵。

 

Mencoder转换视频格式:

 

   以将各种格式转换为flv格式为例(flv格式是flash支持的视频格式):

引用:

mencoder "E:\test.m2p" -o "E:\output.flv" -of lavf -lavfopts i_certify_that_my_video_stream_does_not_use_b_frames -oac mp3lame -lameopts abr:br=56 -ovc lavc -lavcopts vcodec=flv:vbitrate=5000:mbd=2:mv0:trell:v4mv:cbp:last_pred=3:dia=4:cmp=6:vb_strategy=1 -vf scale=512:-3 -ofps 12 -srate 22050

在命令行中输入这行代码(注意:windows的命令行是不支持换行的),按回车运行,一段时间之后就可以得到一个.flv文件,播放一下看看品质如何(可以直接用Mplayer播放)。

下图是我这边转换的效果对比,左边是原视频,右边是转换后的视频:

 

 

 

所有人都会觉得,转换后品质下降了很多,确实是这样,同时可以发现转换后的文件由原来的13M变成了1M,如果要提高品质,可以将vbitrate=500改为vbitrate=5000。

转换后的效果对比,左边是原视频,右边是转换后的视频:

 

 

 

品质几乎一样了,但同时,转换文件变成了6M。关于命令中的一些参数,解释一下:

-o "E:\output.flv":是输出文件路径;

 

-of lavf:是输出文件格式,这里不是flv而是lavf,是因为flv属于libavformat;

 

-lavfopts i_certify_that_my_video_stream_does_not_use_b_frames:-lavfopts表示对lavf进行一些设置,设置的内容就是i_certify_that_my_video_stream_does_not_use_b_frames,翻译成中文就是:我确定,我的视频不用B frames,对于转换flv格式,最好加上这个参数,否则可能会报错,如图:

 

 

-oac mp3lame:oac=output audio codec,输出音频编码器,这里用的mp3lame;

-lameopts abr:br=56:lame options,是专门针对mp3lame的参数设置,abr:br=56,是设置音频比特率为56(比特率:每秒钟输出的音频大小,单位kb/s);

 

-ovc lavc:ovc=output video codec,输出视频编码器,lavc表示one of libavcodec’s video codec,输出格式为libavformat之一,编码器当然也是libavcodec之一啦,至于libavodec里都有哪些编码器,可以查看Mplayer的官方文档;

 

-lavcoptsvcodec=flv:vbitrate=500:mbd=2:mv0:v4mv:trell:cbp:last_pred=3:dia=4:cmp=6:vb_strategy=1:对lavc进行一些设置,详细介绍如下:

 

vcodec=flv:指定视频编码器为flv;

 

vbitrate=500:指定视频比特率为500,这个参数很重要,vbitrate大了可以让视频品质增加,但会让文件变的很大(可以参考flash8自带的转换工具的参数:低品质为150kb/s,中等品质为400kb/s,高品质为700kb/s)。

 

mbd:宏模块选择算法,值为0~2默认为0,值越大转换越缓慢,但在品质和文件大小方面有好处;

 

mv0:编译每个宏模块并选择最好的一个,当mbd=0时无效;

 

v4mv:会稍微增加品质,mbd>0时效果更明显;

 

trell:量子化网格搜索,对每8?block找到最优化编码;

 

cbp:只能和trell一期使用,评估失真的图像块编码;

 

last_pred=3:与上一帧相比的移动数量预测,值为0~99,1~3比较合适,大于3时对品质的提高已经无关紧要,但却会降低速度;

 

dia=4:移动搜索范围,值为-99~6,对于快速转换,-1是个不错的值,如果不是很重视速度,可以考虑2~4;

 

cmp=6:值为1~2000,默认为0,设置用于全象素移动预算的比较函数

 

vb_strategy=1:对动作很大的场景会有帮助,对有些视频,设置vmax_b_frames会有损品质,加上vb_strategy=1会好点。

 

以上是对-lavcopts的详细解释,接下来继续说明mencoder的参数:

 

-vf scale=512:-3:-vf表示视频格式,scale是缩放,512:-3表示强制将宽度设置为512,高度写为-3表示保持高宽比,也可以设置为-1或-2,具体表示什么,有兴趣的可以尝试一下。如果要强制转化为统一大小,可以直接写-vf scale=640:480,但笔者个人建议用-3来保持高宽比。-vf里还有expand和crop参数,例如:-vf scale=512:384,expand=512:384:::1,crop=512:384:0:0,expand表示膨胀,crop表示裁剪;

 

-ofps 12:输出视频的帧频,一般,用于flash播放的视频帧频高了没有没有意义,反而会增加视频文件大小,但如果ofps设置的不合适,比如源视频帧频不是ofps的整数倍,可能会导致转换后的视频、音频不同步,似乎可以将这一参数改为-noskip来解决这一问题; 

 

-srate 22050:音频采样率一般为22050或44100。

 

对于转换flv格式,lavsopts的设置比较重要,还有很多参数本文没有涉及到,在笔者参考的文献中会有具体的说明,感兴趣的可以去看一下。我对于Mencoder的认识主要也是来源于下面2篇文章,实践的比较少,如果有理解和翻译的失误,再次欢迎与我交流。

 

用mencoder在线转换视频格式并控制视频品质

关于用mencoder将各种格式转换为flv格式,网络上应该也有一些文章,我把最近学习的心得和大家分享一下.

如果您正准备开始使用mencoder,似乎也可以当作教程来看,如果您有更好的方法或技术,请不吝赐教!

mencoder,可以从其官方网站上获得:

http://www.mplayerhq.hu

下载完之后,修改一下环境变量,将mencoder.exe及mplayer.exe文件所在的目录添加到path变量里。

mencoder是在命令行中执行的(官网上的文档里的实例似乎都是linux下的)

我是计算机小白,当然只会使用windows……

开始菜单 -> 运行 -> cmd -> 回车,就打开了命令行窗口

这时,我们可以拿一个视频来试试看,我用的是一个mtv,wmv格式的,文件名:APerfectMatch.wmv。

在命令行中输入:(注意,不要从网页上直接copy这段命令到cmd,windows的命令行似乎是不支持换行的......)

mencoder "D:\music\sk8ter_boi_300.wmv" -o "D:\output.flv" -of lavf -oac mp3lame -lameopts abr:br=56 -ovc lavc -lavcopts vcodec=flv:vbitrate=150:mbd=2:mv0:trell:v4mv:cbp:last_pred=3 -srate 22050

按下回车后,如果你看到显示:“mencoder 不是内部或外部命令,也不是可运行的程序,或批处理文件”,那么说明环境变量没有设置好

如果正常,会看到开始转视频,会看到一排一排的字往上翻,内容大概是这样:

Pos: 226.8s 297f (100%) 48fps Trem: 0min 5mb a-v:-0.009 [142:56]

这里边的内容,我最关注的是2个括号里面的,小括号里应该是转换的进度,中括号里的内容很重要,142表示视频比特率,56表示音频比特率(比特率这个词不知道用的对不对......)

转换结束,会显示2行文字:

Video stream: 142.564 kbit/s (17820 B/s) size: 4046677 bytes 227.080 secs 2700 frames

Audio stream: 56.938 kbit/s (7117 B/s) size: 1616197 bytes 227.082 secs

这2行信息我想大家都能明白,其中我一直关注的是那个142.564kbit/s,用过flash8自带转换工具的应该知道高级设置里有个选项是最大数据速率,当选中中等画质的时候,是400kb/s,而低品质也是150kb/s,也就是说,用那句命令转换的视频,其画质都不如品质的,那么,品质怎么样呢?看一下,怎么看flv文件?别忘了我们有万能播放器mplayer,哈哈,直接在命令行里输入:

mplayer "d:\output.flv",看到咱们刚刚转好的视频,我当时一看,画面上马赛克倒是没有,全是瓷砖,我晕倒...

进入正题了,怎么来提高画面品质?(晕倒,原来前面都不是正题...=_=o)

回头看一下我们的命令行:

mencoder "D:\music\sk8ter_boi_300.wmv" -o "D:\output.flv" -of lavf -oac mp3lame -lameopts abr:br=56 -ovc lavc -lavcopts vcodec=flv:vbitrate=150:mbd=2:mv0:trell:v4mv:cbp:last_pred=3 -srate 22050。

下面一个一个分析:

mencoder 说明你用的是mencoder;

"d:\.....wmv" -> 是指你的输入视频;

-o -> 后面指定输出路径;(前面有“-”的都是option(选项的意思))

-of -> 大概是output format的缩写,输出文件格式,咦!为什么不是flv,而是lavf?lavf表示你使用了libavcodec里的格式,flv正好是libavcodec里的,呵呵;

-oac -> 大概是output audio codec的缩写,指定输出音频编码,这儿选用的是mp3lame;

-lameopts -> 指定lame的options,就是设置音频输出的一些参数啦,我只关心视频,跳过

-ovc -> 大概是output video codec的缩写,制定输出视频编码(我最关心的好像要上场了),选用的lavc,什么意思?说是用了libavcodec的编码器;

-lavcopts -> 是lavc的options,要设置视频编码的参数了!(心跳加速,血压升高,口中开始大量分泌唾液),看看它后面都有什么:

codec=flv 说的是用的flv编码器,这个咱不理;

vbitrate=150 video bit rate!视频数据速率!就是它了!原来我设的是150啊!

找到了,下面不看了!改成vbitrate=1000,再试试看! 

结果,和前一次一模一样......(我还改成10000的,真的,还是一样,我当时以为它的单位是b/s而不是kb/s)

冷静下来,去往上看了一下官方文档,这个参数是最大数据速率,最大嘛,你设多大都一样啊,看来不是靠它来控制品质。

不卖关子了,直接给出我的结论吧,设置品质有2种途径:

1、设置-lavcopts,看这样一句命令:

mencoder "D:\music\APerfectMatch.wmv" -o "D:\output.flv" -of lavf -oac mp3lame -lameopts abr:br=56 -ovc lavc -lavcopts vcodec=flv:vbitrate=500:mbd=2:mv0:trell:v4mv:cbp:last_pred=3:dia=4:cmp=6:vb_strategy=1 -vf scale=320:240,expand=320:240:::1,crop=320:240:0:0 -ofps 30 -srate 22050

看看多了什么?

在-lavcopts里多了dia=4:cmp=6:vb_strategy=1这3条

他们的含义我只是大概了解一点点,毕竟不是专业搞视频编码的

dia越大品质越高,如果需要快速编码,设置为-1,设为4时已经很有利于品质了;

cmp越大品质越高,默认值0,是最快速的,一般设到3,设为6已经只会细微提高品质了,但速度会慢

vb_strategy,大概是1或者0,默认值可能为0,我这里设为1,会对编码有帮助,这个参数我自己没有过多推敲,可能并不影响品质......

2、加-sws选项,看下面的命令:

mencoder "D:\music\APerfectMatch.wmv" -o "D:\output.flv" -of lavf -oac mp3lame -lameopts abr:br=56 -ovc lavc -lavcopts vcodec=flv:vbitrate=500:mbd=2:mv0:trell:v4mv:cbp:last_pred=3 -sws 3 -vf scale=320:240,expand=320:240:::1,crop=320:240:0:0 -ofps 30 -srate 22050

只是加一个 -sws 3进去,转换后的效果和前面一种方法大致相同,视频数据速率都是422.5kb/s左右,解释一下

-sws就是用来设置品质的,默认值为2,那么,为什么不用这种简单的方式呢?我个人认为,用前面一种方法有利于找到一个速度和品质的平衡点,毕竟变化的范围比较大。

 

 

转换FLV格式的ffmpeg.exe 参数说明

修改一下环境变量,将ffmpeg.exe文件所在的目录添加到path变量里。

ffmpeg.exe -i F:\闪客之家\闪客之歌.mp3 -ab 56 -ar 22050 -b 500 -r 15 -s 320x240 f:\11.flv 

 

ffmpeg -i F:\01.wmv -ab 56 -ar 22050 -b 500 -r 15 -s 320x240 f:\test.flv 

 

使用-ss参数 作用(time_off set the start time offset),可以从指定时间点开始转换任务。如: 

转换文件格式的同时抓缩微图: 

ffmpeg -i "test.avi" -y -f image2 -ss 8 -t 0.001 -s 350x240 'test.jpg' 

对已有flv抓图: 

ffmpeg -i "test.flv" -y -f image2 -ss 8 -t 0.001 -s 350x240 'test.jpg' 

-ss后跟的时间单位为秒 

 

Ffmpeg转换命令 

ffmpeg -y -i test.mpeg -bitexact -vcodec h263 -b 128 -r 15 -s 176x144 -acodec aac -ac 2 -ar 22500 

-ab 24 -f 3gp test.3gp 

或者 

ffmpeg -y -i test.mpeg -ac 1 -acodec amr_nb -ar 8000 -s 176x144 -b 128 -r 15 test.3gp 

 

 

ffmpeg参数设定解说 

-bitexact 使用标准比特率 

-vcodec xvid 使用xvid压缩 

-s 320x240 指定分辨率 

-r 29.97 桢速率(可以改,确认非标准桢率会导致音画不同步,所以只能设定为15或者29.97) 

画面部分,选其一 

-b <比特率> 指定压缩比特率,似乎ffmpeg是自动VBR的,指定了就大概是平均比特率,比如768,1500这样的 

就是原来默认项目中有的 

-qscale <数值> 以<数值>质量为基础的VBR,取值0.01-255,约小质量越好 

-qmin <数值> 设定最小质量,与-qmax(设定最大质量)共用,比如-qmin 10 -qmax 31 

-sameq 使用和源同样的质量 

声音部分 

-acodec aac 设定声音编码 

-ac <数值> 设定声道数,1就是单声道,2就是立体声,转换单声道的TVrip可以用1(节省一半容量),高品质 

的DVDrip就可以用2 

-ar <采样率> 设定声音采样率,PSP只认24000 

-ab <比特率> 设定声音比特率,前面-ac设为立体声时要以一半比特率来设置,比如192kbps的就设成96,转换 

君默认比特率都较小,要听到较高品质声音的话建议设到160kbps(80)以上 

-vol <百分比> 设定音量,某些DVDrip的AC3轨音量极小,转换时可以用这个提高音量,比如200就是原来的2倍 

这样,要得到一个高画质音质低容量的MP4的话,首先画面最好不要用固定比特率,而用VBR参数让程序自己去 

判断,而音质参数可以在原来的基础上提升一点,听起来要舒服很多,也不会太大(看情况调整 

 

 

例子:ffmpeg -y -i "1.avi" -title "Test" -vcodec xvid -s 368x208 -r 29.97 -b 1500 -acodec aac -ac 2 -ar 24000 -ab 128 -vol 200 -f psp -muxvb 768 "1.***" 

解释:以上命令可以在Dos命令行中输入,也可以创建到批处理文件中运行。不过,前提是:要在ffmpeg所在的目录中执行(转换君所在目录下面的cores子目录)。 

参数: 

-y(覆盖输出文件,即如果1.***文件已经存在的话,不经提示就覆盖掉了) 

-i "1.avi"(输入文件是和ffmpeg在同一目录下的1.avi文件,可以自己加路径,改名字) 

-title "Test"(在PSP中显示的影片的标题) 

-vcodec xvid(使用XVID编码压缩视频,不能改的) 

-s 368x208(输出的分辨率为368x208,注意片源一定要是16:9的不然会变形) 

-r 29.97(帧数,一般就用这个吧) 

-b 1500(视频数据流量,用-b xxxx的指令则使用固定码率,数字随便改,1500以上没效果;还可以用动态码率如:-qscale 4和-qscale 6,4的质量比6高) 

-acodec aac(音频编码用AAC) 

-ac 2(声道数1或2) 

-ar 24000(声音的采样频率,好像PSP只能支持24000Hz) 

-ab 128(音频数据流量,一般选择32、64、96、128) 

-vol 200(200%的音量,自己改) 

-f psp(输出psp专用格式) 

-muxvb 768(好像是给PSP机器识别的码率,一般选择384、512和768,我改成1500,PSP就说文件损坏了) 

"1.***"(输出文件名,也可以加路径改文件名) 

机器强劲的话,可以多开几个批处理文件,让它们并行处理。 

E:\ffmpeg.exe -i I:\1.wmv -b 360 -r 25 -s 320x240 -hq -deinterlace -ab 56 -ar 22050 -ac 1 D:\2.flv

 

FLV视频转换的利器 - ffmpeg.exe

大家应该都知道Youtobe、Google Video之类视频分享网站。他们的视频全部是使用Flash播放,而通过探索实际地址,会发现下载回来的东西都是Flash支持的FLV格式。这种格式的视频,播放和转换是非常麻烦的。但是,有一个源于Linux的工具软件ffmpeg可以轻易地实现FLV向其它格式(avi(mpeg4)、asf、mpeg)的转换或者将其它格式转换为flv。

ffmpeg作为Linux下的LGPL开源程序,在Windows下编译需要特殊的工具。我这里提供的ffmpeg.exe是2004年的旧版本,使用MinGW编译,只有一个可执行文件,可直接运行(命令行程序)。

FLV向其它格式(avi(mpeg4)、asf、mpeg)转换的简易方法: (圆括号内必填,方括号内可选)

转换成wmv/asf

ffmpeg -i (要转换的flv文件完整路径) -f asf -vcodec (wmv1或wmv2) [-b 视频码率] -acodec mp3 [-ab 音频码率] (输出的asf/wmv文件完整路径)

转换成mpeg1

ffmpeg -i (要转换的flv文件完整路径) -f mpeg -vcodec mpeg1video [-b 视频码率] -acodec mp2 [-ab 音频码率] (输出的mpg文件完整路径)

转换成avi(msmpeg4)

ffmpeg -i (要转换的flv文件完整路径) -f avi -vcodec (msmpeg4或msmpeg4v1或msmpeg4v2) [-b 视频码率] -acodec mp3 [-ab 音频码率] (输出的avi文件完整路径)

 

其它格式向flv转换的简易办法

ffmpeg -i (输入的文件完整路径,RM/RMVB不支持,最好是mpeg4的AVI或者MPEG1文件,对新版的wmv支持不好)-f flv -vcodec flv [-b 视频码率] -acodec mp3 [-ab 音频码率] (输出的flv文件)

 

ffmpeg其实还有很多选项。说明文件全部嵌在代码里了。

以下是一个简单的例子,演示如何使用OpenGL ES和MediaCodec将RGB图像转换为MP4视频。 首先,我们需要使用OpenGL ES将RGB图像渲染到纹理上。以下是一个简单的渲染器类: ```cpp class Renderer { public: Renderer(); ~Renderer(); void init(); void render(const uint8_t* data, int width, int height); private: GLuint mTexture; GLuint mProgram; GLuint mVertexShader; GLuint mFragmentShader; GLint mPositionHandle; GLint mTexCoordHandle; GLint mTextureHandle; }; ``` 在Renderer的构造函数中,我们可以编译和链接顶点着色器和片段着色器: ```cpp Renderer::Renderer() { const char* vertexShaderSrc = "attribute vec4 position;\n" "attribute vec2 texCoord;\n" "varying vec2 vTexCoord;\n" "void main() {\n" " gl_Position = position;\n" " vTexCoord = texCoord;\n" "}"; const char* fragmentShaderSrc = "precision mediump float;\n" "varying vec2 vTexCoord;\n" "uniform sampler2D texture;\n" "void main() {\n" " gl_FragColor = texture2D(texture, vTexCoord);\n" "}"; mVertexShader = loadShader(GL_VERTEX_SHADER, vertexShaderSrc); mFragmentShader = loadShader(GL_FRAGMENT_SHADER, fragmentShaderSrc); mProgram = glCreateProgram(); glAttachShader(mProgram, mVertexShader); glAttachShader(mProgram, mFragmentShader); glBindAttribLocation(mProgram, ATTRIB_VERTEX, "position"); glBindAttribLocation(mProgram, ATTRIB_TEXTURE, "texCoord"); glLinkProgram(mProgram); mPositionHandle = glGetAttribLocation(mProgram, "position"); mTexCoordHandle = glGetAttribLocation(mProgram, "texCoord"); mTextureHandle = glGetUniformLocation(mProgram, "texture"); } ``` 在render函数中,我们将RGB数据上传到纹理中,并在渲染器中绘制纹理: ```cpp void Renderer::render(const uint8_t* data, int width, int height) { if (!data) { return; } if (!mTexture) { glGenTextures(1, &mTexture); glBindTexture(GL_TEXTURE_2D, mTexture); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); } glBindTexture(GL_TEXTURE_2D, mTexture); glUseProgram(mProgram); glEnableVertexAttribArray(mPositionHandle); glEnableVertexAttribArray(mTexCoordHandle); glVertexAttribPointer(mPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gVertices); glVertexAttribPointer(mTexCoordHandle, 2, GL_FLOAT, GL_FALSE, 0, gTexCoords); glUniform1i(mTextureHandle, 0); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDisableVertexAttribArray(mPositionHandle); glDisableVertexAttribArray(mTexCoordHandle); } ``` 接下来,我们使用MediaCodec将渲染的帧编码为MP4视频。以下是一个简单的编码器类: ```cpp class Encoder { public: Encoder(); ~Encoder(); void init(int width, int height); void encodeFrame(const uint8_t* data, int64_t pts); void flush(); private: AMediaCodec* mEncoder; AMediaMuxer* mMuxer; int mTrackIndex; int mFrameIndex; bool mIsStarted; }; ``` 在Encoder的构造函数中,我们可以创建MediaCodec和MediaMuxer: ```cpp Encoder::Encoder() { mEncoder = AMediaCodec_createEncoderByType("video/avc"); AMediaFormat* format = AMediaFormat_new(); AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, "video/avc"); AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, 2000000); AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_FRAME_RATE, 30); AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, 1); AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_COLOR_FORMAT, COLOR_FormatSurface); AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_WIDTH, 720); AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_HEIGHT, 1280); AMediaCodec_configure(mEncoder, format, nullptr, nullptr, AMEDIACODEC_CONFIGURE_FLAG_ENCODE); AMediaFormat_delete(format); mTrackIndex = -1; mFrameIndex = 0; mIsStarted = false; } ``` 在init函数中,我们将MediaCodec的输出Surface传递给MediaMuxer,并启动MediaCodec和MediaMuxer: ```cpp void Encoder::init(int width, int height) { if (mIsStarted) { return; } AMediaCodec_start(mEncoder); AMediaMuxer_start(mMuxer); ANativeWindow* window = AMediaCodec_createInputSurface(mEncoder); AMediaMuxer_addTrack(mMuxer, AMediaCodec_getOutputFormat(mEncoder)); AMediaMuxer_start(mMuxer); mTrackIndex = 0; mIsStarted = true; } ``` 在encodeFrame函数中,我们从输出Surface中获取编码的数据,并将其写入MediaMuxer: ```cpp void Encoder::encodeFrame(const uint8_t* data, int64_t pts) { if (!mIsStarted) { return; } ANativeWindow* window = AMediaCodec_createInputSurface(mEncoder); AMediaCodec_configure(mEncoder, nullptr, nullptr, nullptr, 0); AMediaCodec_start(mEncoder); AMediaSurface* surface = AMediaSurface_fromSurfaceTexture((ASurfaceTexture*) window); AMediaCodec_setOutputSurface(mEncoder, surface); AMediaSurface_release(surface); AMediaCodecBufferInfo bufferInfo; int outputBufferIndex = AMediaCodec_dequeueOutputBuffer(mEncoder, &bufferInfo, 0); if (outputBufferIndex >= 0) { AMediaCodec_releaseOutputBuffer(mEncoder, outputBufferIndex, true); } int inputBufferIndex = AMediaCodec_dequeueInputBuffer(mEncoder, 0); if (inputBufferIndex >= 0) { AMediaCodecInputBuffer* inputBuffer = AMediaCodec_getInputBuffer(mEncoder, inputBufferIndex); size_t bufferSize = AMediaCodec_getInputBufferSize(mEncoder); uint8_t* buffer = AMediaCodecInputBuffer_getBuffer(inputBuffer); memcpy(buffer, data, bufferSize); AMediaCodec_queueInputBuffer(mEncoder, inputBufferIndex, 0, bufferSize, pts, 0); } outputBufferIndex = AMediaCodec_dequeueOutputBuffer(mEncoder, &bufferInfo, 0); if (outputBufferIndex >= 0) { AMediaCodecBufferInfo bufferInfo; AMediaCodec_getOutputBufferInfo(mEncoder, outputBufferIndex, &bufferInfo); uint8_t* outputBuffer = AMediaCodec_getOutputBuffer(mEncoder, outputBufferIndex); AMediaMuxer_writeSampleData(mMuxer, mTrackIndex, outputBuffer, &bufferInfo); AMediaCodec_releaseOutputBuffer(mEncoder, outputBufferIndex, false); mFrameIndex++; } } ``` 在flush函数中,我们停止MediaCodec和MediaMuxer: ```cpp void Encoder::flush() { if (!mIsStarted) { return; } AMediaCodec_signalEndOfInputStream(mEncoder); AMediaCodecBufferInfo bufferInfo; while (true) { int outputBufferIndex = AMediaCodec_dequeueOutputBuffer(mEncoder, &bufferInfo, 0); if (outputBufferIndex >= 0) { AMediaCodec_releaseOutputBuffer(mEncoder, outputBufferIndex, true); } else if (outputBufferIndex == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) { AMediaFormat* format = AMediaCodec_getOutputFormat(mEncoder); AMediaMuxer_addTrack(mMuxer, format); mTrackIndex = AMediaMuxer_addTrack(mMuxer, format); AMediaMuxer_start(mMuxer); } else { break; } } AMediaCodec_stop(mEncoder); AMediaCodec_delete(mEncoder); AMediaMuxer_stop(mMuxer); AMediaMuxer_delete(mMuxer); mIsStarted = false; } ``` 在使用时,我们可以像这样使用渲染器和编码器: ```cpp Renderer renderer; Encoder encoder; renderer.init(); encoder.init(width, height); for (int i = 0; i < numFrames; i++) { renderer.render(data[i], width, height); encoder.encodeFrame(data[i], i * 1000000 / 30); } encoder.flush(); ``` 请注意,这只是一个非常简单的例子,实际上要实现一个完整的视频编码器需要更多的步骤和细节。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值