YUV视频流生成转成jpg图片

android9系统

相机Camera类的PreviewCallback回调中,这个接口回调的是相机的预览图片,是YUV格式的数据,这是,利用YuvImage对象的compressToJpeg方法生成Jpeg格式的图片保存在本地。

主要参数解析

new YuvImage(data, ImageFormat.NV21, width, height, null);

format:压缩格式,目前仅支持ImageFormat.NV21与ImageFormat.YUY2两个格式。
width:YuvImage的宽度
height:YuvImage的宽度
strides:(可选)每个图像平面的行字节。 如果YUV数据包含Padding,必须为每一个图像给一定的幅度,如果strides属性为null,该方法假设没有padding,并且根据格式和宽度自身派生行字节。
 

image.compressToJpeg(new Rect(0, 0, width, height), 100, stream)

1) rectangle :要压缩的矩形区域

2) quality :压缩范围,0-100,其中,0表示低质量的压缩,100表示高质量的压缩

3) stream :压缩数据

案例

byte[] mdata = new byte[width * height * 3 / 2];
if(isShoot){
       //获取视频流 可能需要通过 byte[] mdata = mByteBuffer.array()  跟据各自数据来源获取
        isShoot = false;
        //保存图片的地址对象
        File file = new File(Environment.getExternalStorageDirectory().getPath()+ File.separator+ "DCIM"+ File.separator+System.currentTimeMillis()+".jpg");
        //本次设备为width*height 1280x720
        yuv2Picture(mdata,  width, height,file);
    }
    

   
    /**
     *
     * @param data  yuv数据
     * @param width  宽
     * @param height 高
     * @param targetFile  图片保存地址
     */
   public static void yuv2Picture(byte[] data, int width, int height,File targetFile) {
        FileOutputStream stream = null;
        try {
            android.graphics.YuvImage image = new android.graphics.YuvImage(data, android.graphics.ImageFormat.NV21, width, height, null);
            stream = new FileOutputStream(targetFile);
            if (image.compressToJpeg(new Rect(0, 0, width, height), 100, stream)) {
                stream.flush();
            }
        } catch (Exception e) {
            Log.e(TAG, e.toString(),e);
        }finally {
            if(stream!=null){
                try {
                    stream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

YuvImage原码

路径:frameworks\base\graphics\java\android\graphics\YuvImage.java

/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.graphics;

import java.io.OutputStream;

/**
 * YuvImage contains YUV data and provides a method that compresses a region of
 * the YUV data to a Jpeg. The YUV data should be provided as a single byte
 * array irrespective of the number of image planes in it.
 * Currently only ImageFormat.NV21 and ImageFormat.YUY2 are supported.
 *
 * To compress a rectangle region in the YUV data, users have to specify the
 * region by left, top, width and height.
 */
public class YuvImage {

    /**
     * Number of bytes of temp storage we use for communicating between the
     * native compressor and the java OutputStream.
     */
    private final static int WORKING_COMPRESS_STORAGE = 4096;

   /**
     * The YUV format as defined in {@link ImageFormat}.
     */
    private int mFormat;

    /**
     * The raw YUV data.
     * In the case of more than one image plane, the image planes must be
     * concatenated into a single byte array.
     */
    private byte[] mData;

    /**
     * The number of row bytes in each image plane.
     */
    private int[] mStrides;

    /**
     * The width of the image.
     */
    private int mWidth;

    /**
     * The height of the the image.
     */
    private int mHeight;

    /**
     * Construct an YuvImage.
     *
     * @param yuv     The YUV data. In the case of more than one image plane, all the planes must be
     *                concatenated into a single byte array.
     * @param format  The YUV data format as defined in {@link ImageFormat}.
     * @param width   The width of the YuvImage.
     * @param height  The height of the YuvImage.
     * @param strides (Optional) Row bytes of each image plane. If yuv contains padding, the stride
     *                of each image must be provided. If strides is null, the method assumes no
     *                padding and derives the row bytes by format and width itself.
     * @throws IllegalArgumentException if format is not support; width or height <= 0; or yuv is
     *                null.
     */
    public YuvImage(byte[] yuv, int format, int width, int height, int[] strides) {
        if (format != ImageFormat.NV21 &&
                format != ImageFormat.YUY2) {
            throw new IllegalArgumentException(
                    "only support ImageFormat.NV21 " +
                    "and ImageFormat.YUY2 for now");
        }

        if (width <= 0  || height <= 0) {
            throw new IllegalArgumentException(
                    "width and height must large than 0");
        }

        if (yuv == null) {
            throw new IllegalArgumentException("yuv cannot be null");
        }

        if (strides == null) {
            mStrides = calculateStrides(width, format);
        } else {
            mStrides = strides;
        }

        mData = yuv;
        mFormat = format;
        mWidth = width;
        mHeight = height;
    }

    /**
     * Compress a rectangle region in the YuvImage to a jpeg.
     * Only ImageFormat.NV21 and ImageFormat.YUY2
     * are supported for now.
     *
     * @param rectangle The rectangle region to be compressed. The medthod checks if rectangle is
     *                  inside the image. Also, the method modifies rectangle if the chroma pixels
     *                  in it are not matched with the luma pixels in it.
     * @param quality   Hint to the compressor, 0-100. 0 meaning compress for
     *                  small size, 100 meaning compress for max quality.
     * @param stream    OutputStream to write the compressed data.
     * @return          True if the compression is successful.
     * @throws IllegalArgumentException if rectangle is invalid; quality is not within [0,
     *                  100]; or stream is null.
     */
    public boolean compressToJpeg(Rect rectangle, int quality, OutputStream stream) {
        Rect wholeImage = new Rect(0, 0, mWidth, mHeight);
        if (!wholeImage.contains(rectangle)) {
            throw new IllegalArgumentException(
                    "rectangle is not inside the image");
        }

        if (quality < 0 || quality > 100) {
            throw new IllegalArgumentException("quality must be 0..100");
        }

        if (stream == null) {
            throw new IllegalArgumentException("stream cannot be null");
        }

        adjustRectangle(rectangle);
        int[] offsets = calculateOffsets(rectangle.left, rectangle.top);

        return nativeCompressToJpeg(mData, mFormat, rectangle.width(),
                rectangle.height(), offsets, mStrides, quality, stream,
                new byte[WORKING_COMPRESS_STORAGE]);
    }


   /**
     * @return the YUV data.
     */
    public byte[] getYuvData() {
        return mData;
    }

    /**
     * @return the YUV format as defined in {@link ImageFormat}.
     */
    public int getYuvFormat() {
        return mFormat;
    }

    /**
     * @return the number of row bytes in each image plane.
     */
    public int[] getStrides() {
        return mStrides;
    }

    /**
     * @return the width of the image.
     */
    public int getWidth() {
        return mWidth;
    }

    /**
     * @return the height of the image.
     */
    public int getHeight() {
        return mHeight;
    }

    int[] calculateOffsets(int left, int top) {
        int[] offsets = null;
        if (mFormat == ImageFormat.NV21) {
            offsets = new int[] {top * mStrides[0] + left,
                  mHeight * mStrides[0] + top / 2 * mStrides[1]
                  + left / 2 * 2 };
            return offsets;
        }

        if (mFormat == ImageFormat.YUY2) {
            offsets = new int[] {top * mStrides[0] + left / 2 * 4};
            return offsets;
        }

        return offsets;
    }

    private int[] calculateStrides(int width, int format) {
        int[] strides = null;
        if (format == ImageFormat.NV21) {
            strides = new int[] {width, width};
            return strides;
        }

        if (format == ImageFormat.YUY2) {
            strides = new int[] {width * 2};
            return strides;
        }

        return strides;
    }

   private void adjustRectangle(Rect rect) {
       int width = rect.width();
       int height = rect.height();
       if (mFormat == ImageFormat.NV21) {
           // Make sure left, top, width and height are all even.
           width &= ~1;
           height &= ~1;
           rect.left &= ~1;
           rect.top &= ~1;
           rect.right = rect.left + width;
           rect.bottom = rect.top + height;
        }

        if (mFormat == ImageFormat.YUY2) {
            // Make sure left and width are both even.
            width &= ~1;
            rect.left &= ~1;
            rect.right = rect.left + width;
        }
    }

     native methods

    private static native boolean nativeCompressToJpeg(byte[] oriYuv,
            int format, int width, int height, int[] offsets, int[] strides,
            int quality, OutputStream stream, byte[] tempStorage);
}

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
本课程详细、全面地介绍了 Qt 开发中的各个技术细节,并且额外赠送在嵌入式端编写Qt程序的技巧。整个课程涵盖知识点非常多,知识模块囊括 Qt-Core 组件、QWidgets、多媒体、网络、绘图、数据库,超过200个 C++ 类的分析和使用,学完之后将拥有 Qt 图形界面开发的非常坚实的功底。 每个知识点不仅仅会通过视频讲解清楚,并且会配以精心安排的实验和作业,用来保证学习过程中切实掌握核心技术和概念,通过实验来巩固,通过实验来检验,实验与作业的目的是发现问题,发现技术盲点,通过答疑和沟通夯实技术技能。注意:本套视频教程来源于线下的实体班级,因此视频中有少量场景对话和学生问答,对此比较介意的亲们谨慎购买。注意:本套视频教程包含大量课堂源码,包含对应每个知识点的精心编排的作业。由于CSDN官方规定在课程介绍中不能出现作者的联系方式,因此在这里无法直接给出QQ答疑号,视频中的源码、资料和作业文档链接统一在购买后从CSDN平台跟我沟通,我会及时回复跟进。注意:本套视频教程包含全套10套作业题,覆盖所有视频知识点,循序渐进,各个击破,作业总纲如下:下面是部分作业题目展示,每道题都有知识点说明,是检验学习效果的一大利器:(部分作业展示,为了防止盗图盗题对题干做了模糊处理)(部分作业展示,为了防止盗图盗题对题干做了模糊处理)(部分作业展示,为了防止盗图盗题对题干做了模糊处理)(部分作业展示,为了防止盗图盗题对题干做了模糊处理)(部分作业展示,为了防止盗图盗题对题干做了模糊处理)…… ……
FFmpeg可以使用以下命令将YUV视频序列转换为视频文件:ffmpeg -s 1792x1024 -pix_fmt yuv420p -i TGM_1792x1024.yuv -c:v libx264 -preset slow -crf 22 -c:a aac -b:a 128k output.mp4。其中,-s参数指定视频的分辨率,-pix_fmt参数指定像素格式,-i参数指定输入的YUV视频序列文件,-c:v参数指定视频编码器,-preset参数指定编码速度和质量的平衡,-crf参数指定视频的压缩质量,-c:a参数指定音频编码器,-b:a参数指定音频的比特率,output.mp4是输出的视频文件名。\[1\] 如果要将视频文件转换为多张图片,可以使用以下命令:ffmpeg -i input.mp4 -r 30 -f image2 output-%05d.jpg。其中,-i参数指定输入的视频文件,-r参数指定帧率,-f参数指定输出格式为image2,output-%05d.jpg是输出的图片文件名,%05d表示输出的图片文件名按照5位数的顺序命名。\[2\] 如果你想在自己的代码中使用FFmpeg进行YUV转视频的操作,可以参考以下示例代码:int ecode_main(char *yuvFilePath, char *outFilePath, int videoWidth, int videoHeight, long num, int videoInfo\[\])。其中,yuvFilePath是输入的YUV视频序列文件路径,outFilePath是输出的视频文件路径,videoWidth和videoHeight是视频的宽度和高度,num是视频的帧数,videoInfo是视频的其他信息。你可以根据自己的需求在这个函数中添加FFmpeg的相关命令来实现YUV转视频的功能。\[3\] #### 引用[.reference_title] - *1* *2* [ffmpeg将MP4视频转成yuv视频序列以及将文件夹下的所有图片转成yuv视频序列](https://blog.csdn.net/weixin_42427696/article/details/124331676)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [FFmpeg转换yuv为h264视频流](https://blog.csdn.net/Nil88/article/details/50780093)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值