使用Telegram API旋转视频问题进行视频压缩

时间:2017-10-31 06:57:44

标签: android video compression

我正在尝试压缩视频。 如果视频处于横向模式,则代码可以正常工作,但如果视频处于纵向模式,则可以旋转到横向。 我的代码:

public File convertVideo(String path) {
    MediaMetadataRetriever retriever = new MediaMetadataRetriever();
    try {
        FileInputStream inputStream = new FileInputStream(path);

        retriever.setDataSource(path);

    }
    catch (Exception e){
        e.printStackTrace();
    }


    String width = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
    String height = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
    String rotation = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);

    long startTime = -1;
    long endTime = -1;

    int resultWidth = 640;
    int resultHeight = 360;

    int maxPortWidth = 360;
    int maxPortHeight = 640;

    int maxLandWidth = 640;
    int maxLandHeight = 360;

    float imgRatio;
    float maxRatio;


    int rotationValue = Integer.valueOf(rotation);
    int originalWidth = Integer.valueOf(width);
    int originalHeight = Integer.valueOf(height);


    int bitrate = 921600;
    int rotateRender = 0;

    File folder = new File(Environment.getExternalStorageDirectory() +  File.separator
            + Config.VIDEO_COMPRESSOR_APPLICATION_DIR_NAME);
    boolean isDirExist = false;
    if (!folder.exists()) {
        isDirExist = folder.mkdir();
    }
    isDirExist = false;
    folder = new File(Environment.getExternalStorageDirectory() +  File.separator
            + Config.VIDEO_COMPRESSOR_APPLICATION_DIR_NAME+ Config.VIDEO_COMPRESSOR_COMPRESSED_VIDEOS_DIR);
    if (!folder.exists()) {
        isDirExist = folder.mkdir();
    }

    File cacheFile = new File(
            Environment.getExternalStorageDirectory()
                    + File.separator
                    + Config.VIDEO_COMPRESSOR_APPLICATION_DIR_NAME
                    + Config.VIDEO_COMPRESSOR_COMPRESSED_VIDEOS_DIR,
            "VIDEO_" + new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date()) + ".mp4"
    );

    if(rotation.equals("90") || rotation.equals("270")) {

        imgRatio = originalWidth / originalHeight;
        maxRatio = maxPortWidth / maxPortHeight;
        if (originalHeight > maxPortHeight || originalWidth > maxPortWidth) {
            if (imgRatio < maxRatio) {
                imgRatio = maxPortHeight / originalHeight;
                resultWidth = (int) (imgRatio * originalWidth);
                resultHeight = (int) maxPortHeight;
            } else if (imgRatio > maxRatio) {
                imgRatio = maxPortWidth / originalWidth;
                resultHeight = (int) (imgRatio * originalHeight);
                resultWidth = (int) maxPortWidth;
            } else {
                resultHeight = (int) maxPortHeight;
                resultWidth = (int) maxPortWidth;

            }
        }           

    } else {

        imgRatio = originalWidth / originalHeight;
        maxRatio = maxLandWidth / maxLandHeight;
        if (originalHeight > maxLandHeight || originalWidth > maxLandWidth) {
            if (imgRatio!=0.0 && (imgRatio < maxRatio)) {
                imgRatio = maxLandHeight / originalHeight;
                resultWidth = (int) (imgRatio * originalWidth);
                resultHeight = (int) maxLandHeight;
            } else if (imgRatio!=0.0 && (imgRatio > maxRatio)) {
                imgRatio = maxLandWidth / originalWidth;
                resultHeight = (int) (imgRatio * originalHeight);
                resultWidth = (int) maxLandWidth;
            } else {
                resultHeight = (int) maxLandHeight;
                resultWidth = (int) maxLandWidth;

            }
        }
    }
    if (Build.VERSION.SDK_INT < 18 && resultHeight > resultWidth && resultWidth != originalWidth && resultHeight != originalHeight) {
        int temp = resultHeight;
        resultHeight = resultWidth;
        resultWidth = temp;
        rotationValue = 90;
        rotateRender = 270;
    } else if (Build.VERSION.SDK_INT > 20) {
        if(rotationValue == 0) {

            rotateRender = 0;
        } else if (rotationValue == 90) {
            int temp = resultHeight;
            resultHeight = resultWidth;
            resultWidth = temp;
            rotationValue = 0;
            rotateRender = 270;
        } else if (rotationValue == 180) {
            rotateRender = 180;
            rotationValue = 0;
        } else if (rotationValue == 270) {
            int temp = resultHeight;
            resultHeight = resultWidth;
            resultWidth = temp;
            rotationValue = 0;
            rotateRender = 90;
        }
    }
    File inputFile = new File(path);
    if (!inputFile.canRead()) {
        didWriteData(true, true);
        return null;
    } else {
    }

    videoConvertFirstWrite = true;
    boolean error = false;
    long videoStartTime = startTime;
    long time = System.currentTimeMillis();
    if (resultWidth != 0 && resultHeight != 0) {
        MP4Builder mediaMuxer = null;
        MediaExtractor extractor = null;

        try {
            MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
            Mp4Movie movie = new Mp4Movie();
            movie.setCacheFile(cacheFile);
            movie.setRotation(rotationValue);
            movie.setSize(resultWidth, resultHeight);
            mediaMuxer = new MP4Builder().createMovie(movie);
            extractor = new MediaExtractor();
            extractor.setDataSource(inputFile.toString());


            if (resultWidth != originalWidth || resultHeight != originalHeight) {
                int videoIndex;
                videoIndex = selectTrack(extractor, false);

                if (videoIndex >= 0) {
                    MediaCodec decoder = null;
                    MediaCodec encoder = null;
                    InputSurface inputSurface = null;
                    OutputSurface outputSurface = null;
                    try {
                        long videoTime = -1;
                        boolean outputDone = false;
                        boolean inputDone = false;
                        boolean decoderDone = false;
                        int swapUV = 0;
                        int videoTrackIndex = -5;

                        int colorFormat;
                        int processorType = PROCESSOR_TYPE_OTHER;
                        String manufacturer = Build.MANUFACTURER.toLowerCase();
                        if (Build.VERSION.SDK_INT < 18) {
                            MediaCodecInfo codecInfo = selectCodec(MIME_TYPE);
                            colorFormat = selectColorFormat(codecInfo, MIME_TYPE);
                            if (colorFormat == 0) {
                                throw new RuntimeException("no supported color format");
                            }
                            String codecName = codecInfo.getName();
                            if (codecName.contains("OMX.qcom.")) {
                                processorType = PROCESSOR_TYPE_QCOM;
                                if (Build.VERSION.SDK_INT == 16) {
                                    if (manufacturer.equals("lge") || manufacturer.equals("nokia")) {
                                        swapUV = 1;
                                    }
                                }
                            } else if (codecName.contains("OMX.Intel.")) {
                                processorType = PROCESSOR_TYPE_INTEL;
                            } else if (codecName.equals("OMX.MTK.VIDEO.ENCODER.AVC")) {
                                processorType = PROCESSOR_TYPE_MTK;
                            } else if (codecName.equals("OMX.SEC.AVC.Encoder")) {
                                processorType = PROCESSOR_TYPE_SEC;
                                swapUV = 1;
                            } else if (codecName.equals("OMX.TI.DUCATI1.VIDEO.H264E")) {
                                processorType = PROCESSOR_TYPE_TI;
                            }
                            Log.e("tmessages", "codec = " + codecInfo.getName() + " manufacturer = " + manufacturer + "device = " + Build.MODEL);
                        } else {
                            colorFormat = MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface;
                        }


                        int resultHeightAligned = resultHeight;
                        int padding = 0;
                        int bufferSize = resultWidth * resultHeight * 3 / 2;
                        if (processorType == PROCESSOR_TYPE_OTHER) {
                            if (resultHeight % 16 != 0) {
                                resultHeightAligned += (16 - (resultHeight % 16));
                                padding = resultWidth * (resultHeightAligned - resultHeight);
                                bufferSize += padding * 5 / 4;
                            }
                        } else if (processorType == PROCESSOR_TYPE_QCOM) {
                            if (!manufacturer.toLowerCase().equals("lge")) {
                                int uvoffset = (resultWidth * resultHeight + 2047) & ~2047;
                                padding = uvoffset - (resultWidth * resultHeight);
                                bufferSize += padding;
                            }
                        } else if (processorType == PROCESSOR_TYPE_TI) {

                        } else if (processorType == PROCESSOR_TYPE_MTK) {
                            if (manufacturer.equals("baidu")) {
                                resultHeightAligned += (16 - (resultHeight % 16));
                                padding = resultWidth * (resultHeightAligned - resultHeight);
                                bufferSize += padding * 5 / 4;
                            }
                        }

                        extractor.selectTrack(videoIndex);
                        if (startTime > 0) {
                            extractor.seekTo(startTime, MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
                        } else {
                            extractor.seekTo(0, MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
                        }
                        MediaFormat inputFormat = extractor.getTrackFormat(videoIndex);

                        MediaFormat outputFormat = MediaFormat.createVideoFormat(MIME_TYPE, resultWidth, resultHeight);
                        outputFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
                        outputFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate != 0 ? bitrate : 921600);
                        outputFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 25);
                        outputFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10);
                        if (Build.VERSION.SDK_INT < 18) {
                            outputFormat.setInteger("stride", resultWidth + 32);
                            outputFormat.setInteger("slice-height", resultHeight);
                        }

                        encoder = MediaCodec.createEncoderByType(MIME_TYPE);
                        encoder.configure(outputFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
                        if (Build.VERSION.SDK_INT >= 18) {
                            inputSurface = new InputSurface(encoder.createInputSurface());
                            inputSurface.makeCurrent();
                        }
                        encoder.start();

                        decoder = MediaCodec.createDecoderByType(inputFormat.getString(MediaFormat.KEY_MIME));
                        if (Build.VERSION.SDK_INT >= 18) {
                            outputSurface = new OutputSurface();
                        } else {
                            outputSurface = new OutputSurface(resultWidth, resultHeight, rotateRender);
                        }
                        decoder.configure(inputFormat, outputSurface.getSurface(), null, 0);
                        decoder.start();

                        final int TIMEOUT_USEC = 2500;
                        ByteBuffer[] decoderInputBuffers = null;
                        ByteBuffer[] encoderOutputBuffers = null;
                        ByteBuffer[] encoderInputBuffers = null;
                        if (Build.VERSION.SDK_INT < 21) {
                            decoderInputBuffers = decoder.getInputBuffers();
                            encoderOutputBuffers = encoder.getOutputBuffers();
                            if (Build.VERSION.SDK_INT < 18) {
                                encoderInputBuffers = encoder.getInputBuffers();
                            }
                        }

                        while (!outputDone) {
                            if (!inputDone) {
                                boolean eof = false;
                                int index = extractor.getSampleTrackIndex();
                                if (index == videoIndex) {
                                    int inputBufIndex = decoder.dequeueInputBuffer(TIMEOUT_USEC);
                                    if (inputBufIndex >= 0) {
                                        ByteBuffer inputBuf;
                                        if (Build.VERSION.SDK_INT < 21) {
                                            inputBuf = decoderInputBuffers[inputBufIndex];
                                        } else {
                                            inputBuf = decoder.getInputBuffer(inputBufIndex);
                                        }
                                        int chunkSize = extractor.readSampleData(inputBuf, 0);
                                        if (chunkSize < 0) {
                                            decoder.queueInputBuffer(inputBufIndex, 0, 0, 0L, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
                                            inputDone = true;
                                        } else {
                                            decoder.queueInputBuffer(inputBufIndex, 0, chunkSize, extractor.getSampleTime(), 0);
                                            extractor.advance();
                                        }
                                    }
                                } else if (index == -1) {
                                    eof = true;
                                }
                                if (eof) {
                                    int inputBufIndex = decoder.dequeueInputBuffer(TIMEOUT_USEC);
                                    if (inputBufIndex >= 0) {
                                        decoder.queueInputBuffer(inputBufIndex, 0, 0, 0L, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
                                        inputDone = true;
                                    }
                                }
                            }

                            boolean decoderOutputAvailable = !decoderDone;
                            boolean encoderOutputAvailable = true;
                            while (decoderOutputAvailable || encoderOutputAvailable) {
                                int encoderStatus = encoder.dequeueOutputBuffer(info, TIMEOUT_USEC);
                                if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
                                    encoderOutputAvailable = false;
                                } else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
                                    if (Build.VERSION.SDK_INT < 21) {
                                        encoderOutputBuffers = encoder.getOutputBuffers();
                                    }
                                } else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
                                    MediaFormat newFormat = encoder.getOutputFormat();
                                    if (videoTrackIndex == -5) {
                                        videoTrackIndex = mediaMuxer.addTrack(newFormat, false);
                                    }
                                } else if (encoderStatus < 0) {
                                    throw new RuntimeException("unexpected result from encoder.dequeueOutputBuffer: " + encoderStatus);
                                } else {
                                    ByteBuffer encodedData;
                                    if (Build.VERSION.SDK_INT < 21) {
                                        encodedData = encoderOutputBuffers[encoderStatus];
                                    } else {
                                        encodedData = encoder.getOutputBuffer(encoderStatus);
                                    }
                                    if (encodedData == null) {
                                        throw new RuntimeException("encoderOutputBuffer " + encoderStatus + " was null");
                                    }
                                    if (info.size > 1) {
                                        if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
                                            if (mediaMuxer.writeSampleData(videoTrackIndex, encodedData, info, false)) {
                                                didWriteData(false, false);
                                            }
                                        } else if (videoTrackIndex == -5) {
                                            byte[] csd = new byte[info.size];
                                            encodedData.limit(info.offset + info.size);
                                            encodedData.position(info.offset);
                                            encodedData.get(csd);
                                            ByteBuffer sps = null;
                                            ByteBuffer pps = null;
                                            for (int a = info.size - 1; a >= 0; a--) {
                                                if (a > 3) {
                                                    if (csd[a] == 1 && csd[a - 1] == 0 && csd[a - 2] == 0 && csd[a - 3] == 0) {
                                                        sps = ByteBuffer.allocate(a - 3);
                                                        pps = ByteBuffer.allocate(info.size - (a - 3));
                                                        sps.put(csd, 0, a - 3).position(0);
                                                        pps.put(csd, a - 3, info.size - (a - 3)).position(0);
                                                        break;
                                                    }
                                                } else {
                                                    break;
                                                }
                                            }

                                            MediaFormat newFormat = MediaFormat.createVideoFormat(MIME_TYPE, resultWidth, resultHeight);
                                            if (sps != null && pps != null) {
                                                newFormat.setByteBuffer("csd-0", sps);
                                                newFormat.setByteBuffer("csd-1", pps);
                                            }
                                            videoTrackIndex = mediaMuxer.addTrack(newFormat, false);
                                        }
                                    }
                                    outputDone = (info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
                                    encoder.releaseOutputBuffer(encoderStatus, false);
                                }
                                if (encoderStatus != MediaCodec.INFO_TRY_AGAIN_LATER) {
                                    continue;
                                }

                                if (!decoderDone) {
                                    int decoderStatus = decoder.dequeueOutputBuffer(info, TIMEOUT_USEC);
                                    if (decoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
                                        decoderOutputAvailable = false;
                                    } else if (decoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {

                                    } else if (decoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
                                        MediaFormat newFormat = decoder.getOutputFormat();

                                    } else if (decoderStatus < 0) {
                                        throw new RuntimeException("unexpected result from decoder.dequeueOutputBuffer: " + decoderStatus);
                                    } else {
                                        boolean doRender;
                                        if (Build.VERSION.SDK_INT >= 18) {
                                            doRender = info.size != 0;
                                        } else {
                                            doRender = info.size != 0 || info.presentationTimeUs != 0;
                                        }
                                        if (endTime > 0 && info.presentationTimeUs >= endTime) {
                                            inputDone = true;
                                            decoderDone = true;
                                            doRender = false;
                                            info.flags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
                                        }
                                        if (startTime > 0 && videoTime == -1) {
                                            if (info.presentationTimeUs < startTime) {
                                                doRender = false;

                                            } else {
                                                videoTime = info.presentationTimeUs;
                                            }
                                        }
                                        decoder.releaseOutputBuffer(decoderStatus, doRender);
                                        if (doRender) {
                                            boolean errorWait = false;
                                            try {
                                                outputSurface.awaitNewImage();
                                            } catch (Exception e) {
                                                errorWait = true;

                                            }
                                            if (!errorWait) {
                                                if (Build.VERSION.SDK_INT >= 18) {
                                                    outputSurface.drawImage(false);
                                                    inputSurface.setPresentationTime(info.presentationTimeUs * 1000);
                                                    inputSurface.swapBuffers();
                                                } else {
                                                    int inputBufIndex = encoder.dequeueInputBuffer(TIMEOUT_USEC);
                                                    if (inputBufIndex >= 0) {
                                                        outputSurface.drawImage(true);
                                                        ByteBuffer rgbBuf = outputSurface.getFrame();
                                                        ByteBuffer yuvBuf = encoderInputBuffers[inputBufIndex];
                                                        yuvBuf.clear();
                                                        convertVideoFrame(rgbBuf, yuvBuf, colorFormat, resultWidth, resultHeight, padding, swapUV);
                                                        encoder.queueInputBuffer(inputBufIndex, 0, bufferSize, info.presentationTimeUs, 0);
                                                    } else {

                                                    }
                                                }
                                            }
                                        }
                                        if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
                                            decoderOutputAvailable = false;

                                            if (Build.VERSION.SDK_INT >= 18) {
                                                encoder.signalEndOfInputStream();
                                            } else {
                                                int inputBufIndex = encoder.dequeueInputBuffer(TIMEOUT_USEC);
                                                if (inputBufIndex >= 0) {
                                                    encoder.queueInputBuffer(inputBufIndex, 0, 1, info.presentationTimeUs, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        if (videoTime != -1) {
                            videoStartTime = videoTime;
                        }
                    } catch (Exception e) {

                        error = true;
                    }

                    extractor.unselectTrack(videoIndex);

                    if (outputSurface != null) {
                        outputSurface.release();
                    }
                    if (inputSurface != null) {
                        inputSurface.release();
                    }
                    if (decoder != null) {
                        decoder.stop();
                        decoder.release();
                    }
                    if (encoder != null) {
                        encoder.stop();
                        encoder.release();
                    }
                }
            } else {
                long videoTime = readAndWriteTrack(extractor, mediaMuxer, info, startTime, endTime, cacheFile, false);

                if (videoTime != -1) {
                    videoStartTime = videoTime;
                }
            }
            if (!error) {
                readAndWriteTrack(extractor, mediaMuxer, info, videoStartTime, endTime, cacheFile, true);
            }
        } catch (Exception e) {
            error = true;

            e.printStackTrace();

        } finally {
            if (extractor != null) {
                extractor.release();
            }
            if (mediaMuxer != null) {
                try {
                    mediaMuxer.finishMovie(false);
                } catch (Exception e) {


                }
            }

        }
    } else {
        didWriteData(true, true);
        return null;
    }
    didWriteData(true, error);

    return cacheFile;
}

Telegram App视频压缩 https://github.com/lalongooo/VideoCompressor/blob/master/app/src/main/java/com/lalongooo/videocompressor/video/MediaController.java

2 个答案:

答案 0 :(得分:0)

解决

在调用压缩函数之前简单地说明条件。使用MediaMetaDataRetriever检查选定的视频高度和宽度,并设置if condition.For 1:1 ratio video,它也会转换为640x360。因此,尝试在压缩之前获得宽度和高度,并将逻辑用于压缩或不压缩。

public void compress() {

Log.w("VideoMessage","eNTERED : "+inputPath);
lMediaMetadataRetriever.setDataSource(inputPath);
String lVideoWidth = lMediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
Log.w("VideoMessage","VideoWidth: "+lVideoWidth);
String lVideoHeight = lMediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
Log.w("VideoMessage","VideoHeight: "+lVideoHeight);
if(Integer.valueOf(lVideoWidth)<=640 || Integer.valueOf(lVideoHeight)<=360){
    Toast.makeText(this, "Video Already in compressed form", Toast.LENGTH_SHORT).show();
}
else{
    try2CreateCompressDir();
    outPath=Environment.getExternalStorageDirectory()
            + File.separator
            + APP_DIR
            + COMPRESSED_VIDEOS_DIR
            +"VIDEO_" + new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date()) + ".mp4";

    new VideoCompressor.execute(inputPath,outPath);

}

}

答案 1 :(得分:0)

当源视频和转换后的视频分辨率相同时,播放视频的MediaController代码存在问题。为了获得正确的视频转换,您必须指定转换的宽度/高度,它与源视频宽度/高度不匹配。