下载贤集网APP入驻自媒体
这次要用到新的东西SurView、MediaCodec、MediaExtractor、MediaFormat
1.文字说明2.视频播放顺序
SurView:一个View,用来显示视频的,使用的时候代码都比较简单就不多说了
MediaCodec:访问底层媒体编码,能够完成媒体编码和解码
编码是将源对象内容按照一种标准转换为一种标准格式内容。
解码是和编码对应的,它使用和编码相同的标准将编码内容还原为最初的对象内容。
MediaExtractor:负责将指定类型的媒体文件从文件中找到轨道,并填充到MediaCodec的缓冲区中
MediaFormat:封装描述媒体数据格式的信息,无论是音频还是视频。媒体数据的格式被指定为字符串/值对。所有格式通用的键,所有未标记为可选的键都是必需的:
名称 值类型 描述
KEY_MIME 串 格式的类型。
KEY_MAX_INPUT_SIZE 整数 可选,输入数据缓冲区的最大大小
KEY_BIT_RATE 整数 仅编码器,所需比特率(以比特/秒为单位)
(1)开启两个线程分别处理MP4的音频和视频
我先说一下视频的处理使用MediaExtractor提取资源,选择频道
复制代码
- MediaExtractor videoExtractor = new MediaExtractor();
- MediaCodec videoCodec = null;
- try {
- videoExtractor.setDataSource(filePath);
- } catch (IOException e) {
- e.printStackTrace();
- }
- int videoTrackIndex;
- //获取视频所在轨道
- videoTrackIndex = getMediaTrackIndex(videoExtractor, "video/");
- videoExtractor.selectTrack(videoTrackIndex);
设置解码配置,并给MediaCodec配置,而且将SurView于MediaCodec相关联,设置为在这个SurView上显示
复制代码
- MediaFormat mediaFormat = videoExtractor.getTrackFormat(videoTrackIndex);
- int width = mediaFormat.getInteger(MediaFormat.KEY_WIDTH);
- int height = mediaFormat.getInteger(MediaFormat.KEY_HEIGHT);
- float time = mediaFormat.getLong(MediaFormat.KEY_DURATION) / 1000000;
- callBack.videoAspect(width, height, time);
- videoExtractor.selectTrack(videoTrackIndex);
- try {
- videoCodec = MediaCodec.createDecoderByType(mediaFormat.getString(MediaFormat.KEY_MIME));
- videoCodec.configure(mediaFormat, sur, null, 0);
- } catch (IOException e) {
- e.printStackTrace();
- }
循环从MediaExtractor取数据放入MediaCodec,同时MediaCodec返回数据,表示视频播放状态,然后对应转台做不同的处理,
复制代码
- while (!Thread.interrupted()) {
- if (!isPlaying) {
- continue;
- }
- //将资源传递到解码器
- if (!isVideoEOS) {
- isVideoEOS = putBufferToCoder(videoExtractor, videoCodec, inputBuffers);
- }
- int outputBufferIndex = videoCodec.dequeueOutputBuffer(videoBufferInfo, TIMEOUT_US);
- switch (outputBufferIndex) {
- case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
- Log.v(TAG, "format changed");
- break;
- case MediaCodec.INFO_TRY_AGAIN_LATER:
- Log.v(TAG, "超时");
- break;
- case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
- //outputBuffers = videoCodec.getOutputBuffers();
- Log.v(TAG, "output buffers changed");
- break;
- default:
- //直接渲染到Sur时使用不到outputBuffer
- //ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
- //延时操作
- //如果缓冲区里的可展示时间>当前视频播放的进度,就休眠一下
- sleepRender(videoBufferInfo, startMs);
- //渲染
- videoCodec.releaseOutputBuffer(outputBufferIndex, true);
- break;
- }
- if ((videoBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
- Log.v(TAG, "buffer stream end");
- break;
- }
- }//end while
然后是音频,很相似
MediaExtractor获取资源,选择频道,得到MediaFormat,获取一些参数来配置AudioTrack,然后就不说了,上一篇博客说了如何播放音频,复制代码
- MediaExtractor audioExtractor = new MediaExtractor();
- try {
- audioExtractor.setDataSource(filePath);
- } catch (IOException e) {
- e.printStackTrace();
- }
- MediaFormat mediaFormat = audioExtractor.getTrackFormat(i);
- String mime = mediaFormat.getString(MediaFormat.KEY_MIME);
- if (mime.startsWith("audio/")) {
- audioExtractor.selectTrack(i);
- int audioChannels = mediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
- int audioSampleRate = mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE);
- int minBufferSize = AudioTrack.getMinBufferSize(audioSampleRate,
- (audioChannels == 1 ? AudioFormat.CHANNEL_OUT_MONO : AudioFormat.CHANNEL_OUT_STEREO),
- AudioFormat.ENCODING_PCM_16BIT);
- int maxInputSize = mediaFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);
- audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
- audioSampleRate,
- (audioChannels == 1 ? AudioFormat.CHANNEL_OUT_MONO : AudioFormat.CHANNEL_OUT_STEREO),
- AudioFormat.ENCODING_PCM_16BIT,
- audioInputBufferSize,
- AudioTrack.MODE_STREAM);
其实这做的不太好,因为音频和视频没有做协调,之前可能不同步