ImageToVideoUtil2.java
9.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
package com.sw.laryngoscope.imageToVideo;
import android.graphics.Bitmap;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.media.MediaFormat;
import android.media.MediaMuxer;
import android.os.Environment;
import android.util.Log;
import android.view.Surface;
import java.io.IOException;
import java.nio.ByteBuffer;
public class ImageToVideoUtil2 {
MediaCodec mediaCodec;
MediaMuxer mediaMuxer;
boolean mMuxerStarted, isRunning;
public static final String TAG = "ImageToVideoUtil2";
MediaCodec.BufferInfo mBufferInfo=null;
private int mVideoTrackIndex;
EglSurfaceBase eglSurfaceBase;
EglEnv eglEnv;
EncodeProgram2 encodeProgram2;
public void init(int width, int height){
mBufferInfo = new MediaCodec.BufferInfo();
try {
mediaCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
Log.d("ImageToVideoUtil2", " " + Environment.getExternalStorageDirectory().getAbsolutePath().trim());
//创建生成MP4初始化对象
mediaMuxer = new MediaMuxer(Environment.getExternalStorageDirectory().getAbsolutePath()+"/outputbitmap.mp4", MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
} catch (IOException e) {
e.printStackTrace();
}
MediaFormat mediaFormat = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, width, height);
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, width * height);
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 21);
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10);
mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
Surface surface= mediaCodec.createInputSurface();
mediaCodec.start();
EglCore eglCore = new EglCore();
eglSurfaceBase = new EglSurfaceBase(eglCore);
eglSurfaceBase.createWindowSurface(surface,width,height);
eglSurfaceBase.makeCurrent();
// eglEnv = new EglEnv(width,height);
// eglEnv.setUpEnv();
// eglEnv.buildWindowSurface(surface);
// encodeProgram2 = new EncodeProgram2(new int[]{width,height});
// encodeProgram2.build();
}
public int getColorFormat(){
int colorFormat = 0;
int[] formats = this.getMediaCodecList();
lab:
for (int format : formats) {
switch (format) {
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar: // yuv420sp
colorFormat = format;
break lab;
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar: // yuv420p
colorFormat = format;
break lab;
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar: // yuv420psp
colorFormat = format;
break lab;
case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar: // yuv420pp
colorFormat = format;
break lab;
}
}
if (colorFormat <= 0) {
colorFormat = MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar;
}
return colorFormat;
}
public int[] getMediaCodecList() {
//获取解码器列表
int numCodecs = MediaCodecList.getCodecCount();
MediaCodecInfo codecInfo = null;
for (int i = 0; i < numCodecs && codecInfo == null; i++) {
MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
if (!info.isEncoder()) {
continue;
}
String[] types = info.getSupportedTypes();
boolean found = false;
//轮训所要的解码器
for (int j = 0; j < types.length && !found; j++) {
if (types[j].equals("video/avc")) {
found = true;
}
}
if (!found) {
continue;
}
codecInfo = info;
}
Log.d(TAG, "found" + codecInfo.getName() + "supporting" + " video/avc");
MediaCodecInfo.CodecCapabilities capabilities = codecInfo.getCapabilitiesForType("video/avc");
return capabilities.colorFormats;
}
/**
* Extracts all pending data from the encoder and forwards it to the muxer.
* <p>
* If endOfStream is not set, this returns when there is no more data to drain. If it
* is set, we send EOS to the encoder, and then iterate until we see EOS on the output.
* Calling this with endOfStream set should be done once, right before stopping the muxer.
* <p>
* We're just using the muxer to get a .mp4 file (instead of a raw H.264 stream). We're
* not recording audio.
*/
public void drainEncoder(boolean endOfStream) {
final int TIMEOUT_USEC = 10000;
L.i(TAG, "drainEncoder(" + endOfStream + ")");
if (endOfStream) {
L.i(TAG, "sending EOS to encoder");
mediaCodec.signalEndOfInputStream();
}
ByteBuffer[] encoderOutputBuffers = mediaCodec.getOutputBuffers();
while (true) {
int encoderStatus = mediaCodec.dequeueOutputBuffer(mBufferInfo, TIMEOUT_USEC);
if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
L.i(TAG, "encoderStatus == MediaCodec MediaCodec.INFO_TRY_AGAIN_LATER: ");
// no output available yet
if (!endOfStream) {
L.i(TAG, "no output available, break not end");
break; // out of while
} else {
L.i(TAG, "no output available, spinning to await EOS");
// break;
}
} else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
// not expected for an encoder\
L.i(TAG, "encoderStatus == MediaCodec INFO_OUTPUT_BUFFERS_CHANGED: 获取数据");
encoderOutputBuffers = mediaCodec.getOutputBuffers();
} else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
L.i(TAG, "encoderStatus == MediaCodec MediaCodec.INFO_OUTPUT_FORMAT_CHANGED: ");
// should happen before receiving buffers, and should only happen once
// synchronized (lock) {
if (mMuxerStarted) {
throw new RuntimeException("format changed twice");
}
// if(!mMuxerStarted) {
MediaFormat newFormat = mediaCodec.getOutputFormat();
L.i(TAG, "encoder output format changed: " + newFormat);
// now that we have the Magic Goodies, start the muxer
mVideoTrackIndex = mediaMuxer.addTrack(newFormat);
if (mVideoTrackIndex >= 0) {
mediaMuxer.start();
mMuxerStarted = true;
}
// }
// }
} else if (encoderStatus < 0) {
L.i(TAG, "unexpected result from encoder.dequeueOutputBuffer: encoderStatus < 0" +
encoderStatus);
// let's ignore it
} else {
Log.d(TAG, "encoderStatus > 0");
ByteBuffer encodedData = encoderOutputBuffers[encoderStatus];
if (encodedData == null) {
throw new RuntimeException("encoderOutputBuffer " + encoderStatus + " was null");
}
if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
// The codec config data was pulled out and fed to the muxer when we got
// the INFO_OUTPUT_FORMAT_CHANGED status. Ignore it.
Log.d(TAG, "ignoring BUFFER_FLAG_CODEC_CONFIG");
mBufferInfo.size = 0;
}
if (mBufferInfo.size != 0) {
if (!mMuxerStarted) {
throw new RuntimeException("muxer hasn't started");
}
// adjust the ByteBuffer values to match BufferInfo (not needed?)
encodedData.position(mBufferInfo.offset);
encodedData.limit(mBufferInfo.offset + mBufferInfo.size);
if (mMuxerStarted) {
mediaMuxer.writeSampleData(mVideoTrackIndex, encodedData, mBufferInfo);
L.i(TAG, "sent " + mBufferInfo.size + " bytes to muxer, ts=" +
mBufferInfo.presentationTimeUs);
}
}
mediaCodec.releaseOutputBuffer(encoderStatus, false);
if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
L.i(TAG, "BUFFER_FLAG_END_OF_STREAM");
if (!endOfStream) {
L.i(TAG, "reached end of stream unexpectedly");
} else {
L.i(TAG, "end of stream reached");
}
break; // out of while
}
}
}
}
public void drawframe(Bitmap bitmap,int num){
eglSurfaceBase.drawFrame(bitmap,1000000/21*1000L*(num));
// encodeProgram2.renderBitmap(bitmap);
// eglEnv.setPresentationTime(1000000/16*1000L*num);
// eglEnv.swapBuffers();
drainEncoder(false);
}
public void drainEnd() {
drainEncoder(true);
eglSurfaceBase.releaseEglSurface();
// eglEnv.relase();
mediaCodec.stop();
mediaCodec.release();
mediaMuxer.stop();
mediaMuxer.release();
mediaMuxer = null;
}
}