1. Android端的SurfaceView
public class VideoView extends SurfaceView implements SurfaceHolder.Callback {
public VideoView(Context context) {
super(context);
}
...
public VideoView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private SurfaceHolder holder;
private NativeLib nativeLib;
private void init() {
holder = getHolder();
holder.addCallback(this);
nativeLib = new NativeLib();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
new Thread(new Runnable() {
@Override
public void run() {
nativeLib.videoPlay(holder.getSurface(),
"/sdcard/DCIM/Camera/lv_0_20220323141837.mp4");
}
}).start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
public class NativeLib {
static {
System.loadLibrary("nativelib");
}
public native void videoPlay(Surface surface,String inputPath);
}
2. jni中的方法
#include <jni.h>
#include <string>
#include "android/log.h"
#include <android/native_window.h>
#include <android/native_window_jni.h>
extern "C" {
#include "libavcodec/avcodec.h"
#include <libavformat/avformat.h>
#include "libswscale/swscale.h"
#include <libavutil/imgutils.h>
}
char * jstringToChar(JNIEnv *env, jstring str) {
char *rtn = NULL;
jclass classString = env->FindClass("java/lang/String");
jstring strEncode = env->NewStringUTF("UTF-8");
jmethodID mid = env->GetMethodID(classString, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr = (jbyteArray) env->CallObjectMethod(str, mid, strEncode);
jsize length = env->GetArrayLength(barr);
jbyte *ba = env->GetByteArrayElements(barr,JNI_FALSE);
if (length > 0){
rtn = (char *)malloc(length+1);
memcpy(rtn,ba,length);
rtn[length] = 0;
}
env->ReleaseByteArrayElements(barr,ba,0);
return rtn;
}
extern "C" JNIEXPORT void JNICALL
Java_com_vivo_finger_nativelib_NativeLib_videoPlay(JNIEnv *env, jobject,
jobject surface, jstring inputPath) {
char *path = jstringToChar(env,inputPath);
avformat_network_init();
AVFormatContext *avFormatContext = avformat_alloc_context();
avformat_open_input(&avFormatContext, path, NULL, NULL);
avformat_find_stream_info(avFormatContext, NULL);
int video_index = -1;
for (int i = 0; i < avFormatContext->nb_streams; ++i) {
if (avFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
video_index = i;
}
}
AVCodecContext *avCodecContext = avFormatContext->streams[video_index]->codec;
AVCodec *avCodec = avcodec_find_decoder(avCodecContext->codec_id);
if (avcodec_open2(avCodecContext, avCodec, NULL) < 0) {
__android_log_write(ANDROID_LOG_DEFAULT, "videoPlay", "打开失败");
return;
}
AVPacket *packet = (AVPacket *) av_malloc(sizeof(AVPacket));
av_init_packet(packet);
AVFrame *frame = av_frame_alloc();
AVFrame *rgb_frame = av_frame_alloc();
int buffer_size = av_image_get_buffer_size(AV_PIX_FMT_RGBA,
avCodecContext->width,avCodecContext->height,1);
uint8_t *out_buffer = (uint8_t *) av_malloc(buffer_size * sizeof(uint8_t));
av_image_fill_arrays(rgb_frame->data, rgb_frame->linesize, out_buffer, AV_PIX_FMT_RGBA,
avCodecContext->width, avCodecContext->height, 1);
ANativeWindow *nativeWindow = ANativeWindow_fromSurface(env, surface);
ANativeWindow_Buffer native_outBuffer;
ANativeWindow_setBuffersGeometry(nativeWindow, avCodecContext->width, avCodecContext->height,
WINDOW_FORMAT_RGBA_8888);
SwsContext *sws_context = sws_getContext(avCodecContext->width, avCodecContext->height,
avCodecContext->pix_fmt,
avCodecContext->width, avCodecContext->height,
AV_PIX_FMT_RGBA, SWS_BICUBIC, NULL, NULL, NULL);
while (av_read_frame(avFormatContext, packet) >= 0) {
if (packet->stream_index == video_index) {
int ret = avcodec_send_packet(avCodecContext, packet);
av_packet_unref(packet);
if (ret != 0) {
continue;
}
ret = avcodec_receive_frame(avCodecContext, frame);
if (ret != 0) {
continue;
}
ANativeWindow_lock(nativeWindow, &native_outBuffer, NULL);
sws_scale(sws_context, (const uint8_t *const *) frame->data, frame->linesize, 0,
frame->height,
rgb_frame->data, rgb_frame->linesize);
uint8_t *dst = (uint8_t *) native_outBuffer.bits;
int destStride = native_outBuffer.stride * 4;
uint8_t *src = rgb_frame->data[0];
int srcStride = rgb_frame->linesize[0];
for (int i = 0; i < avCodecContext->height; ++i) {
memcpy(dst + i * destStride, src + i * srcStride, srcStride);
}
ANativeWindow_unlockAndPost(nativeWindow);
}
}
ANativeWindow_release(nativeWindow);
av_free(&frame);
av_free(&rgb_frame);
avcodec_close(avCodecContext);
avformat_free_context(avFormatContext);
}