精华内容
下载资源
问答
  • NHVE网络硬件视频编码器C库 通过自定义协议进行硬件视频编码和流传输的库。 另请参见双网络解码器。 有关其他相关项目,请参见。 图书馆背后的意图: 最小化视频延迟 最小化CPU使用率(硬件编码和颜色转换) 多...
  • 视频编码器评测系统:VideoCodecRank

    万次阅读 多人点赞 2015-07-04 13:49:16
    视频编码器领域一直有个比较复杂的问题:mpeg2、divx、xvid、mpeg4、vp8、vp9、x264、openh264、x265等等这一系列编码器到底哪个好?而对于同一种视频编码器,又包括了各种各样的参数配置,这些配置对视频编码器的...

    视频编码器领域一直有个比较复杂的问题:mpeg2、divx、xvid、mpeg4、vp8、vp9、x264、openh264、x265等等这一系列编码器到底哪个好?而对于同一种视频编码器,又包括了各种各样的参数配置,这些配置对视频编码器的影响又是怎样的?为了研究这个问题,我和师弟们在课余时间开发了一个软件系统,专门用于评价视频编码器的性能。

    本文记录自己做的视频编码器性能评价的系统VideoCodecRank。本系统可以通过调整几种不同的维度的参数取值——视频内容、分辨率、编码器预设、码率来对视频编码器的性能进行评价和对比。对于每一个编码器,本系统可以遍历上述几种参数进行编码,并且记录编码视频图像质量和编码速度。通过本系统,可以全方位的对比视频编码器在各种条件下性能的优劣。在此还要感谢二位师弟的参与。目前在大家的合作下该系统基本功能刚开发完成,下一步打算继续测试和完善。


    系统地址: http://www.velab.com.cn/vcr/


    目前的状态

    目前本系统计算了下列编码器:

    x264-faster

    x264-medium

    x264-ultrafast

    x264-superfast

    x264-veryfast

    x264-fast

    x264-slow

    x264-slower

    x264-veryslow

    x265-faster

    x265-medium

    x265-ultrafast

    x265-superfast

    x265-veryfast

    x265-fast

    x265-slow

    x265-slower

    x265-veryslow

    f265-quality10

    f265-quality20

    DivX265-aqo2

    DivX265-aqo3

    DivX265-aqo4

    VP8-good-0

    VP8-good-1

    VP8-good-2

    VP8-good-3

    VP8-good-4

    VP8-good-5

    VP8-realtime

    DivX265-aqo1

    openh264-rc0

    openh264-rc1

    mpeg4

    mpeg1

    mpeg2

    xvid

    h263p

    theora

    VC1-adv0

    VC1-adv1

    VC1-adv2

    VC1-adv3

    VC1-adv4

    VC1-adv5

    VP9-good-0

    VP9-good-1

    VP9-good-2

    VP9-good-3

    VP9-good-4

    VP9-good-5

    VP9-realtime

    Intel-h264-speed

    Intel-h264-quality

    Intel-h264-balanced

    Intel-mpeg2-speed

    Intel-mpeg2-quality

    Intel-mpeg2-balanced

    使用了下列几种内容的测试视频:

    src01

    src02

    src04

    src05

    src06

    src08

    src11

    src12

    src14

    ducks

    park

    ped

    riverbed

    station2

    sunflower

    tractor

    每种内容的测试视频被缩放成了如下分辨率:

    640x360

    848x480

    1280x720

    1920x1080 (raw)

    每个测试视频设定了如下的BPP(可换算为码率):

    0.025

    0.05

    0.075

    0.1

    0.15

    0.2

    统计了如下视频图像质量指标:

    PSNR

    SSIM


    系统涉及到的参数

    本章主要介绍本视频编码器性能评价系统涉及到的参数。这些参数可以分为输入参数和评价参数。输入参数用于模拟不同的编码环境。而评价参数则用于在编码完成后统计编码性能。

    输入参数

    本节介绍该系统的输入参数。这些参数的变动通常会明显的影响视频编码器的性能。这些参数包括:视频内容,分辨率,编码器预设,码率。

    视频内容

    在相同视频质量的前提下,画面内容复杂、运动剧烈,要求的码率较高;画面内容简单、景物静止,要求的码率较低。本系统中我们选择ITU- BT.1788标准中提出的时间复杂度(TI)和空间复杂度(SI)来分别衡量视频的复杂程度。

    时间信息(TI)

    TI反映了一个序列画面随着时间的变化而变化的程度。画面内容运动程度剧烈的序列通常会有较高的TI值。它的计算方法是求序列的每一帧与前一帧图像的帧差,然后对帧差图像计算标准差。选这些标准差中的最大值为TI。它的计算公式如下所示:



    空间信息(SI)

    SI反映了一个序列画面的空间复杂程度。内容细节越多的序列通常会有较高的SI值。它的计算方法是对每一帧视频进行Sobel滤波,然后对滤波后图像计算标准差。选这些标准差中的最大值为SI。它的计算公式如下所示:

    分辨率

    分辨率指的是视频的尺寸。例如常见的分辨率有3840x2160 (4K), 1920x1080 (HD), 1280x720 (720P), 640x360 (360P)等。

    编码器和编码器预设

    不同编码器的编码效果相差很大。此外,同一编码器的预设(preset)对输出的图像质量有较大的影响。本系统将同一编码器的不同的预设也看作为不同的“编码器”。预设指的是预先定义好的一套编码器参数。编码器的预设一般是在速度和图像质量上寻求一个平衡点:速度快的预设一般情况下是以牺牲视频质量为代价的;视频质量好的预设一般情况下编码速度比较慢。例如x264编码器中按照编码速度从快到慢包含了10个预设:ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow, placebo。

    码率

    码率是影响视频质量最主要的参数之一。其它条件形同的情况下,码率越大,视频质量越好。例如一个640x360的1Mbps的的视频的质量肯定好于一个640x360的500kbps的视频。但是不同分辨率的视频码率差别很大。例如我们很难断定一个1280x720的1Mbps的视频的质量是否高于一个640x360的500kbps的视频。为了去掉分辨率这个影响因子,我们在本文的系统中引入了一个新的变量——BPP(每像素比特数)。BPP的计算公式如下:
    BPP=bitrate/(framerate*reso_w*reso_h)
    其中,bitrate是视频的码率,framerate是视频的帧率,reso_w和reso_h分别代表视频的宽和高。

    BPP的意义是视频中一个像素点的数据量。例如我们假设帧率为25fps,上文中1280x720的1Mbps的视频的BPP取值为0.043,640x360的500kbps的视频的BPP取值为0.087。下表列出了BPP,码率和常见分辨率之间的对应关系。

    BPP与码率之间的对应关系

     

    对应码率(kbps)

    每像素比特数

    (bits/pixel)

    640x360

    848x480

    1280x720

    1920x1080

    0.025

    144

    254

    576

    1296

    0.05

    288

    508

    1152

    2592

    0.075

    432

    763

    1728

    3888

    0.1

    576

    1017

    2304

    5184

    0.15

    864

    1526

    3456

    7776

    0.2

    1152

    2035

    4608

    10368


    评价参数

    评价参数用于在编码完成后统计编码的质量情况。评价参数可以分为两类:质量评价参数和速度评价参数。

    质量评价参数

    编码质量评价主要通过全参考视频质量评价算法实现。全参考视频质量评价算法通过比较编码前原始视频与编解码后受损视频获得视频质量的评价结果。最常见的全参考视频质量评价模型为PSNR和SSIM。
    PSNR
    PSNR(峰值信噪比)是使用最为广泛的视频质量评价方法。它的计算公式为:
    其中L为图像灰度值范围,对于8bit位深的图像来说L=2^8-1=255;M*N图像块的MSE(均方误差)计算公式为:
    PSNR取值通常在20-40之间,取值越大代表图像质量越好。尽管PSNR计算简单,但是由于没有考虑到人类视觉感知特性,所以其评价结果与主观感受往往相差较大。
    SSIM
    SSIM(结构相似度)是zhou wang等人提出的一种常见的视频质量评价方法。该方法考虑了人类视觉感知特性,综合考虑了亮度、对比度以及结构的影响。它的计算公式如下所示。
    其中l(x,y)为亮度比较函数,c(x,y)为对比度比较函数,s(x,y) 为结构比较函数。这三个函数的具体计算方法可以参考相关文献。

    SSIM取值在0-1之间,取值越大代表图像质量越好。SSIM相对于PSNR来说更加符合人眼的主观感受,因此也是一种使用很广泛的视频质量评价方法。


    速度评价参数

    编码速度评价主要通过统计编码和解码的耗时(以毫秒为单位)来实现。


    系统运行原理

    本系统会根据输入的配置信息,遍历上文介绍的几种输入参数值,组合成不同的命令进行编码和评价工作。系统开始运行后,会按照顺序执行下面几步工作:
    (1) 对于每个输入的视频测试序列,对它的尺寸进行缩放,生成一系列不同分辨率的视频序列。
    (2) 对于每种分辨率的原始视频序列,选择不同的编码器准备编码。
    (3) 对于每种编码器,设置不同的码率进行编码,生成码流文件。随后解码生成的码流文件,得到受损的视频序列。
    (4) 对于每个受损视频序列,使用不同的视频质量评价方法进行质量评价,得到质量分数。

    上述逻辑下图所示。从图中可以看出本系统遍历参数的顺序如下:

    视频内容-->分辨率-->编码器-->码率-->客观质量评价方法

    当系统完成了一次客观质量评价算的计算之后,就会生成一条保存了当前实验参数的记录,并将该记录存储到数据库中。

    网站说明

    VideoCodecRank网站的结构如下图所示。整个网站除了首页之外包含了“结果集”、“编码器”、“视频序列”、“系统配置”、“关于”几个页面。这些页面之间的关系如下图所示。
     

    首页

    首页中包含了一张编码器的综合比较图表。其中蓝色横条代表了编码图像质量,而黄色横条代表了编码时间。可以拖动图表上方的滑动条调整下面几种参数选择不同的数据对编码器的性能进行排序。
    速度质量权重:目前只支持时间/质量权重设置为1或0。质量权重为1则按照编码器输出视频质量进行排序,时间权重为1则按照编码器消耗时间进行排序。
    分辨率:该选项可以选择输入视频的尺寸。
    码率:该选项可以选择输入视频的码率。注意码率是按照BPP(Bit Per Pixel,每像素比特数)为单位的。
    内容复杂度:该选项可以选择输入测试视频序列。注意输入的视频内容是按照时间复杂度TI或空间复杂度SI(这两个指标均取自于ITU BT.1788标准)进行排序的,以方便选择。
    首页的内容如下所示。
     

    结果集页面

    结果集页面中包含了系统中所有客观视频质量评价的结果。每一条实验记录包含了如下信息:
    编码器
    视频序列
    分辨率
    每像素比特数
    编码时间
    解码时间
    视频质量评价算法
    客观质量
    主观质量

    结果集页面的内容如下图所示。可以通过在下拉框中调整“编码器”,“视频序列”,“分辨率”,“每像素比特数”,“客观质量评价算法”几个参数来筛选符合特定条件的结果。


    编码器页面

    编码器页面中包含了系统中所有参与评价的编码器(注:对于包含多种预设的编码器,每种预设都算作一种编码器)。其中每一条记录包含了如下信息:
    编码器名称
    所属标准
    厂商
    版本
    编码器页面的内容如下图所示。单击编码器的名称可以进入编码器详细信息页面。

    编码器详细信息页面

    编码器详细信息页面包含了3个部分:编码器简介、编码器详细质量和编码器时间-质量权衡图。
    编码器简介部分内容如下所示。可以看出该列表列出了编码器的基本信息。
     
    编码器详细质量部分的内容如下图所示。可以通过选择参数(编码器、视频序列、分辨率、码率),列出特定条件下测试视频序列每一帧画面的图像质量信息(客观算法PSNR、SSIM等)。图表中横坐标为视频序列的帧序号,纵坐标为视频客观质量评价算法的值。
     
    编码器时间-质量权衡图的内容如下图所示。时间/质量权衡图中的每一个点代表了一个编码器,图表横坐标为编码时间,纵坐标为编码图像质量。由此可知,位于图表左边的编码器速度比较快,而位于图表上边的编码器图像质量比较好。“又快又好”的编码器都位于图表的左上方。该图表可以通过选择参数(视频序列、码率、分辨率、客观评价方法),列出特定条件下测试视频编码器的耗时信息和图像质量信息。
     

    视频序列页面

    视频序列页面中列表显示了系统中所有参与测试的原始视频序列信息。其中每一条记录包含如下信息:
    视频序列名称
    原始分辨率
    像素采样格式
    帧率
    帧数
    视频序列页面的内容如下图所示。单击视频序列的名称可以进入视频序列详细信息页面。
     

    视频序列详细信息页面

    视频序列详细信息页面包含了3项内容:视频序列预览、视频序列详细特性以及视频序列时间/空间复杂度对比图。
    视频序列预览部分内容如下所示。可以通过该功能预览测试视频的内容。
     
    视频序列详细特性部分内容如下图所示。可以通过该功能查看视频中每一帧图像的TI(Temporal perceptual Information)信息和SI(Spatial perceptual Information)信息。TI和SI两个指标取自于ITU BT.1788标准。TI越大,代表视频运动剧烈(时间上变化大);SI越大,代表视频内容复杂(空间上纹理多)。图表中横坐标为视频序列的帧序号,纵坐标为视频特性值。
     

    视频序列时间/空间复杂度对比图如下所示。图中每个点代表一个视频序列,图表横坐标为SI,纵坐标为TI。由此可知位于图表上方的视频序列运动比较剧烈,而位于图表右边的视频序列内容纹理比较复杂。最为简单的视频序列位于图表的右上角,最为简单的视频序列位于图表的左下角。



    系统配置页面

    系统配置页面的内容如下图所示。该页面中列出了系统配置的参数信息。例如显示了输入视频会被拉伸为哪几种分辨率,编码时候会选择哪些BPP,客观质量评价算法有哪些等等。




    雷霄骅
    leixiaohua1020@126.com
    http://blog.csdn.net/leixiaohua1020



    展开全文
  • 针对目前视频编码标准和视频编码器较多、缺乏统一评价标准和客观评价结果的问题,提出了使用视频质量、编码速度、码率节省百分比、...结果表明提出的评价体系和测试平台搭建方法可以很好地用于视频编码器的性能评价。
  • STM32编码器模式的测试例程,代码中采用TIM2定时器的编码器模式,在主程序中利用延时函数监测单位时间内的脉冲数,并根据脉冲数计算速度。程序中不包含电机输出控制和PID调速。
  • 本课题研究主要完成了以下工作:①应用SIMD技术完成了A、,S视频编码器帧内预测模块中预测模式以)及zigzag扫描的多媒体指令优化,缩短了帧内预测编码时间,编码器的编码太原理工大学硕士研究生学位论文 速度大大提高...
  • Android视频编码器

    千次阅读 2017-01-04 16:53:00
    1、使用FFmpeg动态库(这个动态库需要有libx264的实现,否则可能会出现寻找编码器失败异常)。关于如何获得这样的一个动态库可以参考http://blog.csdn.net/a992036795/article/details/53941436 2、Android开发环境...

    一、目的
    在Android上使用FFmpeg将摄像头采集的YUV裸流编码为h264。
    二、环境准备
    1、使用FFmpeg动态库(这个动态库需要有libx264的实现,否则可能会出现寻找编码器失败异常)。关于如何获得这样的一个动态库可以参考http://blog.csdn.net/a992036795/article/details/53941436
    2、Android开发环境(我用的是Android Studio2.2.3) 和最新的ndk。
    三、思路
    1、初始化ffmpeg的一些配置。
    2、调用系统摄像头设置参数使用mCamera.setPreviewCallbackWithBuffer();设置回调接口用来接受YUV数据。
    3、将摄像头获得的YUV数据(默认是NV21)转化成YUV420P格式
    3、将获得的修改后的数据传给编码器,进行编码
    4、输出
    四、流程
    这里写图片描述

    流程基本分三大步
    1、初始化(包括打开输出文件,设置参数,寻找编码器、写入头信息等。)
    2、实时传入数据进行编码
    3、刷帧,并写入尾部信息。释放资源

    我用三个jni方法分别对应这三步:

    
        /**
         * 初始化。
         *
         * @param destUrl 目标url
         * @param w       宽
         * @param h       高
         * @return 结果
         */
        public static native int init(String destUrl, int w, int h);
    
        /**
         * 传入数据。
         * 
         * @param bytes
         * @param w
         * @param h
         * @return
         */
        public static native int push(byte[] bytes,int w,int h);
    
        /**
         * 停止
         * @return
         */
        public static native int stop();

    五、代码
    1、java

    package com.blueberry.x264;
    
    import android.app.Activity;
    import android.graphics.ImageFormat;
    import android.hardware.Camera;
    import android.os.Bundle;
    import android.support.annotation.Nullable;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    import android.view.Surface;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;
    import android.view.View;
    import android.widget.Button;
    
    import java.io.IOException;
    import java.util.Arrays;
    import java.util.List;
    
    import static android.hardware.Camera.Parameters.FLASH_MODE_AUTO;
    import static android.hardware.Camera.Parameters.PREVIEW_FPS_MAX_INDEX;
    import static android.hardware.Camera.Parameters.PREVIEW_FPS_MIN_INDEX;
    
    /**
     * Created by blueberry on 1/3/2017.
     */
    
    public class CameraActivity extends AppCompatActivity implements SurfaceHolder.Callback2,
            Camera.PreviewCallback {
        private static final String TAG = "CameraActivity";
    
        private Button btnStart;
        private SurfaceView mSurfaceView;
        private SurfaceHolder mSurfaceHolder;
    
        private Camera mCamera;
    
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_camera);
            btnStart = (Button) findViewById(R.id.btn_start);
            mSurfaceView = (SurfaceView) findViewById(R.id.surface_view);
            mSurfaceHolder = mSurfaceView.getHolder();
            mSurfaceHolder.addCallback(this);
            btnStart.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    start();
                }
            });
    
        }
    
        private boolean isPublish;
        private boolean isStarted;
    
        private void start() {
            if (isStarted) {
                stop();
                isStarted = false;
    
            } else {
                isStarted = true;
                // init
                isPublish = true;
                Pusher.init("/sdcard/camera.h264", size.width, size.height);
            }
        }
    
        private void stop() {
            isPublish = false;
            Pusher.stop();
        }
    
        private void openCamera() {
            try {
                this.mCamera = Camera.open();
            } catch (RuntimeException e) {
                throw new RuntimeException("打开摄像头失败", e);
            }
    
        }
    
        private Camera.Size size;
        private boolean isPreview;
    
        private void initCamera() {
            if (this.mCamera == null) {
                openCamera();
            }
    
            setParameters();
            setCameraDisplayOrientation(this, Camera.CameraInfo.CAMERA_FACING_BACK, mCamera);
    
            int buffSize = size.width * size.height * ImageFormat.getBitsPerPixel(ImageFormat.NV21) / 8;
            mCamera.addCallbackBuffer(new byte[buffSize]);
            mCamera.setPreviewCallbackWithBuffer(this);
            try {
                mCamera.setPreviewDisplay(mSurfaceHolder);
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (isPreview) {
                mCamera.stopPreview();
                isPreview = false;
            }
            mCamera.startPreview();
            isPreview = true;
        }
    
        public static void setCameraDisplayOrientation(Activity activity,
                                                       int cameraId, android.hardware.Camera camera) {
            android.hardware.Camera.CameraInfo info =
                    new android.hardware.Camera.CameraInfo();
            android.hardware.Camera.getCameraInfo(cameraId, info);
            int rotation = activity.getWindowManager().getDefaultDisplay()
                    .getRotation();
            int degrees = 0;
            switch (rotation) {
                case Surface.ROTATION_0:
                    degrees = 0;
                    break;
                case Surface.ROTATION_90:
                    degrees = 90;
                    break;
                case Surface.ROTATION_180:
                    degrees = 180;
                    break;
                case Surface.ROTATION_270:
                    degrees = 270;
                    break;
            }
    
            int result;
            if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                result = (info.orientation + degrees) % 360;
                result = (360 - result) % 360;  // compensate the mirror
            } else {  // back-facing
                result = (info.orientation - degrees + 360) % 360;
            }
            camera.setDisplayOrientation(result);
        }
    
    
        private void setParameters() {
            Camera.Parameters parameters = mCamera.getParameters();
            List<Camera.Size> supportedPreviewSizes = parameters.getSupportedPreviewSizes();
            for (Camera.Size supportSize : supportedPreviewSizes) {
                if (supportSize.width >= 160 && supportSize.width <= 240) {
                    this.size = supportSize;
                    Log.i(TAG, "setParameters: width:" + size.width + " ,height:" + size.height);
                    break;
                }
            }
    
            int defFPS = 20 * 1000;
            List<int[]> supportedPreviewFpsRange = parameters.getSupportedPreviewFpsRange();
    
            int[] destRange = null;
            for (int i = 0; i < supportedPreviewFpsRange.size(); i++) {
                int[] range = supportedPreviewFpsRange.get(i);
                if (range[PREVIEW_FPS_MAX_INDEX] >= defFPS) {
                    destRange = range;
                    Log.i(TAG, "setParameters: destRange:" + Arrays.toString(range));
                    break;
                }
            }
    
            parameters.setPreviewFpsRange(destRange[PREVIEW_FPS_MIN_INDEX],
                    destRange[PREVIEW_FPS_MAX_INDEX]);
            parameters.setPreviewSize(size.width, size.height);
            parameters.setFlashMode(FLASH_MODE_AUTO);
            parameters.setPreviewFormat(ImageFormat.NV21);
            mCamera.setParameters(parameters);
        }
    
    
        @Override
        public void surfaceRedrawNeeded(SurfaceHolder holder) {
        }
    
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
        }
    
    
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            initCamera();
        }
    
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
        }
    
        @Override
        public void onPreviewFrame(final byte[] data, Camera camera) {
            if (isPublish) {
                    Pusher.push(data,size.width,size.height);
            }
    
            int buffSize = size.width * size.height * ImageFormat.getBitsPerPixel(ImageFormat.NV21) / 8;
    
            if (data == null) {
                mCamera.addCallbackBuffer(new byte[buffSize]);
            } else {
                mCamera.addCallbackBuffer(data);
            }
        }
    }
    

    jni:

    public final class Pusher {
    
    
        /**
         * 初始化。
         *
         * @param destUrl 目标url
         * @param w       宽
         * @param h       高
         * @return 结果
         */
        public static native int init(String destUrl, int w, int h);
    
        /**
         * 传入数据。
         *
         * @param bytes
         * @param w
         * @param h
         * @return
         */
        public static native int push(byte[] bytes,int w,int h);
    
        /**
         * 停止
         * @return
         */
        public static native int stop();
    }
    

    c:

    #include <jni.h>
    #include <stdio.h>
    #include <android/log.h>
    #include "libavutil/imgutils.h"
    #include "libavformat/avformat.h"
    #include "libavutil/time.h"
    
    
    #define LOGI(format, ...) \
        __android_log_print(ANDROID_LOG_INFO, TAG,  format, ##__VA_ARGS__)
    
    #define LOGD(format, ...) \
        __android_log_print(ANDROID_LOG_DEBUG,TAG,format,##__VA_ARGS__)
    
    #define LOGE(format, ...) \
        __android_log_print(ANDROID_LOG_ERROR,TAG,format,##__VA_ARGS__)
    
    #define TAG "Push"
    
    #define FPS 10
    
    AVPacket avPacket;
    int size;
    AVFrame *avFrame;
    AVStream *video_st;
    AVCodecContext *avCodecContext;
    int fameCount = 0;
    AVFormatContext *ofmt_ctx;
    int64_t start_time;
    
    static int stop();
    
    static int init(const char *destUrl, int w, int h);
    
    static int push(uint8_t *bytes);
    
    void callback(void *ptr, int level, const char *fmt, va_list vl);
    
    JNIEXPORT jint JNICALL
    Java_com_blueberry_x264_Pusher_init(JNIEnv *env, jclass type, jstring destUrl_, jint w, jint h) {
        const char *destUrl = (*env)->GetStringUTFChars(env, destUrl_, 0);
        int ret = init(destUrl, w, h);
        (*env)->ReleaseStringUTFChars(env, destUrl_, destUrl);
        return ret;
    }
    
    
    JNIEXPORT jint JNICALL
    Java_com_blueberry_x264_Pusher_push(JNIEnv *env, jclass type, jbyteArray bytes_, jint w, jint h) {
        jbyte *bytes = (*env)->GetByteArrayElements(env, bytes_, NULL);
    //    I420: YYYYYYYY UU VV    =>YUV420P
    //    YV12: YYYYYYYY VV UU    =>YUV420P
    //    NV12: YYYYYYYY UVUV     =>YUV420SP
    //    NV21: YYYYYYYY VUVU     =>YUV420SP
        int ret = push((uint8_t *) bytes);
        (*env)->ReleaseByteArrayElements(env, bytes_, bytes, 0);
        return ret;
    }
    
    JNIEXPORT jint JNICALL
    Java_com_blueberry_x264_Pusher_stop(JNIEnv *env, jclass type) {
        return stop();
    }
    
    void callback(void *ptr, int level, const char *fmt, va_list vl) {
        FILE *f = fopen("/storage/emulated/0/avlog.txt", "a+");
        if (f) {
            vfprintf(f, fmt, vl);
            fflush(f);
            fclose(f);
        }
    
    }
    
    static int flush_encoder(AVFormatContext *fmt_ctx, int streamIndex) {
        int ret;
        int got_frame;
        AVPacket enc_pkt;
        if (!(fmt_ctx->streams[streamIndex]->codec->codec->capabilities & CODEC_CAP_DELAY)) {
            return 0;
        }
    
        while (1) {
            enc_pkt.data = NULL;
            enc_pkt.size = 0;
            av_init_packet(&enc_pkt);
            ret = avcodec_encode_video2(fmt_ctx->streams[streamIndex]->codec, &enc_pkt, NULL,
                                        &got_frame);
            av_frame_free(NULL);
            if (ret < 0) {
                break;
            }
            if (!got_frame) {
                ret = 0;
                return ret;
            }
            LOGI("Flush Encoder : Succeed to encoder 1 frame! \tsize:%5d\n", enc_pkt.size);
            ret = av_write_frame(fmt_ctx, &enc_pkt);
            if (ret < 0) {
                break;
            }
    
        }
        return ret;
    }
    
    static int stop() {
        int ret;
        ret = flush_encoder(ofmt_ctx, 0);
        if (ret < 0) {
            LOGE("Flush Encoder failed");
            goto end;
        }
    
        av_write_trailer(ofmt_ctx);
        end:
    
        //Clean
        if (video_st) {
            avcodec_close(video_st->codec);
            av_free(avFrame);
        }
        avio_close(ofmt_ctx->pb);
        avformat_free_context(ofmt_ctx);
        LOGI("stop----------------------");
        return ret;
    }
    
    static int push(uint8_t *bytes) {
        start_time = av_gettime();
    
        int got_picture = 0;
        static int i = 0;
    
        int j = 0;
    
        avFrame = av_frame_alloc();
        int picture_size = av_image_get_buffer_size(avCodecContext->pix_fmt, avCodecContext->width,
                                                    avCodecContext->height, 1);
        uint8_t buffers[picture_size];
    
        av_image_fill_arrays(avFrame->data, avFrame->linesize, buffers, avCodecContext->pix_fmt,
                             avCodecContext->width, avCodecContext->height, 1);
    
        av_new_packet(&avPacket, picture_size);
        size = avCodecContext->width * avCodecContext->height;
    
        //安卓摄像头数据为NV21格式,此处将其转换为YUV420P格式
        memcpy(avFrame->data[0], bytes, size); //Y
        for (j = 0; j < size / 4; j++) {
            *(avFrame->data[2] + j) = *(bytes + size + j * 2); // V
            *(avFrame->data[1] + j) = *(bytes + size + j * 2 + 1); //U
        }
        int ret = avcodec_encode_video2(avCodecContext, &avPacket, avFrame, &got_picture);
        LOGD("avcodec_encode_video2 spend time %ld", (int) ((av_gettime() - start_time) / 1000));
        if (ret < 0) {
            LOGE("Fail to avcodec_encode ! code:%d", ret);
            return -1;
        }
        if (got_picture == 1) {
            avPacket.pts = i++ * (video_st->time_base.den) / ((video_st->time_base.num) * FPS);
            LOGI("Succeed to encode frame: %5d\tsize:%5d\n", fameCount, avPacket.size);
            avPacket.stream_index = video_st->index;
            avPacket.dts = avPacket.pts;
            avPacket.duration = 1;
            int64_t pts_time = AV_TIME_BASE * av_q2d(video_st->time_base);
    
            int64_t now_time = av_gettime() - start_time;
            if (pts_time > now_time) {
                LOGD("等待");
                av_usleep(pts_time - now_time);
            }
    
            av_write_frame(ofmt_ctx, &avPacket);
            LOGD("av_write_frame spend time %ld", (int) (av_gettime() - start_time) / 1000);
            av_free_packet(&avPacket);
            fameCount++;
        } else {
            LOGE("唉~");
        }
        av_frame_free(&avFrame);
    }
    
    static int init(const char *destUrl, int w, int h) {
        av_log_set_callback(callback);
        av_register_all();
        LOGD("resister_all");
        AVOutputFormat *fmt;
        int ret;
        LOGI("ouput url: %s", destUrl);
        avformat_alloc_output_context2(&ofmt_ctx, NULL, "flv", destUrl);
        LOGD("allocl ofmt_ctx finished");
        fmt = ofmt_ctx->oformat;
        if ((ret = avio_open(&ofmt_ctx->pb, destUrl, AVIO_FLAG_READ_WRITE)) < 0) {
            LOGE("avio_open error");
            return -1;
        }
        video_st = avformat_new_stream(ofmt_ctx, NULL);
        if (video_st == NULL) {
            ret = -1;
            return -1;
        }
        LOGD("new stream finished");
        avCodecContext = video_st->codec;
    
    //    avCodecContext->codec_id = fmt->video_codec;
        avCodecContext->codec_id = AV_CODEC_ID_H264;
        avCodecContext->codec_type = AVMEDIA_TYPE_VIDEO;
        avCodecContext->pix_fmt = AV_PIX_FMT_YUV420P;
        avCodecContext->width = w;
        avCodecContext->height = h;
        // 目标的码率,即采样码率;显然,采码率越大,视频大小越大
        avCodecContext->bit_rate = 400000; //400,000
        //每250帧插入一个I帧,I帧越少,视频越小
        avCodecContext->gop_size = 250;
        // 帧率的基本单位用分数表示
        avCodecContext->time_base.num = 1;
        avCodecContext->time_base.den = FPS;
    
        // 最大和最小量化系数
        avCodecContext->qmin = 10;
        avCodecContext->qmax = 51;
    
        avCodecContext->max_b_frames = 3;
    
        // Set Option
        AVDictionary *param = 0;
    
        //H.264
        if (avCodecContext->codec_id == AV_CODEC_ID_H264) {
            av_dict_set(&param, "preset", "slow", 0);
            av_dict_set(&param, "tune", "zerolatency", 0);
            LOGI("set h264 param finished");
        }
        //H.265
        if (avCodecContext->codec_id == AV_CODEC_ID_H265) {
            av_dict_set(&param, "preset", "ultrafast", 0);
            av_dict_set(&param, "tune", "zero-latency", 0);
            LOGI("set h265 param");
        }
    
        AVCodec *avCodec;
        avCodec = avcodec_find_encoder(avCodecContext->codec_id);
        if (NULL == avCodec) {
            LOGE("寻找编码器失败..");
            return -1;
        }
    
        if ((ret = avcodec_open2(avCodecContext, avCodec, &param)) < 0) {
            LOGE("avcodec_open2 fail!");
            return -1;
        }
        // Write File Header
        avformat_write_header(ofmt_ctx, NULL);
    
        return ret;
    }
    
    

    注意这里我设置的帧率为10帧,并且设置的预览宽度不超过240,主要目的就是为了提高编码的效率。(我用小米2S测试这样勉强可以编码),测试这个方法avcodec_encode_video2
    非常的耗时,如果我是1080P的图像时他可能需要等待1秒钟!!!目前刚接触ffmpeg不知道有什么办法可以优化。如有知道的大神可以指点指点。

    参考:http://blog.csdn.net/leixiaohua1020/article/details/25430425
    http://blog.csdn.net/beyond_cn/article/details/12998247

    展开全文
  • 2019年10月22日,由莫斯科国立大学(Moscow State University)举办的MSU世界视频编码器大赛成绩揭晓, 腾讯内部开源协同的V265编码器再创佳绩,一举拿下PSNR(峰值信噪比)/VMAF(Netflix开源的感知视频质量评估算法)...

           2019年10月22日,由莫斯科国立大学(Moscow State University)举办的MSU世界视频编码器大赛成绩揭晓, 腾讯内部开源协同的V265编码器再创佳绩,一举拿下PSNR(峰值信噪比)/VMAF(Netflix开源的感知视频质量评估算法)两项指标第一、SSIM指标第二的出色成绩。 

           近些年随着视频服务领域的快速发展,点播、直播、短视频、VR等领域相继爆发,人们对于高清、超高清视频的追求越来越强烈,同时也带来了越来越大的带宽压力,如何利用利用技术降低带宽消耗的同时又能最大化的还原视频的画质和质量,成为了重要的课题。视频压缩编码作为其中最核心的一环,越来越被各大公司机构重视。MSU世界视频编码器大赛作为视频压缩领域最具影响力的顶级赛事,迄今已连续举办了十四届,吸引了越来越多国内外重量级公司和组织的参加,包括: Intel、Google、Tencent、Huawei、Ittiam、MulticoreWare、Ucodec、Peppa、Kingsoft等都数次参与该比赛。

           今年的世界视频编码器大赛竞争异常激烈,总计有12个编码器公开测试结果,超过往年。同时测试集较往年也有了非常大的改动,不仅在数量上是往届之最,从去年的28个增加到今年的100个, 测试集的选取上也进一步优化从而能更好的反映真实的应用场景。 在这样激烈的竞争下,V265编码器仍然斩获了PSNR/VMAF两项指标的第一,同时SSIM指标也取得了第二的优异成绩。下图为大赛排名的相关数据:

     

     

    整个比较由三部分组成, 分别对应于三种不同档次的编码器用例:快速编码(fast)、通用编码(universal)、以及最佳编码(ripping)。从上图的VMAF对比结果中可以看出,腾讯V265编码器很好的兼顾了压缩效率和编码速度,综合三个速度档次,其不仅在压缩率上优势明显,在整体的编码速度上也是最快的。

    随着近年来H.265视频编码技术的优势愈发明显,各大公司都开始加大力度投入研发, 腾讯作为中国最大的视频服务平台,更是深知它的重要性,腾讯V265编码器,就是腾讯基于H.265标准自主研发的一款视频编码软件。V265在本次大赛中的优异成绩得益于腾讯的新代码文化运动——多个部门在V265编码器研发上进行开源协同,不断在工程上的精雕细琢和在算法上的大胆创新它采用内核功能精简、高效内存访问、核心模块全汇编、快速算法优化、编码与AI融合等技术,在压缩性能、编码速度、码率控制、主观视觉等多个技术指标中均获突破,达到国际领先水平

    腾讯V265编码器目前已支持腾讯云上以极速高清为代表的包括视频编辑、视频转码等各种视频相关业务,让用户在低码率下享受与高码率相同的画质体验。极速高清可以在点播和直播业务下,相比开源软件在相同画质下平均分别节省超20%和40%的带宽成本;或在同等带宽条件下,提供更加高清优质的视频画质体验,感受“质”的变化。腾讯云一直以来都在音视频领域潜心深耕,不断完善自身产品体系,结合用户业务场景不断创新,极速高清、画质增强、老片修复等技术产品给您带来全新的高清视野。

    问鼎国际编码大赛,体现了腾讯V265编码器世界顶级的技术水平,和腾讯深耕于视频编码技术、创造极致视频体验的决心,同时也意味着,腾讯V265编码器有能力在助力腾讯云视频业务的性能提升的同时,更好地助力行业客户,为用户带来更清晰流畅的视频体验。

    展开全文
  • 视频编码器评估与参数优化

    千次阅读 2014-11-15 09:31:53
    视频编码器评估与参数优化是个比较麻烦的问题,主要原因是:编码器种类多,输入的参数繁多,参数的相互影响非线性,深入理解其实现需要投入巨大的精力或者不可能(对于商业产品而言)。而另一方面,评估和选择编码器...

    视频编码器评估与参数优化是个比较麻烦的问题,主要原因是:编码器种类多,输入的参数繁多,参数的相互影响非线性,深入理解其实现需要投入巨大的精力或者不可能(对于商业产品而言)。而另一方面,评估和选择编码器、针对特定的目标选择最优的编码参数组合对于视频服务商——比如视频网站来说,是一个现实的需要。有感于或者苦恼于如何选择最优的方案,笔者通过对多目标优化方法的尝试进行了一定的探索,之所以选择这种方法,主要原因是它比较“暴力”和“傻瓜”,并不需要过多的纠缠参数的涵义f‘(*∩_∩*)′。

    下文仅仅是一个初步的方案可行性论证(发布此文的一个月前),所有展示的数据为实际运行结果,但是只有参考价值或者不完整,仅供交流思路使用。

    因涉及到工作的内容,不打算更新以展示最新的进展——好吧,由于中间各种事情打岔的关系,其实没啥进展.....................╮( ̄﹏ ̄)╭

    1.测试视频资源

     

    视频序列

    说明

    码率kb/s

    帧数

    FPS 帧/秒

    分辨率

    Cartoon

    少儿动漫

    2336

    746

    25

    720x576 (yuv420p)

    Sport-Soccer

    足球世界杯预选赛

    2553

    713

    25

    720x576 (yuv420p)

    Sport-NBA

    NBA篮球赛

    2394

    738

    25

    720x576 (yuv420p)

    Course

    百家讲坛

    2513

    711

    25

    720x576 (yuv420p)

    Scenic

    风景片《大黄山》

    2804

    710

    25

    720x576 (yuv420p)

    Documentary

    历史纪录片《燃烧的太平洋》

    8291

    730

    25

    1920x1080 (yuv420p)

     

    2.编码器:

    x264-snapshot-20141012-2245

     

    3.测试方法

    基于分布式计算的多目标优化

     

    4.评估方法

    4.1目标

    1.        文件压缩率

    2.        处理速度:文件大小 / 编转码时长

    3.        视频质量:SSIM

     

    4.2编码参数

    参数

    说明

    取值范围

    deblock

     

    [-3, 3]

    crf

     

    [0, 51]

    trellis

     

    [0, 2]

    nr

     

    [0, 1000]

    subq

     

    [0, 6]

    mbd

     

    [0, 2]

    pass

     

    [0, 2]

    coder

     

    [ "vlc", "ac", "raw", "rle", "deflate", ]

    me_method

     

    [ "zero", "full", "epzs", "esa", "tesa", "dia", "log", "phods", "x1", "hex", "umh", "iter", ]

    Partitions

     

    [ "parti4x4", "parti8x8", "partp4x4", "partp8x8",]

    Etc…..

     

     

     


    5.测试结果

     

    5.1 2目标(视频质量&文件压缩)

     

    曲线拟合结果:

    对应的编码参数:

    Cartoon视频部分解:

     

     

    5.2 2目标(视频质量&编码速度)

     

     

    5.3 3目标(视频质量&编码速度&文件压缩率)



     

    5.4最优解集收敛速度(convergence rate)

     

    6.简要结论

    1.        X264编码器对不同类型的视频内容有明显不同的最优解集。

    a)        在视频质量、视频压缩率、编码速度三项指标的多种组合上,色彩不丰富、变化幅度小的视频(如动画),帕累托前端的数据要全面优于色彩丰富、变化剧烈的视频(如体育赛事)。这也说明,在强调最优策略的场合,针对不同视频类型进行编码是有价值和必要性的。

    b)       如何对视频类型进行区分,需要更多的工作要做。如:更大的样本。

    2.        多个编码器的比较和评估同样可以基于对多个编码器的帕累托前端的比较。如:对intel mdk进行求解。

    3.        在实验过程中,我们将编码器视作“黑盒子”或者是一个非线性的未知方程组,进行最优求解。

    a)        最终的pareto front可以拟合为:

    b)       最优解集的规律性有待进一步挖掘


    展开全文
  • 选择视频编码器的误区------傅德良

    千次阅读 2018-08-15 17:15:40
    大家好,我是傅德良,在Hulu主要负责的团队是在做音视频编解码和传输相关的一些优化和开发的工作,很高兴跟大家聊一聊对于视频编码器的对比和选择。   主要内容分为以下三个方面:   1,纷争的视频标准与视频...
  • H264编码器性能测试

    千次阅读 2014-06-17 13:33:49
    首先,介绍一下常见的三大开源H264编码器:JM、X264、T264 JM H264的官方测试源码,实现了264的所有特性,但程序结构冗长,编码复杂度高,不推荐商业应用。 X264 摈弃了264中对编码性能贡献小,但计算复杂度极高...
  • ces265:轻量,多线程HEVC视频编码器 我在博士期间编写的一种C ++ HEVC(有时也称为H.265)视频编码器。 原始资源可以在找到。 使用pthreads库,此编码器可用于处理原始YCbCr 4:2:0平面视频。 ces265的官方页面...
  • 首先对HEVC编码的基本原理进行阐述,然后基于德州仪器(TI)公司的DaVinci平台设计了四通道的视频编码硬件平台。该平台采用ARM+DSP的双核体系,ARM负责各个硬件模块的协调控制,DSP则负责视频信号的编码计算。由于...
  • 针对目前视频编码标准和视频编码器较多、缺乏统一评价标准和客观评价结果的问题,提出了使用视频质量、编码速度、码率节省百分比、内存占用等指标相结合的评价体系,同时给出了评测平台的搭建方法。采用多个不同的...
  • 此应用程序可用作在 Android 设备上进行视频编码器性能分析的工具。 它可以查询目标设备上支持的视频编解码器和颜色格式,读取/生成 yuv 数据并通过硬件路径将日期编码为视频流。 支持不同编码率(30/60/120fps)...
  • 以 H. 263、MPEG-4、H. 264三种标准作为测试对象 ,在 Win / Intel平台上测试了优化后编码器的计算效率、编码效率和码率控制精度 ,并对...测试数据为开发人员在一定硬件性价比的约束条件下实现视频编码器提供了参考。
  • 最简单的视频编码器:基于libx264(编码YUV为H.264)

    万次阅读 多人点赞 2014-12-23 00:18:18
    本文记录一个最简单的基于libx264的H.264视频编码器。此前记录的H.264编码器都是基于FFmpeg调用libx264完成编码的,例如: 《最简单的基于FFMPEG的视频编码器(YUV编码为H.264)》相比与上文中的编码器,本文记录的...
  • astiencoder是一种使用GO编写且基于ffmpeg C绑定的开源视频编码器。 目前,该项目仅在FFMpeg 4.1.1上进行了测试。 当我可以使用ffmpeg二进制文件时,为什么还要使用该项目? 在大多数情况下,您不会将astiencoder是...
  • 弗劳恩霍夫多功能视频编码器(VVenC) 多功能视频编码(VVC)是由ITU-T视频编码专家组(VCEG)和ISO / IEC运动图像专家组(MPEG)的联合视频专家组(JVET)开发的最新国际视频编码标准。 VVC是高效视频编码(HEVC)...
  • 最简单的视频编码器:基于libx265(编码YUV为H.265)

    万次阅读 多人点赞 2014-12-23 17:36:43
    本文记录一个最简单的基于libx265的H.265(HEVC)视频编码器。此前记录的编码器是通过FFmpeg调用libx265完成编码的,例如:《最简单的基于FFmpeg的视频编码器-更新版(YUV编码为HEVC(H.265))》相比与上文中的编码器,...
  • MediaCoder CUDA H.264 编码器测试报告

    千次阅读 2012-04-07 14:00:58
    <!-- .pcb {margin-right:0} --> ...“MediaCoder 拥有目前其他 CUDA Encoder 无法比拟的优势,能导入几乎所有的...MediaCoder CUDA H.264 编码器测试报告 异构运算是指系统内不同的运算部件负责各自擅长的计算,
  • 设计了一种适用于工业现场的嵌入式视频编码器,视频压缩按照H.264标准,在Intel推出的PXA255 Xscale架构的处理机和源码开放的Linux嵌入式操作系统的基础上,实现了视频的实时动态采集、压缩和网络传输,介绍了系统...
  • 详细说明请遵循我们的指南:“指令一台视频编码器”。 教tur 所有指南均已写入“ Veido编码器使用说明”,请按照此文档运行我们的项目。 另外,我们还提供了视频指南,以便您查看: 命令行指导视频:cmldemo GUI指南...
  • 一个经过优化的 x264 编码器,可用于视频会议等实时性要求较高的领域。
  • 以H.263、MPEG-4、H.264三种标准作为测试对象,在Win/Intel 平台上测试了优化后编码器的计算效率、编码效率和码率控制精度,并对测试结果...测试数据为开发人员在一定硬件性价比的约束条件下实现视频编码器提供了参考。
  • 鉴于英特尔可扩展视频技术(SVT)开源视频编码器以及其他开源视频编码器/解码器的最新更新,以下是AMD 霄龙 7742 双路服务器在与英特尔竞争的情况下与之抗衡的最新表现...
  • H.264 视频编码器的研究与分析

    千次阅读 2017-06-23 16:35:49
    H.264 视频编码器的研究与分析 郝瑞林 北京邮电大学网络技术研究院 北京(100876) E-mail:ruilynn@gmail.com 摘 要:随着市场对多媒体信息传输需求的增加,多媒体信息传输如何适应不同信道传输特性的...
  • 测试x264编码器的低延时编码和非延时编码
  • 本文记录一个最简单的基于libvpx的VP8视频编码器。这个例子是从官方的示例代码中精简出来的例子。我发现与H.264不同,VP8的裸流(即不包含封装格式的纯视频数据流)是不能播放的。换言之,VP8的裸流必须存放在容器中...
  • DM365的视频编码器的硬件设计

    千次阅读 2012-02-03 12:01:08
    采用ITU-T的H.264(DM365内嵌硬件压缩)视频压缩算法,高清模拟视频信号通过专用视频解码芯片TVP7002转换成数字视频信号,在DM365中进行数据压缩,内嵌ARM把数据打包后传到internet,通过PC机软件解码,进行视频...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 65,039
精华内容 26,015
关键字:

视频编码器测试