Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/207.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/video/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android改变视频文件的分辨率_Android_Video_Encoding_Android Mediacodec - Fatal编程技术网

Android改变视频文件的分辨率

Android改变视频文件的分辨率,android,video,encoding,android-mediacodec,Android,Video,Encoding,Android Mediacodec,我正在尝试编写一个Android应用程序,可以拍摄给定的视频,并将其分辨率更改为给定的大小、比特率和音频采样率。我正在使用API级别18中提供的内置MediaCodec和MediaMuxer类,并且我非常关注BigFlake.com()中的示例,但是我在让它们顺利工作时遇到了一些困难 现在,我在尝试调用MediaCodec类上的dequeueInputBuffer时遇到了一个IllegalStateException。我知道这是一种包罗万象的例外,但我希望有人能看看我下面的代码,让我知道我哪里出

我正在尝试编写一个Android应用程序,可以拍摄给定的视频,并将其分辨率更改为给定的大小、比特率和音频采样率。我正在使用API级别18中提供的内置MediaCodec和MediaMuxer类,并且我非常关注BigFlake.com()中的示例,但是我在让它们顺利工作时遇到了一些困难

现在,我在尝试调用
MediaCodec
类上的
dequeueInputBuffer
时遇到了一个
IllegalStateException
。我知道这是一种包罗万象的例外,但我希望有人能看看我下面的代码,让我知道我哪里出错了

更新

结果表明,
dequeueInputBuffer
调用的问题就是解决方案。因为480 x 360不是16的倍数,
dequeueInputBuffer
抛出了
IllegalStateException
。将目标分辨率更改为512 x 288修复了该问题

现在,我遇到了queueInputBuffer方法调用的问题。这个电话给了我与以前完全相同的
非法状态异常
,但现在由于不同的原因

有趣的是,我已经看过BigFlake.com上的例子,甚至重新实现了它,但在这一行我仍然得到同样的例外。有人知道发生了什么事吗

顺便说一句,我已经删除了我的旧代码,并用我的最新版本更新了这篇文章

谢谢

package com.mikesappshop.videoconverter;

import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.media.MediaMuxer;
import android.util.Log;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;

/**
 * Created by mneill on 11/3/15.
 */

public class VideoConverter {

    // Interface

    public interface CompletionHandler {
        void videoEncodingDidComplete(Error error);
    }

    // Constants

    private static final String TAG = "VideoConverter";
    private static final boolean VERBOSE = true;           // lots of logging

    // parameters for the encoder
    private static final String MIME_TYPE = "video/avc";    // H.264 Advanced Video Coding
    private static final int FRAME_RATE = 15;               // 15fps
    private static final int CAPTURE_RATE = 15;               // 15fps
    private static final int IFRAME_INTERVAL = 10;          // 10 seconds between I-frames
    private static final int CHANNEL_COUNT = 1;
    private static final int SAMPLE_RATE = 128000;
    private static final int TIMEOUT_USEC = 10000;

    // size of a frame, in pixels
    private int mWidth = -1;
    private int mHeight = -1;

    // bit rate, in bits per second
    private int mBitRate = -1;

    // encoder / muxer state
    private MediaCodec mDecoder;
    private MediaCodec mEncoder;
    private MediaMuxer mMuxer;
    private int mTrackIndex;
    private boolean mMuxerStarted;

    /**
     * Starts encoding process
     */
    public void convertVideo(String mediaFilePath, String destinationFilePath, CompletionHandler handler) {

        // TODO: Make configurable
//        mWidth = 480;
//        mHeight = 360;
        mWidth = 512;
        mHeight = 288;
        mBitRate = 500000;

        try {

            if ((mWidth % 16) != 0 || (mHeight % 16) != 0) {
                Log.e(TAG, "Width or Height not multiple of 16");
                Error e = new Error("Width and height must be a multiple of 16");
                handler.videoEncodingDidComplete(e);
                return;
            }

            // prep the decoder and the encoder
            prepareEncoderDecoder(destinationFilePath);

            // load file
            File file = new File(mediaFilePath);
            byte[] fileData = readContentIntoByteArray(file);

            // fill up the input buffer
            fillInputBuffer(fileData);

            // encode buffer
            encode();

        } catch (Exception ex) {
            Log.e(TAG, ex.toString());
            ex.printStackTrace();

        } finally {

            // release encoder and muxer
            releaseEncoder();
        }
    }

