我能够使用MediaCodec API解码和播放内容(在更改比特率之前),但如果我在解码之前尝试使用不同的比特率对内容进行重新编码,则会出现乱码(绿屏灰色)像素化).
我使用的代码基于AndroID测试用例androID.media.cts.DecoderTest Android Test Case android.media.cts.DecoderTest:
public voID encodeDecodeVIDeofile(AssetfileDescriptor assetfileDescriptor) { int bitRate = 500000; int frameRate = 30; int wIDth = 480; int height = 368; String mimeType = "vIDeo/avc"; MediaCodec encoder,decoder = null; ByteBuffer[] encoderinputBuffers; ByteBuffer[] encoderOutputBuffers; ByteBuffer[] decoderinputBuffers = null; ByteBuffer[] decoderOutputBuffers = null; // Find a code that supports the mime type 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(mimeType)) found = true; } if (!found) continue; codecInfo = info; } Log.d(TAG,"Found " + codecInfo.getname() + " supporting " + mimeType); // Find a color profile that the codec supports int colorFormat = 0; MediaCodecInfo.CodecCapabilitIEs capabilitIEs = codecInfo.getCapabilitIEsForType(mimeType); for (int i = 0; i < capabilitIEs.colorFormats.length && colorFormat == 0; i++) { int format = capabilitIEs.colorFormats[i]; switch (format) { case MediaCodecInfo.CodecCapabilitIEs.color_FormatYUV420Planar: case MediaCodecInfo.CodecCapabilitIEs.color_FormatYUV420Packedplanar: case MediaCodecInfo.CodecCapabilitIEs.color_FormatYUV420SemiPlanar: case MediaCodecInfo.CodecCapabilitIEs.color_FormatYUV420PackedSemiPlanar: case MediaCodecInfo.CodecCapabilitIEs.color_TI_FormatYUV420PackedSemiPlanar: colorFormat = format; break; default: Log.d(TAG,"SkipPing unsupported color format " + format); break; } } Log.d(TAG,"Using color format " + colorFormat); // Determine wIDth,height and slice sizes if (codecInfo.getname().equals("OMX.TI.DUCATI1.VIDEO.H264E")) { // This codec doesn't support a wIDth not a multiple of 16,// so round down. wIDth &= ~15; } int strIDe = wIDth; int sliceHeight = height; if (codecInfo.getname().startsWith("OMX.NvIDia.")) { strIDe = (strIDe + 15) / 16 * 16; sliceHeight = (sliceHeight + 15) / 16 * 16; } // Used MediaExtractor to select the first track from the h.264 content MediaExtractor extractor = new MediaExtractor(); extractor.setDataSource(assetfileDescriptor.getfileDescriptor(),assetfileDescriptor.getStartOffset(),assetfileDescriptor.getLength()); MediaFormat extractedFormat = extractor.getTrackFormat(0); String mime = extractedFormat.getString(MediaFormat.KEY_MIME); Log.d(TAG,"Extartced Mime " + mime); extractor.selectTrack(0); // Create an encoder encoder = MediaCodec.createByCodecname(codecInfo.getname()); MediaFormat inputFormat = MediaFormat.createVIDeoFormat(mimeType,wIDth,height); inputFormat.setInteger(MediaFormat.KEY_BIT_RATE,bitRate); inputFormat.setInteger(MediaFormat.KEY_FRAME_RATE,frameRate); inputFormat.setInteger(MediaFormat.KEY_color_FORMAT,colorFormat); inputFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL,5); inputFormat.setInteger("strIDe",strIDe); inputFormat.setInteger("slice-height",sliceHeight); Log.d(TAG,"Configuring encoder with input format " + inputFormat); encoder.configure(inputFormat,null /* surface */,null /* crypto */,MediaCodec.CONfigURE_FLAG_ENCODE); encoder.start(); encoderinputBuffers = encoder.getinputBuffers(); encoderOutputBuffers = encoder.getoutputBuffers(); // start enCoding + deCoding final long kTimeOutUs = 5000; MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); boolean sawinputEOS = false; boolean sawOutputEOS = false; MediaFormat oformat = null; long startMs = System.currentTimeMillis(); while (!sawOutputEOS) { if (!sawinputEOS) { int inputBufIndex = encoder.dequeueinputBuffer(kTimeOutUs); if (inputBufIndex >= 0) { ByteBuffer dstBuf = encoderinputBuffers[inputBufIndex]; int sampleSize = extractor.readSampleData(dstBuf,0 /* offset */); long presentationTimeUs = 0; if (sampleSize < 0) { Log.d(TAG,"saw input EOS."); sawinputEOS = true; sampleSize = 0; } else { presentationTimeUs = extractor.getSampleTime(); } encoder.queueinputBuffer(inputBufIndex,0 /* offset */,sampleSize,presentationTimeUs,sawinputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0); if (!sawinputEOS) { extractor.advance(); } } } int res = encoder.dequeueOutputBuffer(info,kTimeOutUs); if (res >= 0) { int outputBufIndex = res; ByteBuffer buf = encoderOutputBuffers[outputBufIndex]; buf.position(info.offset); buf.limit(info.offset + info.size); if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONfig) != 0) { // create a decoder decoder = MediaCodec.createDecoderByType(mimeType); MediaFormat format = MediaFormat.createVIDeoFormat(mimeType,height); format.setInteger(MediaFormat.KEY_color_FORMAT,colorFormat); format.setByteBuffer("csd-0",buf); decoder.configure(format,surface /* surface */,0 /* flags */); decoder.start(); decoderinputBuffers = decoder.getinputBuffers(); decoderOutputBuffers = decoder.getoutputBuffers(); } else { int decIndex = decoder.dequeueinputBuffer(-1); decoderinputBuffers[decIndex].clear(); decoderinputBuffers[decIndex].put(buf); decoder.queueinputBuffer(decIndex,info.size,info.presentationTimeUs,info.flags); } encoder.releaSEOutputBuffer(outputBufIndex,false /* render */); } else if (res == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { encoderOutputBuffers = encoder.getoutputBuffers(); Log.d(TAG,"encoder output buffers have changed."); } else if (res == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { MediaFormat encformat = encoder.getoutputFormat(); Log.d(TAG,"encoder output format has changed to " + encformat); } if (decoder == null) res = MediaCodec.INFO_TRY_AGAIN_LATER; else res = decoder.dequeueOutputBuffer(info,kTimeOutUs); if (res >= 0) { int outputBufIndex = res; ByteBuffer buf = decoderOutputBuffers[outputBufIndex]; buf.position(info.offset); buf.limit(info.offset + info.size); // The worlds simplest FPS implementation while (info.presentationTimeUs / 1000 > System.currentTimeMillis() - startMs) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printstacktrace(); break; } } decoder.releaSEOutputBuffer(outputBufIndex,true /* render */); if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { Log.d(TAG,"saw output EOS."); sawOutputEOS = true; } } else if (res == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { decoderOutputBuffers = decoder.getoutputBuffers(); Log.d(TAG,"decoder output buffers have changed."); } else if (res == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { oformat = decoder.getoutputFormat(); Log.d(TAG,"decoder output format has changed to " + oformat); } } encoder.stop(); encoder.release(); decoder.stop(); decoder.release();}
我试图编码的文件来自AndroID cts Test Project:
R.raw.vIDeo_480x360_mp4_h264_1000kbps_30fps_aac_stereo_128kbps_44100hz
我猜这个问题与我在编码器MediaCodec中指定的格式参数有关,但我无法弄清楚什么是不正确/缺失.
解决方法 在您的程序中,存在设计问题.在循环while(!sawOutputEOS){你试图重新编码的地方,int inputBufIndex = encoder.dequeueinputBuffer(kTimeOutUs);
从编码器的输入/输入端口中取出一个缓冲区
ByteBuffer dstBuf = encoderinputBuffers[inputBufIndex];
指向出列缓冲区的缓冲区指针
int sampleSize = extractor.readSampleData(dstBuf,0 /* offset */);
出队缓冲区中填充了提取器中的数据.提取器的输出是压缩比特流.这不是YUV未压缩帧.
encoder.queueinputBuffer(inputBufIndex,....)
这里,压缩比特流被编码.由于这不是YUV帧,编码器将尽力执行压缩,因此,您会在编码器的输出处观察到绿色难以辨认的帧.我认为你在屏幕上观察到这一点,因为下面的部分代码解码相同的内容.即使编码器的输出被写入文件并通过不同的播放器或PC播放,也会观察到这种情况.
从程序中,我假设你的设计是Decode ==>编码==>您的图表应该是实时解码
MediaExtractor ==> MediaCodec (Decoder) ==> MediaCodec (Encoder) ==> MediaCodec (Decoder) ==> display
P.S:你在运行这个程序时是否观察到任何内存违规?
总结以上是内存溢出为你收集整理的使用Android MediaCodec以不同的比特率重新编码h.264内容全部内容,希望文章能够帮你解决使用Android MediaCodec以不同的比特率重新编码h.264内容所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)