使用Android MediaCodec以不同的比特率重新编码h.264内容

使用Android MediaCodec以不同的比特率重新编码h.264内容,第1张

概述我正在尝试使用4.2中引入的 Android MediaCodec API重新编码具有不同比特率的h.264 mp4文件. 我能够使用MediaCodec API解码和播放内容(在更改比特率之前),但如果我在解码之前尝试使用不同的比特率对内容进行重新编码,则会出现乱码(绿屏灰色)像素化). 我使用的代码基于Android测试用例android.media.cts.DecoderTest Andro 我正在尝试使用4.2中引入的 Android MediaCodec API重新编码具有不同比特率的h.264 mp4文件.

我能够使用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内容所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1126879.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-30
下一篇 2022-05-30

发表评论

登录后才能评论

评论列表(0条)

保存