概述
CMakeLists.txt
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -UNDEBUG")
add_library(native-codec-jni SHARED
looper.cpp
native-codec-jni.cpp)
# Include libraries needed for native-codec-jni lib
target_link_libraries(native-codec-jni
android
log
mediandk
OpenMAXAL)
NativeCodec.java
/** Native methods, implemented in jni folder */
public static native void createEngine();
public static native boolean createStreamingMediaPlayer(AssetManager assetMgr, String filename);
public static native void setPlayingStreamingMediaPlayer(boolean isPlaying);
public static native void shutdown();
public static native void setSurface(Surface surface);
public static native void rewindStreamingMediaPlayer();
native-codec-jni.cpp
#include <assert.h>
#include <jni.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <limits.h>
#include "looper.h"
#include "media/NdkMediaCodec.h"
#include "media/NdkMediaExtractor.h"
setSurface
// set the surface
void Java_com_example_nativecodec_NativeCodec_setSurface(JNIEnv *env, jclass clazz, jobject surface)
{
// obtain a native window from a Java surface
if (data.window) {
ANativeWindow_release(data.window);
data.window = NULL;
}
data.window = ANativeWindow_fromSurface(env, surface);
LOGV("@@@ setsurface %p", data.window);
}
从一个java的surface获取window
createStreamingMediaPlayer
jboolean Java_com_example_nativecodec_NativeCodec_createStreamingMediaPlayer(JNIEnv* env,
jclass clazz, jobject assetMgr, jstring filename)
{
LOGV("@@@ create");
// convert Java string to UTF-8
const char *utf8 = env->GetStringUTFChars(filename, NULL);获取c文件字符串
LOGV("opening %s", utf8);
off_t outStart, outLen;
int fd = AAsset_openFileDescriptor(AAssetManager_open(AAssetManager_fromJava(env, assetMgr), utf8, 0),
&outStart, &outLen);//获取文件fd
env->ReleaseStringUTFChars(filename, utf8);
if (fd < 0) {
LOGE("failed to open file: %s %d (%s)", utf8, fd, strerror(errno));
return JNI_FALSE;
}
data.fd = fd;
workerdata *d = &data;
AMediaExtractor *ex = AMediaExtractor_new();//获取媒体的解析器
media_status_t err = AMediaExtractor_setDataSourceFd(ex, d->fd,
static_cast<off64_t>(outStart),
static_cast<off64_t>(outLen));
close(d->fd);
if (err != AMEDIA_OK) {
LOGV("setDataSource error: %d", err);
return JNI_FALSE;
}
int numtracks = AMediaExtractor_getTrackCount(ex);//获取媒体轨,音频和视频
AMediaCodec *codec = NULL;
LOGV("input has %d tracks", numtracks);
for (int i = 0; i < numtracks; i++) {
AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i);//获取相应音频和视频轨的媒体信息
const char *s = AMediaFormat_toString(format);把相应的媒体信息转换为字符串
LOGV("track %d format: %s", i, s);
const char *mime;
if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) {//获取媒体类型,如video/avc等
LOGV("no mime type");
return JNI_FALSE;
} else if (!strncmp(mime, "video/", 6)) {
// Omitting most error handling for clarity.
// Production code should check for errors.
AMediaExtractor_selectTrack(ex, i);
codec = AMediaCodec_createDecoderByType(mime);//根据媒体类型创建相应的codec
AMediaCodec_configure(codec, format, d->window, NULL, 0);//codec配置
d->ex = ex;
d->codec = codec;
d->renderstart = -1;
d->sawInputEOS = false;
d->sawOutputEOS = false;
d->isPlaying = false;
d->renderonce = true;
AMediaCodec_start(codec);//开始codec
}
AMediaFormat_delete(format);删除相应的类型
}
mlooper = new mylooper();
mlooper->post(kMsgCodecBuffer, d);//发送msg
return JNI_TRUE;
}
setPlayingStreamingMediaPlayer
// set the playing state for the streaming media player
void Java_com_example_nativecodec_NativeCodec_setPlayingStreamingMediaPlayer(JNIEnv* env,
jclass clazz, jboolean isPlaying)
{
LOGV("@@@ playpause: %d", isPlaying);
if (mlooper) {
if (isPlaying) {
mlooper->post(kMsgResume, &data);//设置播放的状态
} else {
mlooper->post(kMsgPause, &data);
}
}
}
shutdown
// shut down the native media system
void Java_com_example_nativecodec_NativeCodec_shutdown(JNIEnv* env, jclass clazz)
{
LOGV("@@@ shutdown");
if (mlooper) {
mlooper->post(kMsgDecodeDone, &data, true /* flush */);//decode完毕
mlooper->quit();
delete mlooper;
mlooper = NULL;
}
if (data.window) {
ANativeWindow_release(data.window);
data.window = NULL;
}
}
rewindStreamingMediaPlayer
seek动作
// rewind the streaming media player
void Java_com_example_nativecodec_NativeCodec_rewindStreamingMediaPlayer(JNIEnv *env, jclass clazz)
{
LOGV("@@@ rewind");
if (mlooper) {
mlooper->post(kMsgSeek, &data);
}
}
looper.h
#include <pthread.h>
#include <semaphore.h>
struct loopermessage;
class looper {
public:
looper();
looper& operator=(const looper& ) = delete;
looper(looper&) = delete;
virtual ~looper();
void post(int what, void *data, bool flush = false);
void quit();
virtual void handle(int what, void *data);
private:
void addmsg(loopermessage *msg, bool flush);
static void* trampoline(void* p);
void loop();
loopermessage *head;
pthread_t worker;
sem_t headwriteprotect;
sem_t headdataavailable;
bool running;
};
looper.cpp
// for __android_log_print(ANDROID_LOG_INFO, "YourApp", "formatted message");
#include <android/log.h>
#define TAG "NativeCodec-looper"
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)
//定义消息结构体
struct loopermessage;
typedef struct loopermessage loopermessage;
struct loopermessage {
int what;
void *obj;
loopermessage *next;
bool quit;
};
void* looper::trampoline(void* p) {
((looper*)p)->loop();
return NULL;
}
//创建线程和初始化信号量
looper::looper() {
sem_init(&headdataavailable, 0, 0);
sem_init(&headwriteprotect, 0, 1);
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_create(&worker, &attr, trampoline, this);
running = true;
}
//把消息放到同步队列里面
void looper::post(int what, void *data, bool flush) {
loopermessage *msg = new loopermessage();
msg->what = what;
msg->obj = data;
msg->next = NULL;
msg->quit = false;
addmsg(msg, flush);
}
void looper::addmsg(loopermessage *msg, bool flush) {
sem_wait(&headwriteprotect);
loopermessage *h = head;
if (flush) {
while(h) {
loopermessage *next = h->next;
delete h;
h = next;
}
h = NULL;
}
if (h) {
while (h->next) {
h = h->next;
}
h->next = msg;
} else {
head = msg;
}
LOGV("post msg %d", msg->what);
sem_post(&headwriteprotect);
sem_post(&headdataavailable);
}
//获取并处理消息,读写要同步
void looper::loop() {
while(true) {
// wait for available message
sem_wait(&headdataavailable);
// get next available message
sem_wait(&headwriteprotect);
loopermessage *msg = head;
if (msg == NULL) {
LOGV("no msg");
sem_post(&headwriteprotect);
continue;
}
head = msg->next;
sem_post(&headwriteprotect);
if (msg->quit) {
LOGV("quitting");
delete msg;
return;
}
LOGV("processing msg %d", msg->what);
handle(msg->what, msg->obj);
delete msg;
}
}
//退出添加退出的消息
void looper::quit() { LOGV("quit"); loopermessage *msg = new loopermessage(); msg->what = 0; msg->obj = NULL; msg->next = NULL; msg->quit = true; addmsg(msg, false); void *retval; pthread_join(worker, &retval); sem_destroy(&headdataavailable); sem_destroy(&headwriteprotect); running = false; }
//处理消息
void looper::handle(int what, void* obj) { LOGV("dropping msg %d %p", what, obj); }
最后
以上就是疯狂高山为你收集整理的Android-NDK:native-codec的全部内容,希望文章能够帮你解决Android-NDK:native-codec所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复