当前位置:网站首页>NDK learning notes (12) native graphics API, using avilib to create an avi video player

NDK learning notes (12) native graphics API, using avilib to create an avi video player

2022-06-11 05:34:00 Come and go

1. Practice hands , Use AVILib Create a AVI Video player

(1) First download transcode, And configuration avilib.

http://www.linuxfromscratch.org/blfs/view/svn/multimedia/transcode.html

take transcode Medium avilib Copy files to project .

 Insert picture description here
edit platform.h file

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

stay avilib establish CMakeLists.txt

add_library( # Sets the name of the library.
        avi-lib

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        avilib.c
        platform_posix.c)

(2) establish AbstractPlayerActivity And implement native Method

Extract the shared code and abstract it into a class

public abstract class AbstractPlayerActivity extends Activity {
    
    
    public static final String EXTRA_FILE_NAME = "cn.study.aviplayer.EXTRA_FILE_NAME";

    protected long avi = 0;

    @Override
    protected void onStart() {
    
        super.onStart();

        try {
    

            avi = open(getFileName());
        } catch (IOException e) {
    

            new AlertDialog.Builder(this)
                    .setTitle(" Error message ")
                    .setMessage(e.getMessage())
                    .show();
        }
    }


    @Override
    protected void onStop() {
    
        super.onStop();

        if (0 != avi) {
    

            close(avi);
            avi = 0;
        }
    }

    protected String getFileName() {
    

        return getIntent().getExtras().getString(EXTRA_FILE_NAME);
    }


    /** *  Open the specified avi file  * * @return */
    protected native static long open(String fileName) throws IOException;

    /** *  Get the video width  * * @param avi * @return */
    protected native static int getWidth(long avi);

    /** *  Get video height  * * @param avi * @return */
    protected native static int getHeight(long avi);


    /** *  Get frame rate  * * @param avi * @return */
    protected native static double getFrameRate(long avi);

    /** *  Closes the specified based on the given file descriptor avi file  * * @param avi */
    protected native static void close(long avi);

}

Use javah To generate .h file .

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class cn_study_aviplayer_AbstractPlayerActivity */

#ifndef _Included_cn_study_aviplayer_AbstractPlayerActivity
#define _Included_cn_study_aviplayer_AbstractPlayerActivity
#ifdef __cplusplus
extern "C" {
    
#endif
/* * Class: cn_study_aviplayer_AbstractPlayerActivity * Method: open * Signature: (Ljava/lang/String;)J */
JNIEXPORT jlong JNICALL Java_cn_study_aviplayer_AbstractPlayerActivity_open
  (JNIEnv *, jclass, jstring);

/* * Class: cn_study_aviplayer_AbstractPlayerActivity * Method: getWidth * Signature: (J)I */
JNIEXPORT jint JNICALL Java_cn_study_aviplayer_AbstractPlayerActivity_getWidth
  (JNIEnv *, jclass, jlong);

/* * Class: cn_study_aviplayer_AbstractPlayerActivity * Method: getHeight * Signature: (J)I */
JNIEXPORT jint JNICALL Java_cn_study_aviplayer_AbstractPlayerActivity_getHeight
  (JNIEnv *, jclass, jlong);

/* * Class: cn_study_aviplayer_AbstractPlayerActivity * Method: getFrameRate * Signature: (J)D */
JNIEXPORT jdouble JNICALL Java_cn_study_aviplayer_AbstractPlayerActivity_getFrameRate
  (JNIEnv *, jclass, jlong);

/* * Class: cn_study_aviplayer_AbstractPlayerActivity * Method: close * Signature: (J)V */
JNIEXPORT void JNICALL Java_cn_study_aviplayer_AbstractPlayerActivity_close
  (JNIEnv *, jclass, jlong);

#ifdef __cplusplus
}
#endif
#endif

stay native-lib.cpp Import avilib.h need .

extern "C" {
    
#include "avilib/avilib.h"
}

native-lib.cpp

#include <jni.h>
#include <string>

#include "cn_study_aviplayer_AbstractPlayerActivity.h"
#include "Common.h"
#include <android/bitmap.h>

extern "C" {
    
#include "avilib/avilib.h"
}

extern "C" JNIEXPORT jstring JNICALL
Java_cn_study_aviplayer_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

extern "C"
JNIEXPORT jlong JNICALL
Java_cn_study_aviplayer_AbstractPlayerActivity_open(JNIEnv *env, jclass clazz, jstring file_name) {
    

    avi_t *avi = 0;
    // Get the file name and convert it to a string variable 
    const char *cFileName = env->GetStringUTFChars(file_name, 0);
    if (0 == cFileName) {
    

        goto exit;
    }
    avi = AVI_open_input_file(cFileName, 1);
    env->ReleaseStringUTFChars(file_name, cFileName);

    if (0 == avi) {
    

        ThrowException(env, "java/io/IOException", AVI_strerror());
    }

    exit:
    return (jlong) avi;
}

extern "C"
JNIEXPORT jint JNICALL
Java_cn_study_aviplayer_AbstractPlayerActivity_getWidth(JNIEnv *env, jclass clazz, jlong avi) {
    

    return AVI_video_width((avi_t *) avi);
}

extern "C"
JNIEXPORT jint JNICALL
Java_cn_study_aviplayer_AbstractPlayerActivity_getHeight(JNIEnv *env, jclass clazz, jlong avi) {
    

    return AVI_video_height((avi_t *) avi);
}

extern "C"
JNIEXPORT jdouble JNICALL
Java_cn_study_aviplayer_AbstractPlayerActivity_getFrameRate(JNIEnv *env, jclass clazz, jlong avi) {
    

    return AVI_frame_rate((avi_t *) avi);
}

