我正在尝试使用android NDK和ffmpeg来提取视频的第一帧。我在这个网站上看到很多使用命令行代码的例子,看起来像ffmpeg -i video.mp4 -vframes 1 -an -f image2 -y thumbmail.png 2>&1
我是Android NDK的新手,我不知道这是如何在本机代码文件中播放的JNI。它是否可以在本机方法中使用,或者是否有办法使用ffmpeg库以另一种方式完成相同的任务?
答案 0 :(得分:4)
如果您只想提取帧(不是高级视频管理),可以使用this android class。它比编译和添加ffmpeg版本更容易安卓...如果你仍然想使用ffmpeg库,我认为使用静态库会更容易(如果你只想提取帧),但我会强烈建议你使用Api的课程。有时这个类会显示一些错误。如果发生这种情况,您可以添加并使用this external library而不是第一个。 希望它有用
答案 1 :(得分:2)
试试这个 http://www.roman10.net/how-to-build-ffmpeg-for-android/
Android.mk看起来像这样
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := ffmpeg-prebuilt
LOCAL_SRC_FILES := ffmpeg/android/armv5/libffmpeg.so
LOCAL_EXPORT_C_INCLUDES := ffmpeg/android/armv5/include
LOCAL_EXPORT_LDLIBS := ffmpeg/android/armv5/libffmpeg.so
LOCAL_PRELINK_MODULE := true
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_ALLOW_UNDEFINED_SYMBOLS=false
LOCAL_MODULE := ffmpeg-test-jni
LOCAL_SRC_FILES := ffmpeg-test-jni.cpp
LOCAL_CPP_FEATURES += exceptions
LOCAL_CPP_FEATURES += rtti
LOCAL_C_INCLUDES := $(LOCAL_PATH)/ffmpeg/android/armv5/include
LOCAL_SHARED_LIBRARY := ffmpeg-prebuilt
LOCAL_LDLIBS := -llog -ljnigraphics -lz -lm $(LOCAL_PATH)/ffmpeg/android/armv5/libffmpeg.so
include $(BUILD_SHARED_LIBRARY)
这里有一些解码音频的代码,你可以将它映射为视频
#include <stdio.h>
#include <jni.h>
#include <sys/time.h>
#include <android/log.h>
#include <android/bitmap.h>
#include <jni.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include<stdbool.h>
#include <pthread.h>
#include<exception>
#ifndef INT64_C
#define INT64_C(c) (c ## LL)
#define UINT64_C(c) (c ## ULL)
#endif
extern "C"{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavfilter/avcodec.h>
#include <libavfilter/buffersink.h>
#include <libavfilter/buffersrc.h>
}
#define LOG_TAG "FFmpegTest"
#define LOG_LEVEL 10
#define LOGI(level, ...) if (level <= LOG_LEVEL) {__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__);}
#define LOGE(level, ...) if (level <= LOG_LEVEL) {__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__);}
using namespace std;
AVFormatContext *fmt_ctx[1000];
AVCodecContext *dec_ctx[1000];
int audio_stream_index[1000];
int sampleRate[1000];
int channels[1000];
extern "C"{
void descErr(int e){
char x[1000];
av_strerror(e,x,sizeof(x));
LOGE(10,x);
}
JNIEXPORT void JNICALL Java_com_Decoder_initialize(JNIEnv *pEnv, jobject pObj){
try{
avcodec_register_all();
av_register_all();
avformat_network_init();
LOGE(10,"FFMPEG initialization done");
}catch(std::exception e){}
}
JNIEXPORT void JNICALL Java_com_Decoder_releaseEverything(JNIEnv *pEnv, jobject pObj,int ind){
try{
if (dec_ctx[ind]!=NULL && dec_ctx[ind]){
avcodec_close(dec_ctx[ind]);
LOGE(10,"dec_ctx closed");
}
if(fmt_ctx[ind]!=NULL && fmt_ctx[ind]){
avformat_close_input(&fmt_ctx[ind]);
LOGE(10,"fmt_ctx closed");
}
}
catch(std::exception e){}
}
JNIEXPORT int JNICALL Java_com_Decoder_openStream(JNIEnv *pEnv, jobject pObj, jstring streamName,int ind){
try{
int ret,er;
AVCodec *dec;
LOGE(10,"Starting Open Stream");
const char *stream=(char *)pEnv->GetStringUTFChars(streamName, NULL);
if((er=avformat_open_input(&fmt_ctx[ind], stream, NULL, NULL))< 0){
LOGE(10,"Cannot open input file");
descErr(er);
return -1;
}
LOGE(10,"File opened");
if(avformat_find_stream_info(fmt_ctx[ind], NULL) < 0){
LOGE(10,"Cannot find stream information");
return -1;
}
LOGE(10,"Stream information found");
if((audio_stream_index[ind] = av_find_best_stream(fmt_ctx[ind], AVMEDIA_TYPE_AUDIO, -1, -1, &dec, 0))<0){
LOGE(10,"Cannot find a audio stream in the input file\n");
return -1;
}
LOGE(10,"Found audio stream");
dec_ctx[ind] = fmt_ctx[ind]->streams[audio_stream_index[ind]]->codec;
if(avcodec_open2(dec_ctx[ind], dec, NULL) < 0){
LOGE(10,"Cannot open audio decoder\n");
return -1;
}
LOGE(10,"Decoder found");
sampleRate[ind]=fmt_ctx[ind]->streams[audio_stream_index[ind]]->codec->sample_rate;
channels[ind]=fmt_ctx[ind]->streams[audio_stream_index[ind]]->codec->channels;
}
catch(std::exception e){}
return ((channels[ind]& 3)| (sampleRate[ind]<<2));
}
JNIEXPORT jbyteArray JNICALL Java_com_Decoder_getNextFrame(JNIEnv *pEnv, jobject pObj, int ind){
try{
AVPacket packet;
AVFrame *frame = NULL;
int data_size,nFrames;
int ret;
jbyteArray result;
if(av_read_frame(fmt_ctx[ind], &packet)<0){
result = pEnv->NewByteArray(0);
return result;
}
if(packet.stream_index == audio_stream_index[ind]){
if (!(frame = avcodec_alloc_frame())){
LOGE(10,"Out Of Memory");
return NULL;
}
avcodec_get_frame_defaults(frame);
ret = avcodec_decode_audio4(dec_ctx[ind], frame, &nFrames, &packet);
if (ret < 0){
LOGE(10,"Error reading data");
av_free(frame);
return NULL;
}
if(nFrames>0){
data_size = av_samples_get_buffer_size(NULL, dec_ctx[ind]->channels,frame->nb_samples,dec_ctx[ind]->sample_fmt, 1);
result = pEnv->NewByteArray(data_size);
if (result == NULL){
av_free(frame);
return NULL;
}
pEnv->SetByteArrayRegion(result, 0, data_size, (jbyte*)frame->data[0]);
av_free(frame);
return result;
}
}
}
catch(std::exception e){
LOGE(10,"Native Exception");
}
return NULL;
}
}