    /**
     * Configures encoder and muxer state
     */

    private void prepareEncoderDecoder(String outputPath) throws Exception {

        // create decoder to read in the file data
        mDecoder = MediaCodec.createDecoderByType(MIME_TYPE);

        // create encoder to encode the file data into a new format
        MediaCodecInfo info = selectCodec(MIME_TYPE);
        int colorFormat = selectColorFormat(info, MIME_TYPE);

        MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, mWidth, mHeight);
        format.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
        format.setInteger(MediaFormat.KEY_BIT_RATE, mBitRate);
        format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE);
        format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);

        mEncoder = MediaCodec.createByCodecName(info.getName());
        mEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
        mEncoder.start();

        // Create a MediaMuxer for saving the data
        mMuxer = new MediaMuxer(outputPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);

        mTrackIndex = -1;
        mMuxerStarted = false;
    }

    /**
     * Releases encoder resources.  May be called after partial / failed initialization.
     */
    private void releaseEncoder() {

        if (VERBOSE) Log.d(TAG, "releasing encoder objects");

        if (mEncoder != null) {
            mEncoder.stop();
            mEncoder.release();
            mEncoder = null;
        }

        if (mMuxer != null) {
            mMuxer.stop();
            mMuxer.release();
            mMuxer = null;
        }
    }

    private void fillInputBuffer(byte[] data) {

        boolean inputDone = false;
        int processedDataSize = 0;
        int frameIndex = 0;

        Log.d(TAG, "[fillInputBuffer] Buffer load start");

        ByteBuffer[] inputBuffers = mEncoder.getInputBuffers();

        while (!inputDone) {

            int inputBufferIndex = mEncoder.dequeueInputBuffer(10000);
            if (inputBufferIndex >= 0) {

                if (processedDataSize >= data.length) {

                    mEncoder.queueInputBuffer(inputBufferIndex, 0, 0, computePresentationTime(frameIndex), MediaCodec.BUFFER_FLAG_END_OF_STREAM);
                    inputDone = true;
                    Log.d(TAG, "[fillInputBuffer] Buffer load complete");

                } else {

                    ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];

                    int limit = inputBuffer.capacity();
                    int pos = frameIndex * limit;
                    byte[] subData = new byte[limit];
                    System.arraycopy(data, pos, subData, 0, limit);

                    inputBuffer.clear();
                    inputBuffer.put(subData);

                    Log.d(TAG, "[encode] call queueInputBuffer");
                    mDecoder.queueInputBuffer(inputBufferIndex, 0, subData.length, computePresentationTime(frameIndex), MediaCodec.BUFFER_FLAG_CODEC_CONFIG);
                    Log.d(TAG, "[encode] did call queueInputBuffer");

                    Log.d(TAG, "[encode] Loaded frame " + frameIndex + " into buffer");

                    frameIndex++;
                }
            }
        }
    }

    private void encode() throws Exception {

        // get buffer info
        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();

        // start encoding
        ByteBuffer[] encoderOutputBuffers = mEncoder.getOutputBuffers();

        while (true) {

            int encoderStatus = mEncoder.dequeueOutputBuffer(bufferInfo, TIMEOUT_USEC);

            if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {

                // no output available yet
                if (VERBOSE) Log.d(TAG, "no output available, spinning to await EOS");
                break;

            } else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {

                // not expected for an encoder
                encoderOutputBuffers = mEncoder.getOutputBuffers();

            } else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {

                // should happen before receiving buffers, and should only happen once
                if (!mMuxerStarted) {

                    MediaFormat newFormat = mEncoder.getOutputFormat();
                    Log.d(TAG, "encoder output format changed: " + newFormat);

                    // now that we have the Magic Goodies, start the muxer
                    mTrackIndex = mMuxer.addTrack(newFormat);
                    mMuxer.start();
                    mMuxerStarted = true;
                }

            } else if (encoderStatus > 0) {

                ByteBuffer encodedData = encoderOutputBuffers[encoderStatus];

                if (encodedData == null) {
                    throw new RuntimeException("encoderOutputBuffer " + encoderStatus + " was null");
                }

                if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
                    if (VERBOSE) Log.d(TAG, "ignoring BUFFER_FLAG_CODEC_CONFIG");
                    bufferInfo.size = 0;
                }

                if (bufferInfo.size != 0) {

                    if (!mMuxerStarted) {
                        throw new RuntimeException("muxer hasn't started");
                    }

                    // adjust the ByteBuffer values to match BufferInfo (not needed?)
                    encodedData.position(bufferInfo.offset);
                    encodedData.limit(bufferInfo.offset + bufferInfo.size);

                    mMuxer.writeSampleData(mTrackIndex, encodedData, bufferInfo);
                    if (VERBOSE) Log.d(TAG, "sent " + bufferInfo.size + " bytes to muxer");
                }

                mEncoder.releaseOutputBuffer(encoderStatus, false);

                if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
                    if (VERBOSE) Log.d(TAG, "end of stream reached");
                    break;      // out of while
                }
            }
        }
    }

    private byte[] readContentIntoByteArray(File file) throws Exception
    {
        FileInputStream fileInputStream = null;
        byte[] bFile = new byte[(int) file.length()];

        //convert file into array of bytes
        fileInputStream = new FileInputStream(file);
        fileInputStream.read(bFile);
        fileInputStream.close();

        return bFile;
    }

    /**
     * Returns the first codec capable of encoding the specified MIME type, or null if no
     * match was found.
     */
    private static MediaCodecInfo selectCodec(String mimeType) {
        int numCodecs = MediaCodecList.getCodecCount();
        for (int i = 0; i < numCodecs; i++) {
            MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
            if (!codecInfo.isEncoder()) {
                continue;
            }
            String[] types = codecInfo.getSupportedTypes();
            for (int j = 0; j < types.length; j++) {
                if (types[j].equalsIgnoreCase(mimeType)) {
                    return codecInfo;
                }
            }
        }
        return null;
    }

    private static int selectColorFormat(MediaCodecInfo codecInfo, String mimeType) {
        MediaCodecInfo.CodecCapabilities capabilities = codecInfo.getCapabilitiesForType(mimeType);
        for (int i = 0; i < capabilities.colorFormats.length; i++) {
            int colorFormat = capabilities.colorFormats[i];
            if (isRecognizedFormat(colorFormat)) {
                return colorFormat;
            }
        }

        return 0;   // not reached
    }

    private static boolean isRecognizedFormat(int colorFormat) {
        switch (colorFormat) {
            // these are the formats we know how to handle for this test
            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:
                return true;
            default:
                return false;
        }
    }

    /**
     * Generates the presentation time for frame N, in microseconds.
     */
    private static long computePresentationTime(int frameIndex) {
        return 132 + frameIndex * 1000000 / FRAME_RATE;
    }
}
package com.mikesappshop.videoconverter;
导入android.media.MediaCodec;
导入android.media.mediacodeinfo;
导入android.media.mediacodelist;
导入android.media.MediaExtractor;
导入android.media.MediaFormat;
导入android.media.MediaMuxer;
导入android.util.Log;
导入java.io.File;
导入java.io.FileInputStream;
导入java.io.FileOutputStream;
导入java.io.IOException;
导入java.nio.ByteBuffer;
/**
*由mneill于2015年11月3日创建。
*/
公共级视频转换器{
//接口
公共接口完成处理程序{
无效视频编码未完成(错误);
}
//常数
私有静态最终字符串标记=“视频转换器”;
private static final boolean VERBOSE=true;//大量日志记录
//编码器的参数
私有静态最终字符串MIME_TYPE=“video/avc”//H.264高级视频编码
私有静态最终整数帧_速率=15;//15fps
私有静态最终整数捕获速率=15;//15fps
私有静态final int-IFRAME_INTERVAL=10;//I帧之间的间隔为10秒
专用静态最终整数通道计数=1;
私有静态最终整数抽样率=128000;
私有静态最终整数超时_USEC=10000;
//帧的大小,以像素为单位
私有整数mWidth=-1;
私有整数mHeight=-1;
//比特率,以比特/秒为单位
私有int-mBitRate=-1;
//编码器/多路复用器状态
专用媒体编解码器;
专用媒体编解码器;
私有媒体muxer-mMuxer;
私人指数;
私有布尔值mMuxerStarted;
/**
*开始编码过程
*/
public void convertVideo(字符串mediaFilePath、字符串destinationFilePath、CompletionHandler){
//TODO:使可配置
//mWidth=480;
//mHeight=360;
mWidth=512;
mHeight=288;
mBitRate=500000;
试一试{
如果((mWidth%16)!=0 | |(mHeight%16)!=0){
Log.e(标签“宽度或高度不是16的倍数”);
错误e=新错误(“宽度和高度必须是16的倍数”);
处理程序。视频编码完成(e);
返回;
}
//准备解码器和编码器
prepareencoder(destinationFilePath);
//加载文件
文件文件=新文件(mediaFilePath);
字节[]文件数据=readContentIntoByteArray(文件);
//填充输入缓冲区
fillInputBuffer(文件数据);
//编码缓冲区
编码();
}捕获(例外情况除外){
Log.e(TAG,例如toString());
例如printStackTrace();
}最后{
//释放编码器和多路复用器
释放编码器();
}
}
/**
*配置编码器和多路复用器状态
*/
私有void prepareencoder(字符串输出路径)引发异常{
//创建解码器以读取文件数据
mDecoder=MediaCodec.createDecoderByType(MIME_类型);
//创建编码器以将文件数据编码为新格式
MediaCodecInfo=selectCodec(MIME_类型);
int colorFormat=选择colorFormat(信息、MIME类型);
MediaFormat=MediaFormat.createVideoFormat(MIME_类型,mWidth,mHeight);
format.setInteger(MediaFormat.KEY\u COLOR\u format,colorFormat);
format.setInteger(MediaFormat.KEY\u BIT\u RATE,mBitRate);
format.setInteger(MediaFormat.KEY\u FRAME\u RATE,FRAME\u RATE);
format.setInteger(MediaFormat.KEY\u I\u FRAME\u INTERVAL、IFRAME\u INTERVAL);
mEncoder=MediaCodec.createByCodecName(info.getName());
配置(格式、空、空、MediaCodec.configure\u FLAG\u ENCODE);
mEncoder.start();
//创建用于保存数据的MediaMuxer
mMuxer=newmediamuxer(outputPath,MediaMuxer.OutputFormat.MUXER\u OUTPUT\u MPEG\u 4);
mTrackIndex=-1;
mMuxerStarted=false;
}
/**
*释放编码器资源。可在部分/失败初始化后调用。
*/
私有void releaseEncoder(){
if(VERBOSE)Log.d(标记“释放编码器对象”);
if(mEncoder!=null){
门命令停止();
门命令释放();
mEncoder=null;
}
如果(mMuxer!=null){
mMuxer.stop();
mMuxer.release();
mMuxer=null;
}
}
专用void fillInputBuffer(字节[]da
MediaCodecInfo info = selectCodec(MIME_TYPE);
int colorFormat = selectColorFormat(info, MIME_TYPE);
mEncoder = MediaCodec.createEncoderByType(MIME_TYPE);
mEncoder = MediaCodec.createByCodecName(info.getName());