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