Erstellen Sie mp4-Dateien auf Android mit Jcodec
ich habe einige Schwierigkeiten mit dem schreiben von mp4-Dateien auf Android mit MediaRecorder und Jcodec, hier ist mein code
public class SequenceEncoder {
private final static String CLASSTAG = SequenceEncoder.class.getSimpleName();
private SeekableByteChannel ch;
private byte[] yuv = null;
private ArrayList<ByteBuffer> spsList;
private ArrayList<ByteBuffer> ppsList;
private CompressedTrack outTrack;
private int frameNo;
private MP4Muxer muxer;
ArrayList<ByteBuffer> spsListTmp = new ArrayList<ByteBuffer>();
ArrayList<ByteBuffer> ppsListTmp = new ArrayList<ByteBuffer>();
//Encoder
private MediaCodec mediaCodec = null;
public SequenceEncoder(File out) throws IOException {
this.ch = NIOUtils.writableFileChannel(out);
//Muxer that will store the encoded frames
muxer = new MP4Muxer(ch, Brand.MP4);
//Add video track to muxer
outTrack = muxer.addTrackForCompressed(TrackType.VIDEO, 25);
//Encoder extra data ( SPS, PPS ) to be stored in a special place of
//MP4
spsList = new ArrayList<ByteBuffer>();
ppsList = new ArrayList<ByteBuffer>();
}
@SuppressWarnings("unchecked")
public void encodeImage(ByteBuffer buffer, int width, int height) throws IOException {
if (yuv == null) {
int bufferSize = width * height * 3 / 2;
yuv = new byte[bufferSize];
int bitRate = bufferSize;
int frameRate = 25;
String mimeType = "video/avc";
//"video/avc"
mediaCodec = MediaCodec.createEncoderByType(mimeType);
MediaFormat mediaFormat = MediaFormat.createVideoFormat(mimeType, width, height);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate); //125000);
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar);
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5);
mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
mediaCodec.start();
}
byte[] rgba = buffer.array();
//Convert RGBA image to NV12 (YUV420SemiPlanar)
Rgba2Yuv420.convert(rgba, yuv, width, height);
synchronized (mediaCodec) {
try {
ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();
int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);
if (inputBufferIndex >= 0) {
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
inputBuffer.clear();
inputBuffer.put(yuv);
mediaCodec.queueInputBuffer(inputBufferIndex, 0,
yuv.length, 0, 0);
}
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int outputBufferIndex = mediaCodec.dequeueOutputBuffer(
bufferInfo, 0);
while (outputBufferIndex >= 0) {
ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
byte[] outData = new byte[bufferInfo.size];
outputBuffer.get(outData);
ByteBuffer frameBuffer = ByteBuffer.wrap(outData);
spsListTmp.clear();
ppsListTmp.clear();
H264Utils.encodeMOVPacket(frameBuffer, spsListTmp, ppsListTmp);
if (!spsListTmp.isEmpty())
spsList = (ArrayList<ByteBuffer>) spsListTmp.clone();
if (!ppsListTmp.isEmpty())
ppsList = (ArrayList<ByteBuffer>) ppsListTmp.clone();
outTrack.addFrame(new MP4Packet(frameBuffer, frameNo, 25, 1,
frameNo, true, null, frameNo, 0));
frameNo++;
mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
outputBufferIndex = mediaCodec.dequeueOutputBuffer(
bufferInfo, 0);
}
if (outputBufferIndex < 0)
switch (outputBufferIndex) {
case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
outputBuffers = mediaCodec.getOutputBuffers();
break;
case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
break;
case MediaCodec.INFO_TRY_AGAIN_LATER:
break;
default:
break;
}
} catch (Exception e) {
}
}
}
public void finish() throws IOException {
if (!ch.isOpen())
return;
if (mediaCodec != null) {
mediaCodec.stop();
mediaCodec.release();
}
outTrack.addSampleEntry(H264Utils.createMOVSampleEntry(spsList, ppsList));
//Write MP4 header and finalize recording
muxer.writeHeader();
NIOUtils.closeQuietly(ch);
ch.close();
}
}
Wie wir sehen können Android MediaCodec erwarten YUV420SemiPlanar als input-Bild, also gebe ich ihm das richtige. Als Ergebnis habe ich eine beschädigte mp4-Datei mit ungültigen Farben, wenn ich öffnen Sie das mp4-Datei von AVCon ich sehen, dass Farbe format in die Ausgabe-Datei ist yuv420p, so vielleicht das problem? Bitte vorschlagen, wie dieses Problem zu beheben.
Habe auch noch eine Frage, wie man komprimierte audio-stream muxer, nicht gefunden haben, Beispiele.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Android 4.3 (API 18) hat zwei neue features, die nützlich sein können.
Erste, der
MediaCodec
Klasse akzeptiert Eingaben, die von der Oberfläche, so alles, was Sie entschlüsseln können, um eine Oberfläche oder Rendern mit OpenGL ES aufgenommen werden kann, ohne Geige mit YUV Farbebenen.Zweite, die neue MediaMuxer - Klasse bietet eine Möglichkeit zum kombinieren von audio-und H. 264-video in einem .mp4-Datei.
Beispiel source-code (in Erster Linie für die video-Aspekte) finden Sie hier.
YUV420SemiPlanar von 4x4 Bild ist ein format wie YYYYYYYYYYYYYYYYUVUVUVUV, Nicht YYYYYYYYYYYYYYYYUUUUVVVV.
Ich kann die mp4-Datei mit der richtigen Farbe mit Jcodec und MediaCodec auf Android, nachdem ich an einem Bild mit dem format.
Habe ich nicht eine Antwort über audio.