extern "C"
JNIEXPORT void JNICALL
Java_cn_study_aviplayer_AbstractPlayerActivity_close(JNIEnv *env, jclass clazz, jlong avi) {
    

    AVI_close((avi_t *) avi);
}

(3) To configure native-lib, Turn on jnigraphics, Connect avi-lib

cmake_minimum_required(VERSION 3.4.1)


add_library( # Sets the name of the library.
        native-lib

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        native-lib.cpp
        Common.cpp
        cn_study_aviplayer_BitmapPlayerActivity.cpp)
# Add subdirectories 
add_subdirectory(avilib)


find_library( # Sets the name of the path variable.
        log-lib

        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log)


find_library( # Sets the name of the path variable.
        jnigraphics-lib
        jnigraphics)

target_link_libraries( # Specifies the target library.
        native-lib
        # Links the target library to the log library
        # included in the NDK.
        ${
    jnigraphics-lib}# Turn on jnigraphics
        ${
    log-lib}
        avi-lib)

(4)jni graphics api

 retrieval bitmap Object information , Such as size 、 Pixel format . Successfully returns 0, Failure returns a negative number .
int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap,AndroidBitmapInfo* info);
 Access the native pixel cache , Lock the pixel cache to ensure that the pixel's memory does not move .
 Successfully returns 0, Failure returns a negative number .
int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr);
 Free the native pixel cache 
 Successfully returns 0, Failure returns a negative number 
int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap);

(5) Use bitmap Render to update avi player

public class BitmapPlayerActivity extends AbstractPlayerActivity {
    


    private final AtomicBoolean isPlaying = new AtomicBoolean();
    private SurfaceHolder surfaceHolder;
    private SurfaceView surfaceView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bitmap_player);

        surfaceView = findViewById(R.id.surface_view);

        surfaceHolder = surfaceView.getHolder();
        surfaceHolder.addCallback(shCallback);
    }


    private final SurfaceHolder.Callback shCallback = new SurfaceHolder.Callback2() {
    
        @Override
        public void surfaceRedrawNeeded(SurfaceHolder holder) {
    

        }

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
    

            isPlaying.set(true);
            new Thread(renderer).start();
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    

        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
    

            isPlaying.set(false);
        }
    };


    private final Runnable renderer = new Runnable() {
    

        @Override
        public void run() {
    

            Paint paint = new Paint();
            paint.setAntiAlias(true);
            paint.setColor(Color.BLACK);
            paint.setStyle(Paint.Style.FILL);


            int width = getWidth(avi);
            int height = getHeight(avi);


            Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);

            float sx = 2.0f;
            float sy = 2.0f;

            Matrix matrix = new Matrix();
            matrix.postScale(sx, sy);

            int vWidth = (int) (width * sx);
            int vHeight = (int) (height * sy);

            int x = (1080 - vWidth) / 2;
            int y = (1920 - vHeight) / 2;

            matrix.postTranslate(x, y);
            // Delay 
            long frameDelay = (long) (1000 / getFrameRate(avi));
            while (isPlaying.get()) {
    
                render(avi, bitmap);

                Canvas canvas = surfaceHolder.lockCanvas();
                canvas.drawBitmap(bitmap, matrix, null);
                surfaceHolder.unlockCanvasAndPost(canvas);

                // Wait for the next stitch 
                try {
    
                    Thread.sleep(frameDelay);

                } catch (InterruptedException e) {
    

                    break;
                }
            }

        }
    };

    /** *  from avi The file descriptor is output to the specified bitmap To render frames  * * @param avi * @param bitmap * @return */
    private native static boolean render(long avi, Bitmap bitmap);
}

cn_study_aviplayer_BitmapPlayerActivity.cpp

#include "Common.h"
#include "cn_study_aviplayer_BitmapPlayerActivity.h"
extern "C" {
    
#include "avilib/avilib.h"
}
#include <android/bitmap.h>

extern "C"
JNIEXPORT jboolean JNICALL
Java_cn_study_aviplayer_BitmapPlayerActivity_render(JNIEnv *env, jclass clazz, jlong avi,
                                                    jobject bitmap) {
    

    jboolean isFrameRead = JNI_FALSE;
    char *frameBuffer = 0;
    long frameSize = 0;
    int keyFrame = 0;

    if (0 > AndroidBitmap_lockPixels(env, bitmap, (void **) &frameBuffer)) {
    

        ThrowException(env, "java/io/IOException", " Cannot lock pixels ");
        goto exit;
    }

    // take avi frame byte Read bitmap in 
    frameSize = AVI_read_frame((avi_t *) avi, frameBuffer, &keyFrame);

    // Unlock 
    if (0 > AndroidBitmap_unlockPixels(env, bitmap)) {
    

        ThrowException(env, "java/io/IOException", " Cannot unlock pixels ");
        goto exit;
    }
    // Whether the reading is successful 
    if (0 < frameSize) {
    

        isFrameRead = JNI_TRUE;
    }
    exit:
    return isFrameRead;

}

Want to use this avi player , The video file format must be avi Format , I hope the video load is through RGB565 The uncompressed original frame of color space .
Put the video in the specified directory , The operation effect is as follows :
 Insert picture description here
Detailed code and video files

https://gitee.com/xd_box/AviPlayer

2.android studio To configure javah

file>Setting>Tools>External Tools Click on + Number .

program:$JDKPath$\bin\javah.exe
arguments:-classpath . -jni -d $ModuleFileDir$\src\main\cpp $FileClass$
working directory:$ModuleFileDir$\src\main\java

 Insert picture description here

原网站

版权声明
本文为[Come and go]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/03/202203020538239405.html