当下抖音非常火热,你是不是也很心动做一个类似的 App?
短视频内容生产
优质短视频内容的产生依赖于短视频的采集和特效编辑,这就要求在进行抖音 App 开发时,用到基础的美颜、混音、滤镜、变速、图片视频混剪、字幕等功能。
在这些功能基础上,进行预处理,结合 OpenGL、AI、AR 技术,产生很多有趣的动态贴纸玩法,使得短视频内容更具创意。
视频录制的大致实现流程是先由 Camera 、 AudioRecord 进行最原始的相机画面以及声音的采集,然后将采集的数据进行滤镜、降噪等前处理,处理完成后由 MediaCodec 进行硬件编码,***采用 MediaMuxer 生成最终的 MP4 文件。
短视频处理播放
视频的处理和播放主要是视频的清晰度、观看流畅度方面的体验。在这方面来讲,可以采用“窄带高清”技术,在节省码率的同时能够提供更加清晰的观看体验,经过测试,同等视频质量下***可以节省 20-40% 带宽。
除了带宽之外,短视频内容的存储和 CDN 优化也尤为重要,通常我们需要上传到云存储服务器的内容是短视频内容和封面内容。
而 CDN 优化带给短视频平台的则是进一步的短视频***载入和循环播放方面的体验。
比如针对首播慢的问题,像阿里云播放器支持 QUIC 协议,基于 CDN 的调度,可以使短视频***播放秒开的成功率达到 98%。
此外在循环播放时还可以边播放边缓存,用户反复观看某一短视频时就不用耗费流量了。
录制视频的方式
在 Android 系统当中,如果需要一台 Android 设备来获取到一个 MP4 这样的视频文件的话,主流的方式一共与三种:
MediaRecorder:是 Android 系统直接提供给我们的录制类,用于录制音频和视频的一个类,简单方便。
它不需要理会中间录制过程,结束录制后可以直接得到音频文件进行播放,录制的音频文件是经过压缩的,需要设置编码器,录制的音频文件可以用系统自带的播放器播放。
优点:大部分以及集成,直接调用相关接口即可,代码量小,简单稳定;缺点:无法实时处理音频;输出的音频格式不是很多。
MediaCodec+MediaMuxer:MediaCodec 与 MediaMuxer 结合使用同样能够实现录制的功能。
MediaCodec 是 Android 提供的编解码类,MediaMuxer 则是复用类(生成视频文件)。
从易用性的角度上来说肯定不如 MediaRecorder,但是允许我们进行更加灵活的操作,比如需要给录制的视频添加水印等各种效果。
优点: 与 MediaRecorder 一样低功耗速度快,并且更加灵活;缺点: 支持的格式有限,兼容性问题。
FFmpeg:FFmpeg(Fast forword mpeg,音视频转换器)是一个开源免费跨平台的视频和音频流方案,它提供了录制/音视频编解码、转换以及流化音视频的完整解决方案。
主要的作用在于对多媒体数据进行解协议、解封装、解码以及转码等操作。
优点:格式支持非常的强,十分的灵活,功能强大,兼容性好;缺点:C语言些的音视频编解码程序,使用起来不是很方便。
虽然从数据看来 FFmpeg 是***的,但是我们得首先排除这种,因为他的易用性是最差的。
其次,MediaRecorder 也是需要排除的,所以在这里我比较推荐 MediaCodec+MediaMuxer 这种方式。
编码器参数
码率:数据传输时单位时间传送的数据位数,KBPS:千位每秒。码率和质量成正比,也和文件体积成正比。码率超过一定数值,对图像的质量没有多大的影响。
帧数:每秒显示多少个画面,FPS。
关键帧间隔:在 H.264 编码中,编码后输出的压缩图像数据有多种,可以简单的分为关键帧和非关键帧。
关键帧能够进行独立解码,看成是一个图像经过压缩的产物。而非关键帧包含了与其他帧的“差异”信息,也可以称呼为“参考帧”,它的解码需要参考关键帧才能够解码出一个图像。非关键帧拥有更高的压缩率。
MediaCodec+MediaMuxer 的使用
MediaMuxer 和 MediaCodec 这两个类,它们的参考文:
里边有使用的框架。这个组合可以实现很多功能,比如音视频文件的编辑(结合 MediaExtractor),用 OpenGL 绘制 Surface 并生成 MP4 文件,屏幕录像以及类似 Camera App 里的录像功能(虽然这个用 MediaRecorder 更合适)等。
它们一个是生成视频,一个生成音频,这里把它们结合一下,同时生成音频和视频。
基本框架和流程如下:
首先是录音线程,主要参考 HWEncoderExperiments。通过 AudioRecord 类接收来自麦克风的采样数据,然后丢给 Encoder 准备编码:
- AudioRecord audio_recorder;
- audio_recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
- SAMPLE_RATE, CHANNEL_CONFIG, AUDIO_FORMAT, buffer_size);
- // ...
- audio_recorder.startRecording();
- while (is_recording) {
- byte[] this_buffer = new byte[frame_buffer_size];
- read_result = audio_recorder.read(this_buffer, 0, frame_buffer_size); // read audio raw data
- // …
- presentationTimeStamp = System.nanoTime() / 1000;
- audioEncoder.offerAudioEncoder(this_buffer.clone(), presentationTimeStamp); // feed to audio encoder
- }
这里也可以设置 AudioRecord 的回调(通过 setRecordPositionUpdateListener())来触发音频数据的读取。
offerAudioEncoder() 里主要是把 Audio 采样数据送入音频 MediaCodec 的 InputBuffer 进行编码:
- ByteBuffer[] inputBuffers = mAudioEncoder.getInputBuffers();
- int inputBufferIndex = mAudioEncoder.dequeueInputBuffer(-1);
- if (inputBufferIndex >= 0) {
- ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
- inputBuffer.clear();
- inputBuffer.put(this_buffer);
- ...
- mAudioEncoder.queueInputBuffer(inputBufferIndex, 0, this_buffer.length, presentationTimeStamp, 0);
- }
下面,参考 Grafika-SoftInputSurfaceActivity,并加入音频处理。主循环大体分四部分:
- try {
- // Part 1
- prepareEncoder(outputFile);
- ...
- // Part 2
- for (int i = 0; i < NUM_FRAMES; i++) {
- generateFrame(i);
- drainVideoEncoder(false);
- drainAudioEncoder(false);
- }
- // Part 3
- ...
- drainVideoEncoder(true);
- drainAudioEncoder(true);
- } catch (IOException ioe) {
- throw new RuntimeException(ioe);
- } finally {
- // Part 4
- releaseEncoder();
- }
第 1 部分是准备工作,除了 Video 的 MediaCodec,这里还初始化了 Audio 的 MediaCodec:
- MediaFormat audioFormat = new MediaFormat();
- audioFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, 44100);
- audioFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
- ...
- mAudioEncoder = MediaCodec.createEncoderByType(AUDIO_MIME_TYPE);
- mAudioEncoder.configure(audioFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
- mAudioEncoder.start();
第 2 部分进入主循环,App 在 Surface 上直接绘图,由于这个 Surface 是从 MediaCodec 中用 createInputSurface() 申请来的,所以画完后不用显式用 queueInputBuffer() 交给 Encoder。
drainVideoEncoder() 和 drainAudioEncoder() 分别将编码好的音视频从 Buffer 中拿出来(通过 dequeueOutputBuffer()),然后交由 MediaMuxer 进行混合(通过 writeSampleData())。
注意音视频通过 PTS(Presentation Time Stamp,决定了某一帧的音视频数据何时显示或播放)来同步,音频的 time stamp 需在 AudioRecord 从 MIC 采集到数据时获取并放到相应的 bufferInfo 中。
视频由于是在 Surface 上画,因此直接用 dequeueOutputBuffer() 出来的 bufferInfo 中的就行,***将编码好的数据送去 MediaMuxer 进行多路混合。
注意这里 Muxer 要等把 audio track 和 video track 都加入了再开始。
MediaCodec 在一开始调用 dequeueOutputBuffer() 时会返回一次 INFO_OUTPUT_FORMAT_CHANGED消息。
我们只需在这里获取该 MediaCodec 的 format,并注册到 MediaMuxer 里。
接着判断当前 audio track 和 video track 是否都已就绪,如果是的话就启动 Muxer。
总结来说,drainVideoEncoder() 的主逻辑大致如下,drainAudioEncoder 也是类似的,只是把 video 的 MediaCodec 换成 audio 的 MediaCodec 即可:
- while(true) {
- int encoderStatus = mVideoEncoder.dequeueOutputBuffer(mBufferInfo, TIMEOUT_USEC);
- if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
- ...
- } else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
- encoderOutputBuffers = mVideoEncoder.getOutputBuffers();
- } else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
- MediaFormat newFormat = mAudioEncoder.getOutputFormat();
- mAudioTrackIndex = mMuxer.addTrack(newFormat);
- mNumTracksAdded++;
- if (mNumTracksAdded == TOTAL_NUM_TRACKS) {
- mMuxer.start();
- }
- } else if (encoderStatus < 0) {
- ...
- } else {
- ByteBuffer encodedData = encoderOutputBuffers[encoderStatus];
- ...
- if (mBufferInfo.size != 0) {
- mMuxer.writeSampleData(mVideoTrackIndex, encodedData, mBufferInfo);
- }
- mVideoEncoder.releaseOutputBuffer(encoderStatus, false);
- if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
- break;
- }
- }
- }
第 3 部分是结束录制,发送 EOS 信息,这样在 drainVideoEncoder() 和 drainAudioEncoder 中就可以根据 EOS 退出内循环。
第 4 部分为清理工作。把 audio 和 video 的 MediaCodec,MediaCodec 用的 Surface 及 MediaMuxer 对象释放。
***几点注意:
总结
以上就是抖音类 App 的部分内容,其中的步骤和过程是我亲自实践过的,按照上述的过程应该都可以正常运行,写这一篇文章花了很多时间,希望所有看了这篇文章的朋友们都能够有一定的收获。
网站标题:刷抖音看美腿中毒后,我决定做一款抖音App
文章出自:http://www.shufengxianlan.com/qtweb/news13/342563.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联