Uygulamamda, kullanıcının galeriden seçtiği bazı videoları yüklemeye çalışıyorum. Sorun şu ki, genellikle android video dosyaları yüklemek için çok büyük ve bu yüzden ilk önce daha düşük bit hızı/çözünürlüğü tarafından sıkıştırmak istiyoruz.Yeni MediaCodec Kitaplığı'nı kullanarak android üzerinde video sıkıştırma
API 16 ile tanıtılan yeni MediaCodec API'yı (ffmpeg ile bunu yapmaya çalıştım) yeni duydum.
Şu anda şu anda yapıyorum: İlk olarak video kod çözücü kullanarak giriş videosunu çözün ve giriş dosyasından okunan biçimle yapılandırın. Ardından, önceden tanımlanmış bazı parametrelere sahip standart bir video kodlayıcı oluşturun ve dekoder çıktı arabelleğini kodlamak için kullanın. Sonra kodlayıcı çıkış tamponunu bir dosyaya kaydediyorum.
Her şey iyi görünüyor - her bir giriş ve çıkış arabelleğinden aynı sayıda paket yazılıyor ve okunıyor, ancak son dosya bir video dosyası gibi görünmüyor ve herhangi bir video oynatıcı tarafından açılamıyor.
Kod çözme işlemi tamam gibi görünüyor, çünkü bunu Yüzeyde görüntüleyerek test ediyorum. İlk olarak kod çözücüyü bir Yüzey ile çalışacak şekilde yapılandıracağım ve releaseOutputBuffer dediğimizde render işaretini kullanıyoruz ve videoyu ekranda görebiliyoruz.
//init decoder
MediaCodec decoder = MediaCodec.createDecoderByType(mime);
decoder.configure(format, null , null , 0);
decoder.start();
ByteBuffer[] codecInputBuffers = decoder.getInputBuffers();
ByteBuffer[] codecOutputBuffers = decoder.getOutputBuffers();
//init encoder
MediaCodec encoder = MediaCodec.createEncoderByType(mime);
int width = format.getInteger(MediaFormat.KEY_WIDTH);
int height = format.getInteger(MediaFormat.KEY_HEIGHT);
MediaFormat mediaFormat = MediaFormat.createVideoFormat(mime, width, height);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 400000);
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 25);
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar);
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5);
encoder.configure(mediaFormat, null , null , MediaCodec.CONFIGURE_FLAG_ENCODE);
encoder.start();
ByteBuffer[] encoderInputBuffers = encoder.getInputBuffers();
ByteBuffer[] encoderOutputBuffers = encoder.getOutputBuffers();
extractor.selectTrack(0);
boolean sawInputEOS = false;
boolean sawOutputEOS = false;
boolean sawOutputEOS2 = false;
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
BufferInfo encoderInfo = new MediaCodec.BufferInfo();
while (!sawInputEOS || !sawOutputEOS || !sawOutputEOS2) {
if (!sawInputEOS) {
sawInputEOS = decodeInput(extractor, decoder, codecInputBuffers);
}
if (!sawOutputEOS) {
int outputBufIndex = decoder.dequeueOutputBuffer(info, 0);
if (outputBufIndex >= 0) {
sawOutputEOS = decodeEncode(extractor, decoder, encoder, codecOutputBuffers, encoderInputBuffers, info, outputBufIndex);
} else if (outputBufIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
Log.d(LOG_TAG, "decoding INFO_OUTPUT_BUFFERS_CHANGED");
codecOutputBuffers = decoder.getOutputBuffers();
} else if (outputBufIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
final MediaFormat oformat = decoder.getOutputFormat();
Log.d(LOG_TAG, "decoding Output format has changed to " + oformat);
} else if (outputBufIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
Log.d(LOG_TAG, "decoding dequeueOutputBuffer timed out!");
}
}
if (!sawOutputEOS2) {
int encodingOutputBufferIndex = encoder.dequeueOutputBuffer(encoderInfo, 0);
if (encodingOutputBufferIndex >= 0) {
sawOutputEOS2 = encodeOuput(outputStream, encoder, encoderOutputBuffers, encoderInfo, encodingOutputBufferIndex);
} else if (encodingOutputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
Log.d(LOG_TAG, "encoding INFO_OUTPUT_BUFFERS_CHANGED");
encoderOutputBuffers = encoder.getOutputBuffers();
} else if (encodingOutputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
final MediaFormat oformat = encoder.getOutputFormat();
Log.d(LOG_TAG, "encoding Output format has changed to " + oformat);
} else if (encodingOutputBufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
Log.d(LOG_TAG, "encoding dequeueOutputBuffer timed out!");
}
}
}
//clear some stuff here...
ve bu ben kod çözme/kodlamak için kullanmak yöntemdir: Burada
ben kod kullanıyorum edilir
private boolean decodeInput(MediaExtractor extractor, MediaCodec decoder, ByteBuffer[] codecInputBuffers) {
boolean sawInputEOS = false;
int inputBufIndex = decoder.dequeueInputBuffer(0);
if (inputBufIndex >= 0) {
ByteBuffer dstBuf = codecInputBuffers[inputBufIndex];
input1count++;
int sampleSize = extractor.readSampleData(dstBuf, 0);
long presentationTimeUs = 0;
if (sampleSize < 0) {
sawInputEOS = true;
sampleSize = 0;
Log.d(LOG_TAG, "done decoding input: #" + input1count);
} else {
presentationTimeUs = extractor.getSampleTime();
}
decoder.queueInputBuffer(inputBufIndex, 0, sampleSize, presentationTimeUs, sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
if (!sawInputEOS) {
extractor.advance();
}
}
return sawInputEOS;
}
private boolean decodeOutputToFile(MediaExtractor extractor, MediaCodec decoder, ByteBuffer[] codecOutputBuffers,
MediaCodec.BufferInfo info, int outputBufIndex, OutputStream output) throws IOException {
boolean sawOutputEOS = false;
ByteBuffer buf = codecOutputBuffers[outputBufIndex];
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
sawOutputEOS = true;
Log.d(LOG_TAG, "done decoding output: #" + output1count);
}
if (info.size > 0) {
output1count++;
byte[] outData = new byte[info.size];
buf.get(outData);
output.write(outData, 0, outData.length);
} else {
Log.d(LOG_TAG, "no data available " + info.size);
}
buf.clear();
decoder.releaseOutputBuffer(outputBufIndex, false);
return sawOutputEOS;
}
private boolean encodeInputFromFile(MediaCodec encoder, ByteBuffer[] encoderInputBuffers, MediaCodec.BufferInfo info, FileChannel channel) throws IOException {
boolean sawInputEOS = false;
int inputBufIndex = encoder.dequeueInputBuffer(0);
if (inputBufIndex >= 0) {
ByteBuffer dstBuf = encoderInputBuffers[inputBufIndex];
input1count++;
int sampleSize = channel.read(dstBuf);
if (sampleSize < 0) {
sawInputEOS = true;
sampleSize = 0;
Log.d(LOG_TAG, "done encoding input: #" + input1count);
}
encoder.queueInputBuffer(inputBufIndex, 0, sampleSize, channel.position(), sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
}
return sawInputEOS;
}
yanlış yapıyorum üzerinde herhangi bir öneri?
Ben MediaCodec ile kodlama için çok fazla örnekler çözme için sadece birkaç örnek kodu ... sayesinde yardım
MediaCodec'e ihtiyacınız yoktur. Tek başına gitmek tehlikelidir, bunu yapın: http://stackoverflow.com/a/23815402 –
Yorumlar bölümünde belirtildiği gibi - ffmpeg kullanarak bittim – shem
@ shem: Bu sorunu çözdünüz mü? Aynı problem üzerinde başarı olmadan çalışıyorum. Like @fadden, çıktıyı bir MediaMuxer ile biçimlendirmemiz gerektiğine katılıyorum. Lütfen bir dosya okuyan (MediaExtractor) bir örneğe işaret edin ve farklı bir boyutta kodlanmış bir video yazdım (API 22 seviyesini kullanıyorum, bu yüzden asenkron bir örnek daha iyi olurdu!) –