FFMPEG 視頻編碼最多見的H264,H265須要X264,X265外部模塊支持,能夠從咱們開源平臺的FFMPEG編譯項目裏面獲取代碼和配置進行一鍵式編譯:https://github.com/Car-eye-team/Car-eye-FFMPEG,咱們下面的代碼主要是爲了簡化代碼調用結構。只須要配置參數,輸入數據就能夠進行視頻編碼,很少說,貼上代碼:java
[cpp] view plain copyandroid
- /*
- * 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 copygit
- /*
- * 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接口github
[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的類,和調用代碼app
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 copyide
- 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爲準oop
car-eye開源官方網址:www.car-eye.cn 網站
car-eye 流媒體平臺網址:www.liveoss.com ui
car-eye 技術官方郵箱: support@car-eye.cn
car-eye技術交流QQ羣: 590411159
CopyRight© car-eye 開源團隊 2018