欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

在Android上使用FFmpeg将摄像头采集的YUV裸流编码为h264。

程序员文章站 2022-07-14 18:47:23
...

http://blog.csdn.NET/a992036795/article/details/54020491




一、目的 
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、输出 
四、流程 
在Android上使用FFmpeg将摄像头采集的YUV裸流编码为h264。

流程基本分三大步 
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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

五、代码 
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);
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213

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();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

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;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259

注意这里我设置的帧率为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

0