FFMPEG 视频编码最常见的H264,H265需要X264,X265外部模块支持,可以从我们开源平台的FFMPEG编译项目里面获取代码和配置进行一键式编译:https://github.com/Car-eye-team/Car-eye-FFMPEG,我们下面的代码主要是为了简化代码调用结构。只需要配置参数,输入数据就可以进行视频编码,不多说,贴上代码:
[cpp] view plain copy
-
/*
-
* Car eye 车辆管理平台: www.car-eye.cn
-
* Car eye 开源网址: https://github.com/Car-eye-team
-
* CarEyeEncoderAPI.h
-
*
-
* Author: Wgj
-
* Date: 2018-04-29 20:01
-
* Copyright 2018
-
*
-
* CarEye 媒体编码库接口声明
-
*/
-
#ifndef __CAREYE_ENCODER_H__
-
#define __CAREYE_ENCODER_H__
-
#include "public.h"
-
// 编码器对象句柄定义
-
#define CarEye_Encoder_Handle void*
-
// 最大音频帧大小 1 second of 48khz 32bit audio
-
#define MAX_AUDIO_FRAME_SIZE 192000
-
// 媒体编码类型定义 与FFMPEG中一一对应,H265定义与其他库定义需要转换
-
enum CarEye_CodecType
-
{
-
// 不进行编码
-
CAREYE_CODEC_NONE = 0,
-
// H264编码
-
CAREYE_CODEC_H264 = 0x1C,
-
// H265编码
-
CAREYE_CODEC_H265 = 0xAE,
-
// MJPEG编码
-
CAREYE_CODEC_MJPEG = 0x08,
-
// MPEG4编码
-
CAREYE_CODEC_MPEG4 = 0x0D,
-
// AAC编码
-
CAREYE_CODEC_AAC = 0x15002,
-
// G711 Ulaw编码 对应FFMPEG中的AV_CODEC_ID_PCM_MULAW定义
-
CAREYE_CODEC_G711U = 0x10006,
-
// G711 Alaw编码 对应FFMPEG中的AV_CODEC_ID_PCM_ALAW定义
-
CAREYE_CODEC_G711A = 0x10007,
-
// G726编码 对应FFMPEG中的AV_CODEC_ID_ADPCM_G726定义
-
CAREYE_CODEC_G726 = 0x1100B,
-
};
-
// YUV视频流格式定义,与FFMPEG中一一对应
-
enum CarEye_AVType
-
{
-
CAREYE_FMT_YUV420P = 0,
-
CAREYE_FMT_YUV422P = 4,
-
CAREYE_FMT_YUV444P = 5,
-
CAREYE_FMT_YUV410P = 6,
-
CAREYE_FMT_YUV411P = 7,
-
};
-
// 原始流结构定义
-
typedef struct CarEye_OriginalStream
-
{
-
// 视频输入流格式
-
enum CarEye_AVType InVideoType;
-
// 期望输出的视频流格式,不期望输出可设置为CAREYE_CODEC_NONE
-
enum CarEye_CodecType OutVideoType;
-
// 期望输出的音频流格式,不期望输出可设置为CAREYE_CODEC_NONE
-
enum CarEye_CodecType OutAudioType;
-
// 视频帧率(FPS),推荐值:25
-
unsigned char FramesPerSecond;
-
// 视频宽度像素
-
unsigned short Width;
-
// 视频的高度像素
-
unsigned short Height;
-
// 一组图片中的图片数量,推荐值:10
-
int GopSize;
-
// 非B帧之间的B帧的最大数量,推荐值:1
-
int MaxBFrames;
-
// 视频码率,越高视频越清楚,相应体积也越大 如:4000000
-
float VideoBitrate;
-
// 音频采样率 如:44100
-
unsigned int SampleRate;
-
// 音频比特率 如:64000,越高声音越清楚,相应体积也越大
-
float AudioBitrate;
-
}CarEye_OriginalStream;
-
// YUV媒体流结构定义
-
#ifdef __cplusplus
-
extern "C"
-
{
-
#endif
-
/*
-
* Comments: 创建一个编码器对象
-
* Param aInfo: 要编码的媒体信息
-
* @Return CarEye_Encoder_Handle 成功返回编码器对象,否则返回NULL
-
*/
-
CE_API CarEye_Encoder_Handle CE_APICALL CarEye_EncoderCreate( CarEye_OriginalStream aInfo);
-
/*
-
* Comments: 释放编码器资源
-
* Param aEncoder: 要释放的编码器
-
* @Return None
-
*/
-
CE_API void CE_APICALL CarEye_EncoderRelease(CarEye_Encoder_Handle aEncoder);
-
/*
-
* Comments: 将输入YUV视频编码为设置好的格式数据输出
-
* Param aEncoder: 申请到的有效编码器
-
* Param aYuv: 要编码的YUV数据
-
* Param aPts: 当前视频帧序号
-
* Param aBytes: [输出]编码后的视频流
-
* @Return int < 0编码失败,> 0为编码后数据字节个数 ==0表示参数无效
-
*/
-
CE_API int CE_APICALL CarEye_EncoderYUV(CarEye_Encoder_Handle aEncoder,
-
CarEye_YUVFrame *aYuv, int aPts,
-
unsigned char *aBytes);
-
/*
-
* Comments: 获取PCM编码时接受的最大字节数
-
* Param aEncoder: 申请到的有效编码器
-
* @Return PCM编码缓冲区最大字节数
-
*/
-
CE_API int CE_APICALL CarEye_GetPcmMaxSize(CarEye_Encoder_Handle aEncoder);
-
/*
-
* Comments: 将输入的PCM音频编码为指定数据格式输出
-
* Param aEncoder: 申请到的有效编码器
-
* Param aPcm: 要编码的PCM数据
-
* Param aSize: 要编码音频流字节数
-
* Param aBytes: [输出] 编码后的音频流
-
* Param aPts: 当前编码帧的序号
-
* @Return int < 0编码失败,> 0为编码后PCM的字节个数 ==0表示参数无效
-
*/
-
CE_API int CE_APICALL CarEye_EncoderPCM(CarEye_Encoder_Handle aEncoder,
-
unsigned char *aPcm, int aSize, int aPts,
-
unsigned char *aBytes);
-
#ifdef __cplusplus
-
}
-
#endif
-
#endif
[cpp] view plain copy
-
/*
-
* Car eye 车辆管理平台: www.car-eye.cn
-
* Car eye 开源网址: https://github.com/Car-eye-team
-
* CarEyeEncoderAPI.cpp
-
*
-
* Author: Wgj
-
* Date: 2018-04-29 20:02
-
* Copyright 2018
-
*
-
* CarEye 媒体编码库接口实现
-
*/
-
#include "CarEyeEncoderAPI.h"
-
#include "FFVideoFilter.h"
-
#ifdef _WIN32
-
//Windows
-
extern "C"
-
{
-
#include "libavutil/opt.h"
-
#include "libavcodec/avcodec.h"
-
#include "libavutil/imgutils.h"
-
#include "libavformat/avformat.h"
-
#include "libswresample/swresample.h"
-
#include "libavfilter/avfilter.h"
-
};
-
#else
-
//Linux...
-
#ifdef __cplusplus
-
extern "C"
-
{
-
#endif
-
#include <libavutil/opt.h>
-
#include <libavcodec/avcodec.h>
-
#include <libavutil/imgutils.h>
-
#include <libavformat/avformat.h>
-
#include <libswresample/swresample.h>
-
#include <libavfilter/avfilter.h>
-
#ifdef __cplusplus
-
};
-
#endif
-
#endif
-
// 编码器结构体定义
-
typedef struct
-
{
-
// 视频编码器
-
AVCodecContext *VEncoder;
-
// 音频编码器
-
AVCodecContext *AEncoder;
-
// 编码后的视频帧 音视频帧对象分别定义,防止多线程分别编码音视频造成读写冲突
-
AVFrame *VFrame;
-
// 编码后的音频帧
-
AVFrame *AFrame;
-
// 音频转码器
-
struct SwrContext *AConverter;
-
// 存储PCM数据缓冲区
-
unsigned char *PcmBuffer;
-
// 接收PCM字节个数上限
-
int PcmSize;
-
// 每组PCM数据的字节数
-
int PerPcmSize;
-
// 视频字幕对象
-
}CarEyeEncoder;
-
/*
-
* Comments: 利用编码器对媒体包进行编码并输出编码后的数据
-
* Param aEncoder: 有效的编码器
-
* Param aFrame: 要编码的媒体数据包
-
* Param aPacket: [输出] 编码后的数据
-
* @Return int 小于0失败,等于0成功
-
*/
-
static int Encode(AVCodecContext *aEncoder, AVFrame *aFrame, AVPacket *aPacket)
-
{
-
int ret;
-
ret = avcodec_send_frame(aEncoder, aFrame);
-
if (ret < 0)
-
{
-
printf("Error sending a packet for encoding\n");
-
return ret;
-
}
-
ret = avcodec_receive_packet(aEncoder, aPacket);
-
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
-
{
-
return 0;
-
}
-
else if (ret < 0)
-
{
-
//error during encoding
-
return -1;
-
}
-
return ret;
-
}
-
/*
-
* Comments: 创建一个编码器对象
-
* Param aInfo: 要编码的媒体信息
-
* @Return CarEye_Encoder_Handle 成功返回编码器对象,否则返回NULL
-
*/
-
CE_API CarEye_Encoder_Handle CE_APICALL CarEye_EncoderCreate(CarEye_OriginalStream aInfo)
-
{
-
if (aInfo.OutVideoType == CAREYE_CODEC_NONE
-
&& aInfo.OutAudioType == CAREYE_CODEC_NONE)
-
{
-
CarEyeLog("null paramter\n");
-
// 至少包含一项编码需求
-
return NULL;
-
}
-
CarEyeEncoder *encoder = new CarEyeEncoder;
-
if (encoder == NULL)
-
{
-
CarEyeLog("alloc encoder fail\n");
-
return NULL;
-
}
-
memset(encoder, 0x00, sizeof(CarEyeEncoder));
-
// 注册编码器
-
av_register_all();
-
// 媒体编码器
-
AVCodec *pCodec;
-
if (aInfo.OutVideoType != CAREYE_CODEC_NONE)
-
{
-
// 请求视频编码器
-
pCodec = avcodec_find_encoder((AVCodecID)aInfo.OutVideoType);
-
if (pCodec == NULL)
-
{
-
CarEyeLog("Could not find video encoder.\n");
-
CarEye_EncoderRelease(encoder);
-
return NULL;
-
}
-
// 申请编码器上下文
-
encoder->VEncoder = avcodec_alloc_context3(pCodec);
-
if (encoder->VEncoder == NULL)
-
{
-
CarEyeLog("Could not alloc video encoder.\n");
-
CarEye_EncoderRelease(encoder);
-
return NULL;
-
}
-
encoder->VEncoder->codec_id = (AVCodecID)aInfo.OutVideoType;
-
encoder->VEncoder->time_base.num = 1;
-
// 帧率
-
encoder->VEncoder->time_base.den = aInfo.FramesPerSecond;
-
// 每包一个视频帧
-
encoder->VEncoder->frame_number = 1;
-
// 媒体类型为视频
-
encoder->VEncoder->codec_type = AVMEDIA_TYPE_VIDEO;
-
encoder->VEncoder->bit_rate = aInfo.VideoBitrate;
-
// 视频分辨率
-
encoder->VEncoder->width = aInfo.Width;
-
encoder->VEncoder->height = aInfo.Height;
-
encoder->VEncoder->gop_size = aInfo.GopSize;
-
encoder->VEncoder->max_b_frames = aInfo.MaxBFrames;
-
encoder->VEncoder->pix_fmt = (AVPixelFormat)aInfo.InVideoType;
-
AVDictionary *param = NULL;
-
//H.264
-
if (aInfo.OutVideoType == CAREYE_CODEC_H264)
-
{
-
av_dict_set(¶m, "preset", "slow", 0);
-
av_dict_set(¶m, "tune", "zerolatency", 0);
-
}
-
//H.265
-
if (aInfo.OutVideoType == CAREYE_CODEC_H265)
-
{
-
av_dict_set(¶m, "preset", "ultrafast", 0);
-
av_dict_set(¶m, "tune", "zero-latency", 0);
-
}
-
if (avcodec_open2(encoder->VEncoder, pCodec, ¶m) < 0)
-
{
-
CarEyeLog("Could not open video encoder.\n");
-
CarEye_EncoderRelease(encoder);
-
return NULL;
-
}
-
encoder->VFrame = av_frame_alloc();
-
if (encoder->VFrame == NULL)
-
{
-
CarEyeLog("Alloc video frame faile!\n");
-
CarEye_EncoderRelease(encoder);
-
return NULL;
-
}
-
encoder->VFrame->format = encoder->VEncoder->pix_fmt;
-
encoder->VFrame->width = encoder->VEncoder->width;
-
encoder->VFrame->height = encoder->VEncoder->height;
-
if (av_image_alloc(encoder->VFrame->data, encoder->VFrame->linesize,
-
encoder->VEncoder->width, encoder->VEncoder->height,
-
encoder->VEncoder->pix_fmt, 16) < 0)
-
{
-
CarEyeLog("Could not allocate raw picture buffer!\n");
-
CarEye_EncoderRelease(encoder);
-
return NULL;
-
}
-
}
-
if (aInfo.OutAudioType != CAREYE_CODEC_NONE)
-
{
-
// 请求音频编码器
-
pCodec = avcodec_find_encoder((AVCodecID)aInfo.OutAudioType);
-
if (pCodec == NULL)
-
{
-
CarEyeLog("Could not find audio encoder.\n");
-
CarEye_EncoderRelease(encoder);
-
return NULL;
-
}
-
// 申请编码器上下文
-
encoder->AEncoder = avcodec_alloc_context3(pCodec);
-
if (encoder->AEncoder == NULL)
-
{
-
CarEyeLog("Could not alloc audio encoder.\n");
-
CarEye_EncoderRelease(encoder);
-
return NULL;
-
}
-
// 参数赋值
-
encoder->AEncoder->codec_id = (AVCodecID)aInfo.OutAudioType;
-
encoder->AEncoder->codec_type = AVMEDIA_TYPE_AUDIO;
-
encoder->AEncoder->sample_fmt = AV_SAMPLE_FMT_S16P; //AV_SAMPLE_FMT_FLTP;
-
encoder->AEncoder->sample_rate = aInfo.SampleRate;
-
encoder->AEncoder->bit_rate = aInfo.AudioBitrate;
-
encoder->AEncoder->channel_layout = AV_CH_LAYOUT_STEREO; //AV_CH_LAYOUT_STEREO;
-
encoder->AEncoder->channels = av_get_channel_layout_nb_channels(encoder->AEncoder->channel_layout);
-
int ret = avcodec_open2(encoder->AEncoder, pCodec, NULL);
-
if (ret < 0)
-
{
-
CarEyeLog("Could not open audio encoder.\n");
-
CarEye_EncoderRelease(encoder);
-
return NULL;
-
}
-
encoder->AFrame = av_frame_alloc();
-
if (encoder->AFrame == NULL)
-
{
-
printf("Alloc audio frame fail!\n");
-
CarEye_EncoderRelease(encoder);
-
return NULL;
-
}
-
encoder->AFrame->nb_samples = encoder->AEncoder->frame_size;
-
encoder->AFrame->format = encoder->AEncoder->sample_fmt;
-
encoder->AFrame->channel_layout = encoder->AEncoder->channel_layout;
-
if (av_frame_get_buffer(encoder->AFrame, 0) < 0)
-
{
-
CarEyeLog("Failed to allocate the audio frame data\n");
-
CarEye_EncoderRelease(encoder);
-
return NULL;
-
}
-
encoder->PerPcmSize = av_get_bytes_per_sample(encoder->AEncoder->sample_fmt);
-
encoder->PcmSize = encoder->PerPcmSize * encoder->AEncoder->channels * encoder->AFrame->nb_samples;
-
// encoder->PcmBuffer = (uint8_t *)av_malloc(encoder->PcmSize);
-
// avcodec_fill_audio_frame(encoder->AFrame, encoder->AEncoder->channels, encoder->AEncoder->sample_fmt, (const uint8_t *)encoder->PcmBuffer, encoder->PcmSize, 1);
-
encoder->AConverter = swr_alloc();
-
if (encoder->AConverter == NULL)
-
{
-
CarEyeLog("Allock audio converter fail!\n");
-
CarEye_EncoderRelease(encoder);
-
return NULL;
-
}
-
int out_channels = av_get_default_channel_layout(encoder->AEncoder->channels);
-
encoder->AConverter = swr_alloc_set_opts(encoder->AConverter, encoder->AEncoder->channel_layout,
-
encoder->AEncoder->sample_fmt, encoder->AEncoder->sample_rate,
-
out_channels, encoder->AEncoder->sample_fmt, encoder->AEncoder->sample_rate, 0, NULL);
-
if (swr_init(encoder->AConverter) < 0)
-
{
-
CarEyeLog("Init audio converter fail!\n");
-
CarEye_EncoderRelease(encoder);
-
return NULL;
-
}
-
}
-
return encoder;
-
}
-
/*
-
* Comments: 释放编码器资源
-
* Param aEncoder: 要释放的编码器
-
* @Return None
-
*/
-
CE_API void CE_APICALL CarEye_EncoderRelease(CarEye_Encoder_Handle aEncoder)
-
{
-
CarEyeEncoder *encoder = (CarEyeEncoder *)aEncoder;
-
if (encoder == NULL)
-
{
-
return;
-
}
-
if (encoder->VEncoder != NULL)
-
{
-
avcodec_close(encoder->VEncoder);
-
av_free(encoder->VEncoder);
-
encoder->VEncoder = NULL;
-
}
-
if (encoder->AEncoder != NULL)
-
{
-
avcodec_close(encoder->AEncoder);
-
av_free(encoder->AEncoder);
-
encoder->AEncoder = NULL;
-
}
-
if (encoder->VFrame != NULL)
-
{
-
av_frame_free(&encoder->VFrame);
-
encoder->VFrame = NULL;
-
}
-
if (encoder->PcmBuffer != NULL)
-
{
-
av_freep(encoder->PcmBuffer);
-
encoder->PcmBuffer = NULL;
-
}
-
if (encoder->AFrame != NULL)
-
{
-
av_frame_free(&encoder->AFrame);
-
encoder->AFrame = NULL;
-
}
-
if (encoder->AConverter != NULL)
-
{
-
swr_free(&encoder->AConverter);
-
encoder->AConverter = NULL;
-
}
-
delete encoder;
-
encoder = NULL;
-
}
-
/*
-
* Comments: 将输入YUV视频编码为设置好的格式数据输出
-
* Param aEncoder: 申请到的有效编码器
-
* Param aYuv: 要编码的YUV数据
-
* Param aPts: 当前视频帧序号
-
* Param aBytes: [输出]编码后的视频流
-
* @Return int < 0编码失败,> 0为编码后数据字节个数 ==0表示参数无效
-
*/
-
CE_API int CE_APICALL CarEye_EncoderYUV(CarEye_Encoder_Handle aEncoder,
-
CarEye_YUVFrame *aYuv, int aPts,
-
unsigned char *aBytes)
-
{
-
CarEyeEncoder *encoder = (CarEyeEncoder *)aEncoder;
-
if (encoder == NULL || encoder->VEncoder == NULL)
-
{
-
return 0;
-
}
-
if (aBytes == NULL)
-
{
-
return 0;
-
}
-
int ret;
-
int out_size = 0;
-
AVPacket packet = { 0 };
-
av_init_packet(&packet);
-
packet.data = NULL;
-
packet.size = 0;
-
// 赋值Y值
-
memcpy(encoder->VFrame->data[0], aYuv->Y, aYuv->YSize);
-
memcpy(encoder->VFrame->data[1], aYuv->U, aYuv->USize);
-
memcpy(encoder->VFrame->data[2], aYuv->V, aYuv->VSize);
-
encoder->VFrame->pts = aPts;
-
ret = Encode(encoder->VEncoder, encoder->VFrame, &packet);
-
if (ret < 0)
-
{
-
CarEyeLog("Encode video error.\n");
-
av_packet_unref(&packet);
-
return ret;
-
}
-
out_size = packet.size;
-
if (out_size > 0)
-
{
-
memcpy(aBytes, packet.data, packet.size);
-
}
-
av_packet_unref(&packet);
-
return out_size;
-
}
-
/*
-
* Comments: 获取PCM编码时接受的最大字节数
-
* Param aEncoder: 申请到的有效编码器
-
* @Return PCM编码缓冲区最大字节数
-
*/
-
CE_API int CE_APICALL CarEye_GetPcmMaxSize(CarEye_Encoder_Handle aEncoder)
-
{
-
CarEyeEncoder *encoder = (CarEyeEncoder *)aEncoder;
-
if (encoder == NULL || encoder->AEncoder == NULL)
-
{
-
return -1;
-
}
-
return encoder->PcmSize;
-
}
-
/*
-
* Comments: 将输入的PCM音频编码为指定数据格式输出
-
* Param aEncoder: 申请到的有效编码器
-
* Param aPcm: 要编码的PCM数据
-
* Param aSize: 要编码音频流字节数
-
* Param aBytes: [输出] 编码后的音频流
-
* Param aPts: 当前编码帧的序号
-
* @Return int < 0编码失败,> 0为编码后PCM的字节个数 ==0表示参数无效
-
*/
-
CE_API int CE_APICALL CarEye_EncoderPCM(CarEye_Encoder_Handle aEncoder,
-
unsigned char *aPcm, int aSize, int aPts,
-
unsigned char *aBytes)
-
{
-
CarEyeEncoder *encoder = (CarEyeEncoder *)aEncoder;
-
if (encoder == NULL || encoder->AEncoder == NULL)
-
{
-
return 0;
-
}
-
if (aBytes == NULL || aSize < 1 || aPcm == NULL)
-
{
-
return 0;
-
}
-
int ret;
-
int out_size = 0;
-
int i = 0, j = 0;
-
int cp_count = 0;
-
AVPacket packet = { 0 };
-
av_init_packet(&packet);
-
packet.data = NULL;
-
packet.size = 0;
-
for (i = 0; i < encoder->AFrame->nb_samples; i++)
-
{
-
for (j = 0; j < encoder->AEncoder->channels; j++)
-
{
-
memcpy(encoder->AFrame->data[j] + i * encoder->PerPcmSize, aPcm, encoder->PerPcmSize);
-
cp_count += encoder->PerPcmSize;
-
if (cp_count >= aSize)
-
{
-
break;
-
}
-
}
-
}
-
encoder->AFrame->pts = aPts;
-
ret = Encode(encoder->AEncoder, encoder->AFrame, &packet);
-
if (ret < 0)
-
{
-
printf("Decode audio error.\n");
-
av_packet_unref(&packet);
-
return ret;
-
}
-
out_size = packet.size;
-
if (out_size > 0)
-
{
-
memcpy(aBytes, packet.data, packet.size);
-
}
-
av_packet_unref(&packet);
-
return out_size;
-
}
以上库是支持音视频编码的。我们本节只说明视频编码部分。给出视频编码的JNI接口
[cpp] view plain copy
-
typedef struct{
-
int InVedioType;
-
int OutVedioType;
-
int fps;
-
int width;
-
int height;
-
int VideoBitrate;
-
int InputAuidoType;
-
int OutAudioType;
-
int SampleRate;
-
int AudioBitrate;
-
int Encodetype;
-
}ParamInfo;
-
JNIEXPORT jlong JNICALL Java_com_CarEye_CarEyelib_ffmpegandroid_FFmpegNative_CreateEncode(JNIEnv* env, jobject obj, jobject para) {
-
void* ret;
-
CarEye_OriginalStream param;
-
jclass jcInfo = (*env)->GetObjectClass(env, para);
-
if (0 == jcInfo) {
-
CarEyeLog("GetObjectClass returned 0\n");
-
return 0;
-
}
-
int fps = (*env)->GetIntField(env, para, (*env)->GetFieldID(env, jcInfo, "fps", "I"));
-
int InVedioType = (*env)->GetIntField(env, para,(*env)->GetFieldID(env, jcInfo, "InVedioType", "I"));
-
int OutVedioType =(*env)->GetIntField(env, para,(*env)->GetFieldID(env, jcInfo, "OutVedioType", "I"));
-
int width = (*env)->GetIntField(env, para,(*env)->GetFieldID(env, jcInfo, "width", "I"));
-
int height = (*env)->GetIntField(env, para,(*env)->GetFieldID(env, jcInfo, "height", "I"));
-
int VideoBitrate = (*env)->GetIntField(env, para,(*env)->GetFieldID(env, jcInfo, "VideoBitrate", "I"));
-
int InputAuidoType = (*env)->GetIntField(env, para,(*env)->GetFieldID(env, jcInfo, "InputAuidoType", "I"));
-
int OutAudioType = (*env)->GetIntField(env, para,(*env)->GetFieldID(env, jcInfo, "OutAudioType", "I"));
-
int SampleRate = (*env)->GetIntField(env, para,(*env)->GetFieldID(env, jcInfo, "SampleRate", "I"));
-
int AudioBitrate=(*env)->GetIntField(env, para,(*env)->GetFieldID(env, jcInfo, "AudioBitrate", "I"));
-
CarEyeLog("fps:%d", fps);
-
CarEyeLog("InVedioType:%d", InVedioType);
-
CarEyeLog("width:%d,VideoBitrate:%d,OutVedioType:%d ", width,VideoBitrate,OutVedioType);
-
param.AudioBitrate = AudioBitrate;
-
param.InVideoType = InVedioType;
-
param.OutAudioType = OutAudioType;
-
param.OutVideoType = OutVedioType;
-
param.FramesPerSecond = fps;
-
param.GopSize = 10;
-
param.MaxBFrames =1;
-
param.Width = width;
-
param.Height = height;
-
param.VideoBitrate =VideoBitrate;
-
param.SampleRate = SampleRate;
-
ret = CarEye_EncoderCreate(param);
-
if( ret == NULL) {
-
return 0;
-
}else
-
{
-
return (long)ret;
-
}
-
}
-
JNIEXPORT jint JNICALL Java_com_CarEye_CarEyelib_ffmpegandroid_FFmpegNative_encode(JNIEnv* env, jobject obj, jlong handle,jint index, jbyteArray frame, jbyteArray OutFrame) {
-
void* pHandle;
-
int ret;
-
unsigned char* in_data;
-
unsigned char* out_data;
-
CarEye_YUVFrame yuv_frame;
-
if(handle==0)
-
return -1;
-
pHandle = (void*)handle;
-
in_data = (*env)->GetByteArrayElements(env,frame, 0 );
-
int len = (*env)->GetArrayLength(env,frame);
-
out_data = (*env)->GetByteArrayElements(env,OutFrame, 0 );
-
yuv_frame.Y = in_data;
-
yuv_frame.YSize = len*2/3;
-
yuv_frame.U = &in_data[len*2/3];
-
yuv_frame.USize = len/6;
-
yuv_frame.V = &in_data[len*5/6];
-
yuv_frame.VSize = len/6;
-
ret = CarEye_EncoderYUV(pHandle, &yuv_frame, index,out_data );
-
(*env)->ReleaseByteArrayElements(env,frame,in_data,0);
-
(*env)->ReleaseByteArrayElements(env,OutFrame,out_data,0);
-
return ret;
-
}
-
JNIEXPORT jint JNICALL Java_com_CarEye_CarEyelib_ffmpegandroid_FFmpegNative_ReleaseEncode(JNIEnv* env, jobject obj, jlong handle) {
-
void* pHandle;
-
if(handle==0)
-
return -1;
-
pHandle = (void*)handle;
-
CarEye_EncoderRelease(pHandle);
-
return 0;
-
}
注意的是,参数传递了一个结构体进来,对应JAVA层需要传递一个类:给出java的类,和调用代码
public class EncodeParamInfo { int InVedioType; int OutVedioType; int fps; int width; int height; int VideoBitrate; int InputAuidoType; int OutAudioType; int SampleRate; int AudioBitrate; int Encodetype; };
[java] view plain copy
-
void TestEncode() {
-
new Thread(new Runnable() {
-
@Override
-
public void run() {
-
int loop = 0;
-
FileOutputStream out;
-
FileInputStream in;
-
FFmpegNative ffmpeg = new FFmpegNative();
-
EncodeParamInfo info = new EncodeParamInfo();
-
info.fps = 25;
-
info.width = 1280;
-
info.height = 720;
-
info.InVedioType = 0;
-
info.OutVedioType = 0x1C;
-
info.InputAuidoType = 0;
-
info.VideoBitrate = 3000000;
-
long handle = ffmpeg.InitEncode(info);
-
if (handle == 0) {
-
Log.d(TAG, "init encoder fail");
-
}
-
Log.d(TAG, "init encoder success");
-
byte[] data = new byte[1280 * 720 * 3 / 2];
-
byte[] out_data = new byte[1280 * 720 * 3 / 2];
-
try {
-
File f = new File("/mnt/sdcard/out.h264");
-
if (f.exists()) f.delete();
-
f.createNewFile();
-
out = new FileOutputStream(f);
-
File input = new File("/mnt/sdcard/input.yuv");
-
in = new FileInputStream(input);
-
int len;
-
while (true) {
-
if (in.read(data, 0, 1280 * 720 * 3 / 2) < 0) {
-
Log.d(TAG, "read fail:");
-
break;
-
} else {
-
int result = ffmpeg.EncodeData(handle, loop++, data, out_data);
-
if (result > 0) {
-
out.write(out_data, 0, result);
-
Log.d(TAG, "encoder sucessful:"+result);
-
}else {
-
Log.d(TAG, "encoder fail:"+result);
-
}
-
}
-
}
-
in.close();
-
out.close();
-
ffmpeg.DestroyEncode(handle);
-
} catch (Exception e) {
-
e.printStackTrace();
-
}
-
}
-
}).start();
-
}
相关代码请参考car-eye 开源网站和github为准
car-eye开源官方网址:www.car-eye.cn
car-eye 流媒体平台网址:www.liveoss.com
car-eye 技术官方邮箱: support@car-eye.cn
car-eye技术交流QQ群: 590411159
CopyRight© car-eye 开源团队 2018