FFMEPG 平台移植,接口简化和外部模块接入 (三)ffmpeg android移植(ffmpeg实现水印文字显示)



首先来看一副图,用来纪念对视频领域做出贡献的雷神:

当然在这个图片里面的decode不是必须的,Filter 模块本身是一个非常独立的模块,但因为相关的程序,给人造成了他必须要依赖于编码器或者解码器来工作。

OK 不多说,先看看内部实现代码:

[cpp]  view plain  copy
  1. #ifndef __CAREYE_PUBLIC_H__  
  2. #define __CAREYE_PUBLIC_H__  
  3.   
  4. #define __STDC_CONSTANT_MACROS  
  5. #ifdef _WIN32  
  6. #define CE_API  __declspec(dllexport)  
  7. #define CE_APICALL  __stdcall  
  8. #else  
  9. #define CE_API  
  10. #define CE_APICALL   
  11. #endif  
  12.   
  13. #ifndef _WIN32  
  14. #define _ANDROID_  
  15. #endif  
  16.   
  17. #ifdef _ANDROID_  
  18.   
  19. #include <android/log.h>  
  20.   
  21. #define CarEyeLog(...) __android_log_print(ANDROID_LOG_DEBUG, "Car-eye-ffmpeg", __VA_ARGS__)  
  22.   
  23. #else  
  24.   
  25. #define CarEyeLog   printf  
  26. #endif  
  27.   
  28.   
  29.   
  30. typedef struct _CarEye_YUVFrame_  
  31. {  
  32.     // Y分量数据存储区  
  33.     unsigned char *Y;  
  34.     // Y分量数据字节数  
  35.     int YSize;  
  36.     // U分量数据存储区  
  37.     unsigned char *U;  
  38.     // U分量数据字节数  
  39.     int USize;  
  40.     // V分量数据存储区  
  41.     unsigned char *V;  
  42.     // V分量数据字节数  
  43.     int VSize;  
  44. }CarEye_YUVFrame;  
  45.   
  46.   
  47.   
  48. //error number  
  49. #define NO_ERROR                    0  
  50. #define PARAMTER_ERROR      1  
  51. #define NULL_MEMORY             2  
  52.   
  53. #define MAX_FILTER_DESCR 512  
  54.   
  55. #endif  

[cpp]  view plain  copy
  1. #ifndef __CAREYE_FILTER_INTERFACE_H__  
  2. #define __CAREYE_FILTER_INTERFACE_H__  
  3.   
  4.   
  5. #define MAX_STRING_LENGTH 1024  
  6. #define MAX_FILE_NAME 64  
  7. // OSD水印结果定义  
  8. typedef struct _CarEye_OSDParam_  
  9. {  
  10.     int width;  
  11.     int height;  
  12.     int fps;  
  13.     // 起始X轴坐标  
  14.     int X;  
  15.     // 起始Y轴坐标  
  16.     int Y;  
  17.     // 字体大小  
  18.     int FontSize;  
  19.     // 16进制的RGB颜色值,如绿色:0x00FF00  
  20.     unsigned int FontColor;  
  21.     // 水印透明度 0~1  
  22.     float Transparency;  
  23.     // 水印内容  
  24.     char SubTitle[MAX_STRING_LENGTH];  
  25.     // 字体名称,字体文件放到库的同目录下,如“arial.ttf”  
  26.     char FontName[MAX_FILE_NAME];  
  27. }CarEye_OSDParam;  
  28.   
  29.   
  30. typedef struct  
  31. {  
  32.     AVFrame *VFrame;  
  33.     // 编码后的音频帧    
  34.     CarEye_OSDParam para;  
  35.     void* handle;  
  36. }CarEyeFilter;  
  37.   
  38.   
  39. #ifdef __cplusplus  
  40. extern "C"  
  41. {  
  42. #endif  
  43.     /* 
  44.     * Comments: 打开水印资源 
  45.     * Param aEncoder: 编码器对象句柄 
  46.     * Param aParam: 水印参数 
  47.     * @Return int 是否成功,0成功,其他失败 
  48.     */  
  49.     CE_API int CE_APICALL CarEye_OpenOsd(CarEyeFilter* pFilter, CarEye_OSDParam aParam);  
  50.   
  51.     /* 
  52.     * Comments: 关闭水印资源 
  53.     * Param aDeocoder: 编码器对象 
  54.     * @Return int 关闭成功与否 0成功 
  55.     */  
  56.     CE_API int CE_APICALL CarEye_CloseOsd(CarEyeFilter* pFilter);  
  57.   
  58.     CE_API int CE_APICALL CarEye_add_osd(CarEyeFilter* pFilter, CarEye_YUVFrame *aYuv, CarEye_OSDParam aParam);  
  59. #ifdef __cplusplus  
  60. }  
  61. #endif  
  62.       
  63. #endif  


实现部分代码:

[cpp]  view plain  copy
  1. #include "FFVideoFilter.h"  
  2.   
  3.   
  4. /* 
  5. * Comments: 打开水印资源 
  6. * Param aEncoder: 编码器对象句柄 
  7. * Param aParam: 水印参数 
  8. * @Return int 是否成功,0成功,其他失败 
  9. */  
  10.   
  11. CE_API int CE_APICALL CarEye_OpenOsd( CarEyeFilter* pFliter, CarEye_OSDParam aParam)  
  12. {  
  13.     if(pFliter==NULL)  
  14.     {  
  15.         return -PARAMTER_ERROR;  
  16.     }  
  17.     avfilter_register_all();  
  18.     pFliter->VFrame = NULL;  
  19.     pFliter->VFrame = av_frame_alloc();  
  20.     if(pFliter->VFrame ==   NULL)  
  21.     {         
  22.         return -NULL_MEMORY;  
  23.     }         
  24.     pFliter->VFrame->width = aParam.width;  
  25.     pFliter->VFrame->height = aParam.height;  
  26.     pFliter->VFrame->pts = 0;   
  27.     if (av_image_alloc(pFliter->VFrame->data, pFliter->VFrame->linesize,  
  28.     pFliter->VFrame->width,  pFliter->VFrame->height,  
  29.     AV_PIX_FMT_YUV420P, 16) < 0)  
  30.     {  
  31.         CarEyeLog("Cannot av_image_alloc\n");  
  32.         av_frame_free(&pFliter->VFrame);  
  33.         return -NULL_MEMORY;  
  34.     }  
  35.     pFliter->VFrame->format = AV_PIX_FMT_YUV420P;  
  36.     FFVideoFilter *handle = new FFVideoFilter();  
  37.     pFliter->handle =(FFVideoFilter*)handle;   
  38.     return handle->InitFilters( aParam);  
  39. }  
  40.   
  41.   
  42. CE_API int CE_APICALL CarEye_add_osd(CarEyeFilter* pFliter, CarEye_YUVFrame *aYuv,CarEye_OSDParam param)  
  43. {  
  44.     if(pFliter==NULL || pFliter->VFrame == NULL)  
  45.     {  
  46.           return -PARAMTER_ERROR;  
  47.     }     
  48.     FFVideoFilter* handle = (FFVideoFilter*)pFliter->handle;  
  49.       pFliter->VFrame->pts++;  
  50.       memcpy(pFliter->VFrame->data[0], aYuv->Y, aYuv->YSize);  
  51.     memcpy(pFliter->VFrame->data[1], aYuv->U, aYuv->USize);  
  52.     memcpy(pFliter->VFrame->data[2], aYuv->V, aYuv->VSize);         
  53.     if (handle->BlendFilters(pFliter->VFrame,param) < 0)  
  54.     {         
  55.         return -PARAMTER_ERROR;  
  56.     }  
  57.     memcpy(aYuv->Y, pFliter->VFrame->data[0], aYuv->YSize);  
  58.     memcpy(aYuv->U, pFliter->VFrame->data[1],  aYuv->USize);  
  59.     memcpy(aYuv->V, pFliter->VFrame->data[2],  aYuv->VSize);  
  60.     return NO_ERROR;  
  61. }  
  62. /* 
  63. * Comments: 关闭水印资源 
  64. * Param aDeocoder: 编码器对象 
  65. * @Return int 关闭成功与否 0 成功 
  66. */  
  67. CE_API int CE_APICALL CarEye_CloseOsd(CarEyeFilter* pFliter)  
  68. {  
  69.     FFVideoFilter* handle = (FFVideoFilter*)pFliter->handle;  
  70.   if(pFliter->VFrame != NULL)  
  71.   {  
  72.       av_frame_free(&pFliter->VFrame);  
  73.   }  
  74.     delete handle;  
  75.     return NO_ERROR;  


[cpp]  view plain  copy
  1. #include "FFVideoFilter.h"  
  2.   
  3.   
  4. /* 
  5. * Comments: 打开水印资源 
  6. * Param aEncoder: 编码器对象句柄 
  7. * Param aParam: 水印参数 
  8. * @Return int 是否成功,0成功,其他失败 
  9. */  
  10.   
  11. CE_API int CE_APICALL CarEye_OpenOsd( CarEyeFilter* pFliter, CarEye_OSDParam aParam)  
  12. {  
  13.     if(pFliter==NULL)  
  14.     {  
  15.         return -PARAMTER_ERROR;  
  16.     }  
  17.     avfilter_register_all();  
  18.     pFliter->VFrame = NULL;  
  19.     pFliter->VFrame = av_frame_alloc();  
  20.     if(pFliter->VFrame ==   NULL)  
  21.     {         
  22.         return -NULL_MEMORY;  
  23.     }         
  24.     pFliter->VFrame->width = aParam.width;  
  25.     pFliter->VFrame->height = aParam.height;  
  26.     pFliter->VFrame->pts = 0;   
  27.     if (av_image_alloc(pFliter->VFrame->data, pFliter->VFrame->linesize,  
  28.     pFliter->VFrame->width,  pFliter->VFrame->height,  
  29.     AV_PIX_FMT_YUV420P, 16) < 0)  
  30.     {  
  31.         CarEyeLog("Cannot av_image_alloc\n");  
  32.         av_frame_free(&pFliter->VFrame);  
  33.         return -NULL_MEMORY;  
  34.     }  
  35.     pFliter->VFrame->format = AV_PIX_FMT_YUV420P;  
  36.     FFVideoFilter *handle = new FFVideoFilter();  
  37.     pFliter->handle =(FFVideoFilter*)handle;   
  38.     return handle->InitFilters( aParam);  
  39. }  
  40.   
  41.   
  42. CE_API int CE_APICALL CarEye_add_osd(CarEyeFilter* pFliter, CarEye_YUVFrame *aYuv,CarEye_OSDParam param)  
  43. {  
  44.     if(pFliter==NULL || pFliter->VFrame == NULL)  
  45.     {  
  46.           return -PARAMTER_ERROR;  
  47.     }     
  48.     FFVideoFilter* handle = (FFVideoFilter*)pFliter->handle;  
  49.       pFliter->VFrame->pts++;  
  50.       memcpy(pFliter->VFrame->data[0], aYuv->Y, aYuv->YSize);  
  51.     memcpy(pFliter->VFrame->data[1], aYuv->U, aYuv->USize);  
  52.     memcpy(pFliter->VFrame->data[2], aYuv->V, aYuv->VSize);         
  53.     if (handle->BlendFilters(pFliter->VFrame,param) < 0)  
  54.     {         
  55.         return -PARAMTER_ERROR;  
  56.     }  
  57.     memcpy(aYuv->Y, pFliter->VFrame->data[0], aYuv->YSize);  
  58.     memcpy(aYuv->U, pFliter->VFrame->data[1],  aYuv->USize);  
  59.     memcpy(aYuv->V, pFliter->VFrame->data[2],  aYuv->VSize);  
  60.     return NO_ERROR;  
  61. }  
  62. /* 
  63. * Comments: 关闭水印资源 
  64. * Param aDeocoder: 编码器对象 
  65. * @Return int 关闭成功与否 0 成功 
  66. */  
  67. CE_API int CE_APICALL CarEye_CloseOsd(CarEyeFilter* pFliter)  
  68. {  
  69.     FFVideoFilter* handle = (FFVideoFilter*)pFliter->handle;  
  70.   if(pFliter->VFrame != NULL)  
  71.   {  
  72.       av_frame_free(&pFliter->VFrame);  
  73.   }  
  74.     delete handle;  
  75.     return NO_ERROR;  
  76. }  

在写JNI之前先看下make文件,主要有两个,android.mk用来实现对ffmpeg 库和新增加的外部水印库的编译,application.mk 主要定义编译的全局变量,如参数和架构等,看下怎么编译ffmpeg的动态库的,这里我们没有用到FFMPEG的avdevice这个库。

#APP_ABI := armeabi armeabi-v7a x86
ifeq ($(APP_ABI), x86)
LIB_NAME_PLUS := x86
else
LIB_NAME_PLUS := armeabi
endif

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE:= avcodec-prebuilt-$(LIB_NAME_PLUS)
LOCAL_SRC_FILES:= prebuilt/$(LIB_NAME_PLUS)/libavcodec-57.so
include $(PREBUILT_SHARED_LIBRARY)


include $(CLEAR_VARS)
LOCAL_MODULE:= avfilter-prebuilt-$(LIB_NAME_PLUS)
LOCAL_SRC_FILES:= prebuilt/$(LIB_NAME_PLUS)/libavfilter-6.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE:= avformat-prebuilt-$(LIB_NAME_PLUS)
LOCAL_SRC_FILES:= prebuilt/$(LIB_NAME_PLUS)/libavformat-57.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE :=  avutil-prebuilt-$(LIB_NAME_PLUS)
LOCAL_SRC_FILES := prebuilt/$(LIB_NAME_PLUS)/libavutil-55.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := swresample-prebuilt-$(LIB_NAME_PLUS)
LOCAL_SRC_FILES := prebuilt/$(LIB_NAME_PLUS)/libswresample-2.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := swscale-prebuilt-$(LIB_NAME_PLUS)
LOCAL_SRC_FILES := prebuilt/$(LIB_NAME_PLUS)/libswscale-4.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
ifeq ($(APP_ABI), x86)
TARGET_ARCH:=x86
TARGET_ARCH_ABI:=x86
else
LOCAL_ARM_MODE := arm
endif

LOCAL_MODULE := libffmpegjni
LOCAL_SRC_FILES := com_li_sheldon_ffmpeg4android_FFmpegNative.c CarEyeEncoderAPI.cpp FFVideoFilter.cpp  CarEyeFilter_interface.cpp
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog -lz
LOCAL_SHARED_LIBRARIES:= avcodec-prebuilt-$(LIB_NAME_PLUS) \
                         avfilter-prebuilt-$(LIB_NAME_PLUS) \
                         avformat-prebuilt-$(LIB_NAME_PLUS) \
                         avutil-prebuilt-$(LIB_NAME_PLUS) \
                         swresample-prebuilt-$(LIB_NAME_PLUS) \
                         swscale-prebuilt-$(LIB_NAME_PLUS)
LOCAL_C_INCLUDES += -L$(SYSROOT)/usr/include
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include

ifeq ($(APP_ABI), x86)
LOCAL_CFLAGS := -DUSE_X86_CONFIG
else
LOCAL_CFLAGS := -DUSE_ARM_CONFIG
endif
include $(BUILD_SHARED_LIBRARY)

编译后生成libffmpegjni.so, 然后提供JNI的源码给上层调用:

[cpp]  view plain  copy
  1. (1)JNIEXPORT :在Jni编程中所有本地语言实现Jni接口的方法前面都有一个"JNIEXPORT",这个可以看做是Jni的一个标志,至今为止没发现它有什么特殊的用处。  
  2.   
  3. (2)jint :这个学过编程的人都知道,当然是方法的返回值了。  
  4.   
  5. (3)JNICALL :这个可以理解为Jni 和Call两个部分,和起来的意思就是 Jni调用XXX(后面的XXX就是JAVA的方法名)。  
  6.   
  7. (4)Java_com_test01_Test_firstTest:这个就是被上一步中被调用的部分,也就是Java中的native 方法名,这里起名字的方式比较特别,是:包名+类名+方法名。  
  8.   
  9. (5)JNIEnv * env:这个env可以看做是Jni接口本身的一个对象,在上一篇中提到的jni.h头文件中存在着大量被封装好的函数,这些函数也是Jni编程中经常被使用到的,要想调用这些函数就需要使用JNIEnv这个对象。例如:env->GetObjectClass()。(详情请查看jni.h)  
  10.   
  11. (6)jobject obj:刚才在Test类的main方法中有这样一段代码:   
  12. */  
  13.   
  14. /* DO NOT EDIT THIS FILE - it is machine generated */  
  15. #include "com_li_sheldon_ffmpeg4android_FFmpegNative.h"  
  16. /* Header for class com_hsb_ffmpeg_FFmpegNative */  
  17. #include "libavcodec/avcodec.h"  
  18. #include "libavcodec/avdct.h"  
  19. #include "libavcodec/avfft.h"  
  20. #include "libavcodec/dirac.h"  
  21. #include "libavcodec/dv_profile.h"  
  22. #include "libavcodec/vaapi.h"  
  23. #include "libavcodec/version.h"  
  24. #include "libavcodec/vorbis_parser.h"  
  25.   
  26. #include "libavdevice/avdevice.h"  
  27. #include "libavdevice/version.h"  
  28.   
  29. #include "libavfilter/avfilter.h"  
  30. #include "libavfilter/avfiltergraph.h"  
  31. #include "libavfilter/buffersink.h"  
  32. #include "libavfilter/buffersrc.h"  
  33. #include "libavfilter/version.h"  
  34.   
  35. #include "libavformat/avformat.h"  
  36. #include "libavformat/avio.h"  
  37. #include "libavformat/version.h"  
  38.   
  39. #include "libavutil/adler32.h"  
  40. #include "libavutil/aes_ctr.h"  
  41. #include "libavutil/aes.h"  
  42. #include "libavutil/attributes.h"  
  43. #include "libavutil/audio_fifo.h"  
  44. #include "libavutil/avassert.h"  
  45. #include "libavutil/avconfig.h"  
  46. #include "libavutil/avstring.h"  
  47. #include "libavutil/avutil.h"  
  48. #include "libavutil/base64.h"  
  49. #include "libavutil/blowfish.h"  
  50. #include "libavutil/bprint.h"  
  51. #include "libavutil/bswap.h"  
  52. #include "libavutil/buffer.h"  
  53. #include "libavutil/camellia.h"  
  54. #include "libavutil/cast5.h"  
  55. #include "libavutil/channel_layout.h"  
  56. #include "libavutil/common.h"  
  57. #include "libavutil/cpu.h"  
  58. #include "libavutil/crc.h"  
  59. #include "libavutil/des.h"  
  60. #include "libavutil/dict.h"  
  61. #include "libavutil/display.h"  
  62. #include "libavutil/downmix_info.h"  
  63. #include "libavutil/error.h"  
  64. #include "libavutil/eval.h"  
  65. #include "libavutil/ffversion.h"  
  66. #include "libavutil/fifo.h"  
  67. #include "libavutil/file.h"  
  68. #include "libavutil/frame.h"  
  69. #include "libavutil/hash.h"  
  70. #include "libavutil/hmac.h"  
  71. #include "libavutil/imgutils.h"  
  72. #include "libavutil/intfloat.h"  
  73. #include "libavutil/intreadwrite.h"  
  74. #include "libavutil/lfg.h"  
  75. #include "libavutil/log.h"  
  76. #include "libavutil/lzo.h"  
  77. #include "libavutil/macros.h"  
  78. #include "libavutil/mastering_display_metadata.h"  
  79. #include "libavutil/mathematics.h"  
  80. #include "libavutil/md5.h"  
  81. #include "libavutil/mem.h"  
  82. #include "libavutil/motion_vector.h"  
  83. #include "libavutil/murmur3.h"  
  84. #include "libavutil/opt.h"  
  85. #include "libavutil/parseutils.h"  
  86. #include "libavutil/pixdesc.h"  
  87. #include "libavutil/pixelutils.h"  
  88. #include "libavutil/pixfmt.h"  
  89. #include "libavutil/random_seed.h"  
  90. #include "libavutil/rational.h"  
  91. #include "libavutil/rc4.h"  
  92. #include "libavutil/replaygain.h"  
  93. #include "libavutil/ripemd.h"  
  94. #include "libavutil/samplefmt.h"  
  95. #include "libavutil/sha.h"  
  96. #include "libavutil/sha512.h"  
  97. #include "libavutil/stereo3d.h"  
  98. #include "libavutil/tea.h"  
  99. #include "libavutil/threadmessage.h"  
  100. #include "libavutil/time.h"  
  101. #include "libavutil/timecode.h"  
  102. #include "libavutil/timestamp.h"  
  103. #include "libavutil/tree.h"  
  104. #include "libavutil/twofish.h"  
  105. #include "libavutil/version.h"  
  106. #include "libavutil/xtea.h"  
  107. #include "libswresample/swresample.h"  
  108. #include "libswresample/version.h"  
  109. #include "libswscale/swscale.h"  
  110. #include "libswscale/version.h"  
  111. #include "CarEyeEncoderAPI.h"  
  112. #include "CarEyeFilter_interface.h"  
  113.   
  114. #include <android/log.h>  
  115. #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "ffmpeg4android", __VA_ARGS__)  
  116.   
  117. JNIEXPORT jint JNICALL Java_com_li_sheldon_ffmpeg4android_FFmpegNative_ffmpeg_1h264  
  118.   (JNIEnv* env, jobject obj, jint codecID)  
  119.  {  
  120.     AVCodec* codec = NULL;  
  121.     av_register_all();//该函数在所有基于ffmpeg的应用程序中几乎都是第一个被调用的。只有调用了该函数,才能使用复用器,编码器等  
  122.     codec = avcodec_find_decoder(codecID);//通过code ID查找一个已经注册的音视频编码器。H264的codecID是28,所以我们java那边传28下来如果检测到H264注册过了这边codec就不为空,返回0  
  123.     if(codec != NULL){  
  124.       return 0;  
  125.     }else{  
  126.       return -1;  
  127.     }  
  128. }  
  129. CarEyeFilter gFliter;  
  130.   
  131. JNIEXPORT jint JNICALL Java_com_li_sheldon_ffmpeg4android_FFmpegNative_OpenOSD(JNIEnv* env, jobject obj, jint width, jint height, jint startX, jint startY, jint FontSize,  jint color, jstring  filename, jstring content  )  
  132. {  
  133.     char* Name;  
  134.     char* pContent;  
  135.     gFliter.para.X = startX;  
  136.     gFliter.para.Y = startY;  
  137.     gFliter.para.width = width;  
  138.     gFliter.para.height = height;  
  139.     gFliter.para.FontSize = FontSize;  
  140.     gFliter.para.FontColor = color;  
  141.     gFliter.para.fps = 25;  
  142.     Name=(*env)->GetStringUTFChars(env,filename, JNI_FALSE);  
  143.     pContent=(*env)->GetStringUTFChars(env,content, JNI_FALSE);  
  144.     strcpy(gFliter.para.FontName, Name);  
  145.     strcpy(gFliter.para.SubTitle, pContent);      
  146.     gFliter.para.Transparency = 0.7;       
  147.     (*env)->ReleaseStringUTFChars(env, filename, Name);  
  148.     (*env)->ReleaseStringUTFChars(env, content, pContent);                 
  149.     return CarEye_OpenOsd(&gFliter, gFliter.para);  
  150. }  
  151.   
  152. JNIEXPORT jint JNICALL Java_com_li_sheldon_ffmpeg4android_FFmpegNative_CloseOSD(JNIEnv* env, jobject obj)  
  153. {         
  154.     return CarEye_CloseOsd(&gFliter);  
  155. }  
  156.   
  157. JNIEXPORT jint JNICALL Java_com_li_sheldon_ffmpeg4android_FFmpegNative_AddOSD(JNIEnv* env, jobject obj, jbyteArray frame, jstring txtoverlay)  
  158. {  
  159.     unsigned char * pBuffer;  
  160.     int ret;  
  161.     char *txt;  
  162.     CarEye_YUVFrame yuv_frame;  
  163.     pBuffer = (*env)->GetByteArrayElements(env,frame, 0 );  
  164.     int len = (*env)->GetArrayLength(env,frame);       
  165.     yuv_frame.Y = pBuffer;  
  166.     yuv_frame.YSize = len*2/3;  
  167.     yuv_frame.U = &pBuffer[len*2/3];  
  168.     yuv_frame.USize = len/6;  
  169.     yuv_frame.V = &pBuffer[len*5/6];  
  170.     yuv_frame.VSize = len/6;  
  171.     txt = (*env)->GetStringUTFChars(env,txtoverlay, JNI_FALSE);  
  172.     strcpy(gFliter.para.SubTitle, txt);      
  173.     ret = CarEye_add_osd(&gFliter,&yuv_frame,gFliter.para);          
  174.    (*env)->ReleaseStringUTFChars(env, txtoverlay, txt);       
  175.    (*env)->ReleaseByteArrayElements(env,frame,pBuffer,0);  
  176.    return ret;  
  177. }  

OK, 写一个简单例子测试下:

[java]  view plain  copy
  1. package com.li.sheldon.ffmpeg4android;  
  2.   
  3. import android.util.Log;  
  4.   
  5. /** 
  6.  * Created by sheldon on 17-1-4. 
  7.  */  
  8. public class FFmpegNative {  
  9.   
  10.     static{  
  11.         System.loadLibrary("avcodec-57");  
  12.         System.loadLibrary("avfilter-6");  
  13.         System.loadLibrary("avformat-57");  
  14.         System.loadLibrary("avutil-55");  
  15.         System.loadLibrary("swresample-2");  
  16.         System.loadLibrary("swscale-4");  
  17.         System.loadLibrary("ffmpegjni");  
  18.     }  
  19.     private native int AddOSD(byte[] buffer, String txt);  
  20.     private native int CloseOSD();  
  21.     private native int OpenOSD(int width, int height, int startX, int startY, int fontsize, int color, String  filename, String  content);  
  22.     private native int ffmpeg_h264(int id);  
  23.   
  24.     public int test_h246(int id){  
  25.         return ffmpeg_h264(id);  
  26.     }  
  27.     public int InitOSD(int width, int height, int startX, int startY, int fontsize, int color, String  filename, String  content)  
  28.     {  
  29.          return OpenOSD(width,height,startX,startY,fontsize,color, filename,content );  
  30.     }  
  31.     public int DelOSD()  
  32.     {  
  33.         return CloseOSD();  
  34.     }  
  35.     public int blendOSD(byte[] buffer,String txt)  
  36.     {  
  37.         return AddOSD(buffer,txt);  
  38.     }  
  39.   
  40. }  

[cpp]  view plain  copy
  1. package com.li.sheldon.ffmpeg4android;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5. import android.util.Log;  
  6. import android.widget.TextView;  
  7.   
  8. import java.io.File;  
  9. import java.io.FileInputStream;  
  10. import java.io.FileNotFoundException;  
  11. import java.io.FileOutputStream;  
  12. import java.io.IOException;  
  13. import java.text.SimpleDateFormat;  
  14. import java.util.Date;  
  15.   
  16. public class MainActivity extends Activity {  
  17.     @Override  
  18.     protected void onCreate(Bundle savedInstanceState) {  
  19.         super.onCreate(savedInstanceState);  
  20.         setContentView(R.layout.activity_main);  
  21.         int codec_id = 28;  
  22.         final FFmpegNative ffmpeg = new FFmpegNative();  
  23.         int tmp = ffmpeg.test_h246(codec_id); //28 is the H264 Codec ID  
  24.         TextView tv = (TextView) this.findViewById(R.id.hello_ffmpeg);  
  25.         tv.setText(tmp == 0 ? "Support Codec ID:" + codec_id : "Not support Codec ID:" + codec_id);  
  26.         Log.d("ffmpeg4android""OSD init start: ");  
  27.         new Thread(new Runnable() {  
  28.             @Override  
  29.             public void run() {  
  30.                 int loop = 0;  
  31.                 FileOutputStream out;  
  32.                 FileInputStream in;  
  33.                 FFmpegNative ffmpeg = new FFmpegNative();  
  34.                 int ret = ffmpeg.InitOSD(1280, 720, 10, 10, 28, 0x00ff00, String.format("/mnt/sdcard/arial.ttf"), String.format("ddddd"));  
  35.                 if (ret != 0) {  
  36.                     Log.d("ffmpeg4android""OSD init fail: "+ret);  
  37.                 }  
  38.                 Log.d("ffmpeg4android""OSD blend ");  
  39.                 byte[] data=new byte[1280*720*3/2];  
  40.                 try {  
  41.                     File f = new File("/mnt/sdcard/out.yuv");  
  42.                     if(f.exists()) f.delete();  
  43.                     f.createNewFile();  
  44.                     out = new FileOutputStream(f);  
  45.                     File input = new File("/mnt/sdcard/input.yuv");  
  46.                     in = new FileInputStream(input);  
  47.                     int len;  
  48.                     while(loop<1000)  
  49.                     {  
  50.                         if(in.read(data,0,1280*720*3/2)<0)  
  51.                         {  
  52.                             Log.d("ffmpeg4android""read fail:");  
  53.                             break;  
  54.                         }else {  
  55.                             String txt = "car-eye-filter" + new SimpleDateFormat("yyyy-MM-dd").format(new Date())+loop;  
  56.                             int result =  ffmpeg.blendOSD(data, txt);  
  57.                             out.write(data,0,1280*720*3/2);  
  58.                             Log.d("ffmpeg4android""write data sucessful:"+result+"data[0]"+data[0]);  
  59.                         }  
  60.                         loop++;  
  61.                     }  
  62.                     in.close();  
  63.                     out.close();  
  64.                     ffmpeg.DelOSD();  
  65.   
  66.                 } catch (Exception e) {  
  67.                     e.printStackTrace();  
  68.                 }  
  69.   
  70.             }  
  71.         }).start();  
  72.   
  73.     }  
  74. }  



生成的YUV数据用播放器打开如下



car-eye开源官方网址:www.car-eye.cn   

car-eye 流媒体平台网址:www.liveoss.com    

car-eye 技术官方邮箱: [email protected]    
car-eye技术交流QQ群: 590411159     


CopyRight©  car-eye 开源团队 2018



首先来看一副图,用来纪念对视频领域做出贡献的雷神:

当然在这个图片里面的decode不是必须的,Filter 模块本身是一个非常独立的模块,但因为相关的程序,给人造成了他必须要依赖于编码器或者解码器来工作。

OK 不多说,先看看内部实现代码:

[cpp]  view plain  copy
  1. #ifndef __CAREYE_PUBLIC_H__  
  2. #define __CAREYE_PUBLIC_H__  
  3.   
  4. #define __STDC_CONSTANT_MACROS  
  5. #ifdef _WIN32  
  6. #define CE_API  __declspec(dllexport)  
  7. #define CE_APICALL  __stdcall  
  8. #else  
  9. #define CE_API  
  10. #define CE_APICALL   
  11. #endif  
  12.   
  13. #ifndef _WIN32  
  14. #define _ANDROID_  
  15. #endif  
  16.   
  17. #ifdef _ANDROID_  
  18.   
  19. #include <android/log.h>  
  20.   
  21. #define CarEyeLog(...) __android_log_print(ANDROID_LOG_DEBUG, "Car-eye-ffmpeg", __VA_ARGS__)  
  22.   
  23. #else  
  24.   
  25. #define CarEyeLog   printf  
  26. #endif  
  27.   
  28.   
  29.   
  30. typedef struct _CarEye_YUVFrame_  
  31. {  
  32.     // Y分量数据存储区  
  33.     unsigned char *Y;  
  34.     // Y分量数据字节数  
  35.     int YSize;  
  36.     // U分量数据存储区  
  37.     unsigned char *U;  
  38.     // U分量数据字节数  
  39.     int USize;  
  40.     // V分量数据存储区  
  41.     unsigned char *V;  
  42.     // V分量数据字节数  
  43.     int VSize;  
  44. }CarEye_YUVFrame;  
  45.   
  46.   
  47.   
  48. //error number  
  49. #define NO_ERROR                    0  
  50. #define PARAMTER_ERROR      1  
  51. #define NULL_MEMORY             2  
  52.   
  53. #define MAX_FILTER_DESCR 512  
  54.   
  55. #endif  

[cpp]  view plain  copy
  1. #ifndef __CAREYE_FILTER_INTERFACE_H__  
  2. #define __CAREYE_FILTER_INTERFACE_H__  
  3.   
  4.   
  5. #define MAX_STRING_LENGTH 1024  
  6. #define MAX_FILE_NAME 64  
  7. // OSD水印结果定义  
  8. typedef struct _CarEye_OSDParam_  
  9. {  
  10.     int width;  
  11.     int height;  
  12.     int fps;  
  13.     // 起始X轴坐标  
  14.     int X;  
  15.     // 起始Y轴坐标  
  16.     int Y;  
  17.     // 字体大小  
  18.     int FontSize;  
  19.     // 16进制的RGB颜色值,如绿色:0x00FF00  
  20.     unsigned int FontColor;  
  21.     // 水印透明度 0~1  
  22.     float Transparency;  
  23.     // 水印内容  
  24.     char SubTitle[MAX_STRING_LENGTH];  
  25.     // 字体名称,字体文件放到库的同目录下,如“arial.ttf”  
  26.     char FontName[MAX_FILE_NAME];  
  27. }CarEye_OSDParam;  
  28.   
  29.   
  30. typedef struct  
  31. {  
  32.     AVFrame *VFrame;  
  33.     // 编码后的音频帧    
  34.     CarEye_OSDParam para;  
  35.     void* handle;  
  36. }CarEyeFilter;  
  37.   
  38.   
  39. #ifdef __cplusplus  
  40. extern "C"  
  41. {  
  42. #endif  
  43.     /* 
  44.     * Comments: 打开水印资源 
  45.     * Param aEncoder: 编码器对象句柄 
  46.     * Param aParam: 水印参数 
  47.     * @Return int 是否成功,0成功,其他失败 
  48.     */  
  49.     CE_API int CE_APICALL CarEye_OpenOsd(CarEyeFilter* pFilter, CarEye_OSDParam aParam);  
  50.   
  51.     /* 
  52.     * Comments: 关闭水印资源 
  53.     * Param aDeocoder: 编码器对象 
  54.     * @Return int 关闭成功与否 0成功 
  55.     */  
  56.     CE_API int CE_APICALL CarEye_CloseOsd(CarEyeFilter* pFilter);  
  57.   
  58.     CE_API int CE_APICALL CarEye_add_osd(CarEyeFilter* pFilter, CarEye_YUVFrame *aYuv, CarEye_OSDParam aParam);  
  59. #ifdef __cplusplus  
  60. }  
  61. #endif  
  62.       
  63. #endif  


实现部分代码:

[cpp]  view plain  copy
  1. #include "FFVideoFilter.h"  
  2.   
  3.   
  4. /* 
  5. * Comments: 打开水印资源 
  6. * Param aEncoder: 编码器对象句柄 
  7. * Param aParam: 水印参数 
  8. * @Return int 是否成功,0成功,其他失败 
  9. */  
  10.   
  11. CE_API int CE_APICALL CarEye_OpenOsd( CarEyeFilter* pFliter, CarEye_OSDParam aParam)  
  12. {  
  13.     if(pFliter==NULL)  
  14.     {  
  15.         return -PARAMTER_ERROR;  
  16.     }  
  17.     avfilter_register_all();  
  18.     pFliter->VFrame = NULL;  
  19.     pFliter->VFrame = av_frame_alloc();  
  20.     if(pFliter->VFrame ==   NULL)  
  21.     {         
  22.         return -NULL_MEMORY;  
  23.     }         
  24.     pFliter->VFrame->width = aParam.width;  
  25.     pFliter->VFrame->height = aParam.height;  
  26.     pFliter->VFrame->pts = 0;   
  27.     if (av_image_alloc(pFliter->VFrame->data, pFliter->VFrame->linesize,  
  28.     pFliter->VFrame->width,  pFliter->VFrame->height,  
  29.     AV_PIX_FMT_YUV420P, 16) < 0)  
  30.     {  
  31.         CarEyeLog("Cannot av_image_alloc\n");  
  32.         av_frame_free(&pFliter->VFrame);  
  33.         return -NULL_MEMORY;  
  34.     }  
  35.     pFliter->VFrame->format = AV_PIX_FMT_YUV420P;  
  36.     FFVideoFilter *handle = new FFVideoFilter();  
  37.     pFliter->handle =(FFVideoFilter*)handle;   
  38.     return handle->InitFilters( aParam);  
  39. }  
  40.   
  41.   
  42. CE_API int CE_APICALL CarEye_add_osd(CarEyeFilter* pFliter, CarEye_YUVFrame *aYuv,CarEye_OSDParam param)  
  43. {  
  44.     if(pFliter==NULL || pFliter->VFrame == NULL)  
  45.     {  
  46.           return -PARAMTER_ERROR;  
  47.     }     
  48.     FFVideoFilter* handle = (FFVideoFilter*)pFliter->handle;  
  49.       pFliter->VFrame->pts++;  
  50.       memcpy(pFliter->VFrame->data[0], aYuv->Y, aYuv->YSize);  
  51.     memcpy(pFliter->VFrame->data[1], aYuv->U, aYuv->USize);  
  52.     memcpy(pFliter->VFrame->data[2], aYuv->V, aYuv->VSize);         
  53.     if (handle->BlendFilters(pFliter->VFrame,param) < 0)  
  54.     {         
  55.         return -PARAMTER_ERROR;  
  56.     }  
  57.     memcpy(aYuv->Y, pFliter->VFrame->data[0], aYuv->YSize);  
  58.     memcpy(aYuv->U, pFliter->VFrame->data[1],  aYuv->USize);  
  59.     memcpy(aYuv->V, pFliter->VFrame->data[2],  aYuv->VSize);  
  60.     return NO_ERROR;  
  61. }  
  62. /* 
  63. * Comments: 关闭水印资源 
  64. * Param aDeocoder: 编码器对象 
  65. * @Return int 关闭成功与否 0 成功 
  66. */  
  67. CE_API int CE_APICALL CarEye_CloseOsd(CarEyeFilter* pFliter)  
  68. {  
  69.     FFVideoFilter* handle = (FFVideoFilter*)pFliter->handle;  
  70.   if(pFliter->VFrame != NULL)  
  71.   {  
  72.       av_frame_free(&pFliter->VFrame);  
  73.   }  
  74.     delete handle;  
  75.     return NO_ERROR;  


[cpp]  view plain  copy
  1. #include "FFVideoFilter.h"  
  2.   
  3.   
  4. /* 
  5. * Comments: 打开水印资源 
  6. * Param aEncoder: 编码器对象句柄 
  7. * Param aParam: 水印参数 
  8. * @Return int 是否成功,0成功,其他失败 
  9. */  
  10.   
  11. CE_API int CE_APICALL CarEye_OpenOsd( CarEyeFilter* pFliter, CarEye_OSDParam aParam)  
  12. {  
  13.     if(pFliter==NULL)  
  14.     {  
  15.         return -PARAMTER_ERROR;  
  16.     }  
  17.     avfilter_register_all();  
  18.     pFliter->VFrame = NULL;  
  19.     pFliter->VFrame = av_frame_alloc();  
  20.     if(pFliter->VFrame ==   NULL)  
  21.     {         
  22.         return -NULL_MEMORY;  
  23.     }         
  24.     pFliter->VFrame->width = aParam.width;  
  25.     pFliter->VFrame->height = aParam.height;  
  26.     pFliter->VFrame->pts = 0;   
  27.     if (av_image_alloc(pFliter->VFrame->data, pFliter->VFrame->linesize,  
  28.     pFliter->VFrame->width,  pFliter->VFrame->height,  
  29.     AV_PIX_FMT_YUV420P, 16) < 0)  
  30.     {  
  31.         CarEyeLog("Cannot av_image_alloc\n");  
  32.         av_frame_free(&pFliter->VFrame);  
  33.         return -NULL_MEMORY;  
  34.     }  
  35.     pFliter->VFrame->format = AV_PIX_FMT_YUV420P;  
  36.     FFVideoFilter *handle = new FFVideoFilter();  
  37.     pFliter->handle =(FFVideoFilter*)handle;   
  38.     return handle->InitFilters( aParam);  
  39. }  
  40.   
  41.   
  42. CE_API int CE_APICALL CarEye_add_osd(CarEyeFilter* pFliter, CarEye_YUVFrame *aYuv,CarEye_OSDParam param)  
  43. {  
  44.     if(pFliter==NULL || pFliter->VFrame == NULL)  
  45.     {  
  46.           return -PARAMTER_ERROR;  
  47.     }     
  48.     FFVideoFilter* handle = (FFVideoFilter*)pFliter->handle;  
  49.       pFliter->VFrame->pts++;  
  50.       memcpy(pFliter->VFrame->data[0], aYuv->Y, aYuv->YSize);  
  51.     memcpy(pFliter->VFrame->data[1], aYuv->U, aYuv->USize);  
  52.     memcpy(pFliter->VFrame->data[2], aYuv->V, aYuv->VSize);         
  53.     if (handle->BlendFilters(pFliter->VFrame,param) < 0)  
  54.     {         
  55.         return -PARAMTER_ERROR;  
  56.     }  
  57.     memcpy(aYuv->Y, pFliter->VFrame->data[0], aYuv->YSize);  
  58.     memcpy(aYuv->U, pFliter->VFrame->data[1],  aYuv->USize);  
  59.     memcpy(aYuv->V, pFliter->VFrame->data[2],  aYuv->VSize);  
  60.     return NO_ERROR;  
  61. }  
  62. /* 
  63. * Comments: 关闭水印资源 
  64. * Param aDeocoder: 编码器对象 
  65. * @Return int 关闭成功与否 0 成功 
  66. */  
  67. CE_API int CE_APICALL CarEye_CloseOsd(CarEyeFilter* pFliter)  
  68. {  
  69.     FFVideoFilter* handle = (FFVideoFilter*)pFliter->handle;  
  70.   if(pFliter->VFrame != NULL)  
  71.   {  
  72.       av_frame_free(&pFliter->VFrame);  
  73.   }  
  74.     delete handle;  
  75.     return NO_ERROR;  
  76. }  

在写JNI之前先看下make文件,主要有两个,android.mk用来实现对ffmpeg 库和新增加的外部水印库的编译,application.mk 主要定义编译的全局变量,如参数和架构等,看下怎么编译ffmpeg的动态库的,这里我们没有用到FFMPEG的avdevice这个库。

#APP_ABI := armeabi armeabi-v7a x86
ifeq ($(APP_ABI), x86)
LIB_NAME_PLUS := x86
else
LIB_NAME_PLUS := armeabi
endif

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE:= avcodec-prebuilt-$(LIB_NAME_PLUS)
LOCAL_SRC_FILES:= prebuilt/$(LIB_NAME_PLUS)/libavcodec-57.so
include $(PREBUILT_SHARED_LIBRARY)


include $(CLEAR_VARS)
LOCAL_MODULE:= avfilter-prebuilt-$(LIB_NAME_PLUS)
LOCAL_SRC_FILES:= prebuilt/$(LIB_NAME_PLUS)/libavfilter-6.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE:= avformat-prebuilt-$(LIB_NAME_PLUS)
LOCAL_SRC_FILES:= prebuilt/$(LIB_NAME_PLUS)/libavformat-57.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE :=  avutil-prebuilt-$(LIB_NAME_PLUS)
LOCAL_SRC_FILES := prebuilt/$(LIB_NAME_PLUS)/libavutil-55.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := swresample-prebuilt-$(LIB_NAME_PLUS)
LOCAL_SRC_FILES := prebuilt/$(LIB_NAME_PLUS)/libswresample-2.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := swscale-prebuilt-$(LIB_NAME_PLUS)
LOCAL_SRC_FILES := prebuilt/$(LIB_NAME_PLUS)/libswscale-4.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
ifeq ($(APP_ABI), x86)
TARGET_ARCH:=x86
TARGET_ARCH_ABI:=x86
else
LOCAL_ARM_MODE := arm
endif

LOCAL_MODULE := libffmpegjni
LOCAL_SRC_FILES := com_li_sheldon_ffmpeg4android_FFmpegNative.c CarEyeEncoderAPI.cpp FFVideoFilter.cpp  CarEyeFilter_interface.cpp
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog -lz
LOCAL_SHARED_LIBRARIES:= avcodec-prebuilt-$(LIB_NAME_PLUS) \
                         avfilter-prebuilt-$(LIB_NAME_PLUS) \
                         avformat-prebuilt-$(LIB_NAME_PLUS) \
                         avutil-prebuilt-$(LIB_NAME_PLUS) \
                         swresample-prebuilt-$(LIB_NAME_PLUS) \
                         swscale-prebuilt-$(LIB_NAME_PLUS)
LOCAL_C_INCLUDES += -L$(SYSROOT)/usr/include
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include

ifeq ($(APP_ABI), x86)
LOCAL_CFLAGS := -DUSE_X86_CONFIG
else
LOCAL_CFLAGS := -DUSE_ARM_CONFIG
endif
include $(BUILD_SHARED_LIBRARY)

编译后生成libffmpegjni.so, 然后提供JNI的源码给上层调用:

[cpp]  view plain  copy
  1. (1)JNIEXPORT :在Jni编程中所有本地语言实现Jni接口的方法前面都有一个"JNIEXPORT",这个可以看做是Jni的一个标志,至今为止没发现它有什么特殊的用处。  
  2.   
  3. (2)jint :这个学过编程的人都知道,当然是方法的返回值了。  
  4.   
  5. (3)JNICALL :这个可以理解为Jni 和Call两个部分,和起来的意思就是 Jni调用XXX(后面的XXX就是JAVA的方法名)。  
  6.   
  7. (4)Java_com_test01_Test_firstTest:这个就是被上一步中被调用的部分,也就是Java中的native 方法名,这里起名字的方式比较特别,是:包名+类名+方法名。  
  8.   
  9. (5)JNIEnv * env:这个env可以看做是Jni接口本身的一个对象,在上一篇中提到的jni.h头文件中存在着大量被封装好的函数,这些函数也是Jni编程中经常被使用到的,要想调用这些函数就需要使用JNIEnv这个对象。例如:env->GetObjectClass()。(详情请查看jni.h)  
  10.   
  11. (6)jobject obj:刚才在Test类的main方法中有这样一段代码:   
  12. */  
  13.   
  14. /* DO NOT EDIT THIS FILE - it is machine generated */  
  15. #include "com_li_sheldon_ffmpeg4android_FFmpegNative.h"  
  16. /* Header for class com_hsb_ffmpeg_FFmpegNative */  
  17. #include "libavcodec/avcodec.h"  
  18. #include "libavcodec/avdct.h"  
  19. #include "libavcodec/avfft.h"  
  20. #include "libavcodec/dirac.h"  
  21. #include "libavcodec/dv_profile.h"  
  22. #include "libavcodec/vaapi.h"  
  23. #include "libavcodec/version.h"  
  24. #include "libavcodec/vorbis_parser.h"  
  25.   
  26. #include "libavdevice/avdevice.h"  
  27. #include "libavdevice/version.h"  
  28.   
  29. #include "libavfilter/avfilter.h"  
  30. #include "libavfilter/avfiltergraph.h"  
  31. #include "libavfilter/buffersink.h"  
  32. #include "libavfilter/buffersrc.h"  
  33. #include "libavfilter/version.h"  
  34.   
  35. #include "libavformat/avformat.h"  
  36. #include "libavformat/avio.h"  
  37. #include "libavformat/version.h"  
  38.   
  39. #include "libavutil/adler32.h"  
  40. #include "libavutil/aes_ctr.h"  
  41. #include "libavutil/aes.h"  
  42. #include "libavutil/attributes.h"  
  43. #include "libavutil/audio_fifo.h"  
  44. #include "libavutil/avassert.h"  
  45. #include "libavutil/avconfig.h"  
  46. #include "libavutil/avstring.h"  
  47. #include "libavutil/avutil.h"  
  48. #include "libavutil/base64.h"  
  49. #include "libavutil/blowfish.h"  
  50. #include "libavutil/bprint.h"  
  51. #include "libavutil/bswap.h"  
  52. #include "libavutil/buffer.h"  
  53. #include "libavutil/camellia.h"  
  54. #include "libavutil/cast5.h"  
  55. #include "libavutil/channel_layout.h"  
  56. #include "libavutil/common.h"  
  57. #include "libavutil/cpu.h"  
  58. #include "libavutil/crc.h"  
  59. #include "libavutil/des.h"  
  60. #include "libavutil/dict.h"  
  61. #include "libavutil/display.h"  
  62. #include "libavutil/downmix_info.h"  
  63. #include "libavutil/error.h"  
  64. #include "libavutil/eval.h"  
  65. #include "libavutil/ffversion.h"  
  66. #include "libavutil/fifo.h"  
  67. #include "libavutil/file.h"  
  68. #include "libavutil/frame.h"  
  69. #include "libavutil/hash.h"  
  70. #include "libavutil/hmac.h"  
  71. #include "libavutil/imgutils.h"  
  72. #include "libavutil/intfloat.h"  
  73. #include "libavutil/intreadwrite.h"  
  74. #include "libavutil/lfg.h"  
  75. #include "libavutil/log.h"  
  76. #include "libavutil/lzo.h"  
  77. #include "libavutil/macros.h"  
  78. #include "libavutil/mastering_display_metadata.h"  
  79. #include "libavutil/mathematics.h"  
  80. #include "libavutil/md5.h"  
  81. #include "libavutil/mem.h"  
  82. #include "libavutil/motion_vector.h"  
  83. #include "libavutil/murmur3.h"  
  84. #include "libavutil/opt.h"  
  85. #include "libavutil/parseutils.h"  
  86. #include "libavutil/pixdesc.h"  
  87. #include "libavutil/pixelutils.h"  
  88. #include "libavutil/pixfmt.h"  
  89. #include "libavutil/random_seed.h"  
  90. #include "libavutil/rational.h"  
  91. #include "libavutil/rc4.h"  
  92. #include "libavutil/replaygain.h"  
  93. #include "libavutil/ripemd.h"  
  94. #include "libavutil/samplefmt.h"  
  95. #include "libavutil/sha.h"  
  96. #include "libavutil/sha512.h"  
  97. #include "libavutil/stereo3d.h"  
  98. #include "libavutil/tea.h"  
  99. #include "libavutil/threadmessage.h"  
  100. #include "libavutil/time.h"  
  101. #include "libavutil/timecode.h"  
  102. #include "libavutil/timestamp.h"  
  103. #include "libavutil/tree.h"  
  104. #include "libavutil/twofish.h"  
  105. #include "libavutil/version.h"  
  106. #include "libavutil/xtea.h"  
  107. #include "libswresample/swresample.h"  
  108. #include "libswresample/version.h"  
  109. #include "libswscale/swscale.h"  
  110. #include "libswscale/version.h"  
  111. #include "CarEyeEncoderAPI.h"  
  112. #include "CarEyeFilter_interface.h"  
  113.   
  114. #include <android/log.h>  
  115. #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "ffmpeg4android", __VA_ARGS__)  
  116.   
  117. JNIEXPORT jint JNICALL Java_com_li_sheldon_ffmpeg4android_FFmpegNative_ffmpeg_1h264  
  118.   (JNIEnv* env, jobject obj, jint codecID)  
  119.  {  
  120.     AVCodec* codec = NULL;  
  121.     av_register_all();//该函数在所有基于ffmpeg的应用程序中几乎都是第一个被调用的。只有调用了该函数,才能使用复用器,编码器等  
  122.     codec = avcodec_find_decoder(codecID);//通过code ID查找一个已经注册的音视频编码器。H264的codecID是28,所以我们java那边传28下来如果检测到H264注册过了这边codec就不为空,返回0  
  123.     if(codec != NULL){  
  124.       return 0;  
  125.     }else{  
  126.       return -1;  
  127.     }  
  128. }  
  129. CarEyeFilter gFliter;  
  130.   
  131. JNIEXPORT jint JNICALL Java_com_li_sheldon_ffmpeg4android_FFmpegNative_OpenOSD(JNIEnv* env, jobject obj, jint width, jint height, jint startX, jint startY, jint FontSize,  jint color, jstring  filename, jstring content  )  
  132. {  
  133.     char* Name;  
  134.     char* pContent;  
  135.     gFliter.para.X = startX;  
  136.     gFliter.para.Y = startY;  
  137.     gFliter.para.width = width;  
  138.     gFliter.para.height = height;  
  139.     gFliter.para.FontSize = FontSize;  
  140.     gFliter.para.FontColor = color;  
  141.     gFliter.para.fps = 25;  
  142.     Name=(*env)->GetStringUTFChars(env,filename, JNI_FALSE);  
  143.     pContent=(*env)->GetStringUTFChars(env,content, JNI_FALSE);  
  144.     strcpy(gFliter.para.FontName, Name);  
  145.     strcpy(gFliter.para.SubTitle, pContent);      
  146.     gFliter.para.Transparency = 0.7;       
  147.     (*env)->ReleaseStringUTFChars(env, filename, Name);  
  148.     (*env)->ReleaseStringUTFChars(env, content, pContent);                 
  149.     return CarEye_OpenOsd(&gFliter, gFliter.para);  
  150. }  
  151.   
  152. JNIEXPORT jint JNICALL Java_com_li_sheldon_ffmpeg4android_FFmpegNative_CloseOSD(JNIEnv* env, jobject obj)  
  153. {         
  154.     return CarEye_CloseOsd(&gFliter);  
  155. }  
  156.   
  157. JNIEXPORT jint JNICALL Java_com_li_sheldon_ffmpeg4android_FFmpegNative_AddOSD(JNIEnv* env, jobject obj, jbyteArray frame, jstring txtoverlay)  
  158. {  
  159.     unsigned char * pBuffer;  
  160.     int ret;  
  161.     char *txt;  
  162.     CarEye_YUVFrame yuv_frame;  
  163.     pBuffer = (*env)->GetByteArrayElements(env,frame, 0 );  
  164.     int len = (*env)->GetArrayLength(env,frame);       
  165.     yuv_frame.Y = pBuffer;  
  166.     yuv_frame.YSize = len*2/3;  
  167.     yuv_frame.U = &pBuffer[len*2/3];  
  168.     yuv_frame.USize = len/6;  
  169.     yuv_frame.V = &pBuffer[len*5/6];  
  170.     yuv_frame.VSize = len/6;  
  171.     txt = (*env)->GetStringUTFChars(env,txtoverlay, JNI_FALSE);  
  172.     strcpy(gFliter.para.SubTitle, txt);      
  173.     ret = CarEye_add_osd(&gFliter,&yuv_frame,gFliter.para);          
  174.    (*env)->ReleaseStringUTFChars(env, txtoverlay, txt);       
  175.    (*env)->ReleaseByteArrayElements(env,frame,pBuffer,0);  
  176.    return ret;  
  177. }  

OK, 写一个简单例子测试下:

[java]  view plain  copy
  1. package com.li.sheldon.ffmpeg4android;  
  2.   
  3. import android.util.Log;  
  4.   
  5. /** 
  6.  * Created by sheldon on 17-1-4. 
  7.  */  
  8. public class FFmpegNative {  
  9.   
  10.     static{  
  11.         System.loadLibrary("avcodec-57");  
  12.         System.loadLibrary("avfilter-6");  
  13.         System.loadLibrary("avformat-57");  
  14.         System.loadLibrary("avutil-55");  
  15.         System.loadLibrary("swresample-2");  
  16.         System.loadLibrary("swscale-4");  
  17.         System.loadLibrary("ffmpegjni");  
  18.     }  
  19.     private native int AddOSD(byte[] buffer, String txt);  
  20.     private native int CloseOSD();  
  21.     private native int OpenOSD(int width, int height, int startX, int startY, int fontsize, int color, String  filename, String  content);  
  22.     private native int ffmpeg_h264(int id);  
  23.   
  24.     public int test_h246(int id){  
  25.         return ffmpeg_h264(id);  
  26.     }  
  27.     public int InitOSD(int width, int height, int startX, int startY, int fontsize, int color, String  filename, String  content)  
  28.     {  
  29.          return OpenOSD(width,height,startX,startY,fontsize,color, filename,content );  
  30.     }  
  31.     public int DelOSD()  
  32.     {  
  33.         return CloseOSD();  
  34.     }  
  35.     public int blendOSD(byte[] buffer,String txt)  
  36.     {  
  37.         return AddOSD(buffer,txt);  
  38.     }  
  39.   
  40. }  

[cpp]  view plain  copy
  1. package com.li.sheldon.ffmpeg4android;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5. import android.util.Log;  
  6. import android.widget.TextView;  
  7.   
  8. import java.io.File;  
  9. import java.io.FileInputStream;  
  10. import java.io.FileNotFoundException;  
  11. import java.io.FileOutputStream;  
  12. import java.io.IOException;  
  13. import java.text.SimpleDateFormat;  
  14. import java.util.Date;  
  15.   
  16. public class MainActivity extends Activity {  
  17.     @Override  
  18.     protected void onCreate(Bundle savedInstanceState) {  
  19.         super.onCreate(savedInstanceState);  
  20.         setContentView(R.layout.activity_main);  
  21.         int codec_id = 28;  
  22.         final FFmpegNative ffmpeg = new FFmpegNative();  
  23.         int tmp = ffmpeg.test_h246(codec_id); //28 is the H264 Codec ID  
  24.         TextView tv = (TextView) this.findViewById(R.id.hello_ffmpeg);  
  25.         tv.setText(tmp == 0 ? "Support Codec ID:" + codec_id : "Not support Codec ID:" + codec_id);  
  26.         Log.d("ffmpeg4android""OSD init start: ");  
  27.         new Thread(new Runnable() {  
  28.             @Override  
  29.             public void run() {  
  30.                 int loop = 0;  
  31.                 FileOutputStream out;  
  32.                 FileInputStream in;  
  33.                 FFmpegNative ffmpeg = new FFmpegNative();  
  34.                 int ret = ffmpeg.InitOSD(1280, 720, 10, 10, 28, 0x00ff00, String.format("/mnt/sdcard/arial.ttf"), String.format("ddddd"));  
  35.                 if (ret != 0) {  
  36.                     Log.d("ffmpeg4android""OSD init fail: "+ret);  
  37.                 }  
  38.                 Log.d("ffmpeg4android""OSD blend ");  
  39.                 byte[] data=new byte[1280*720*3/2];  
  40.                 try {  
  41.                     File f = new File("/mnt/sdcard/out.yuv");  
  42.                     if(f.exists()) f.delete();  
  43.                     f.createNewFile();  
  44.                     out = new FileOutputStream(f);  
  45.                     File input = new File("/mnt/sdcard/input.yuv");  
  46.                     in = new FileInputStream(input);  
  47.                     int len;  
  48.                     while(loop<1000)  
  49.                     {  
  50.                         if(in.read(data,0,1280*720*3/2)<0)  
  51.                         {  
  52.                             Log.d("ffmpeg4android""read fail:");  
  53.                             break;  
  54.                         }else {  
  55.                             String txt = "car-eye-filter" + new SimpleDateFormat("yyyy-MM-dd").format(new Date())+loop;  
  56.                             int result =  ffmpeg.blendOSD(data, txt);  
  57.                             out.write(data,0,1280*720*3/2);  
  58.                             Log.d("ffmpeg4android""write data sucessful:"+result+"data[0]"+data[0]);  
  59.                         }  
  60.                         loop++;  
  61.                     }  
  62.                     in.close();  
  63.                     out.close();  
  64.                     ffmpeg.DelOSD();  
  65.   
  66.                 } catch (Exception e) {  
  67.                     e.printStackTrace();  
  68.                 }  
  69.   
  70.             }  
  71.         }).start();  
  72.   
  73.     }  
  74. }  



生成的YUV数据用播放器打开如下



car-eye开源官方网址:www.car-eye.cn   

car-eye 流媒体平台网址:www.liveoss.com    

car-eye 技术官方邮箱: [email protected]    
car-eye技术交流QQ群: 590411159     


CopyRight©  car-eye 开源团队 2018



猜你喜欢

转载自blog.csdn.net/dengtieshan1/article/details/80380983