1

我正在尝试使用 android NDK 和 ffmpeg 来提取视频的第一帧。我在这个网站上看到了很多使用命令行代码的示例,这些示例看起来像是ffmpeg -i video.mp4 -vframes 1 -an -f image2 -y thumbmail.png 2>&1我是 android NDK 的新手,但我不确定这如何在 jni 中的本机代码文件中发挥作用。它会在本机方法中使用,还是有办法使用 ffmpeg 库以另一种方式完成相同的任务?

4

2 回答 2

4

如果您只想提取帧(而不是高级视频管理),您可以使用这个 android 类。这绝对比为 android 编译和添加 ffmpeg 版本更容易......如果你仍然想使用 ffmpeg 库,我认为使用静态库会更容易(如果你只想提取帧),但我强烈建议您使用 Api 的课程。有时这个类会显示一些错误。如果发生这种情况,您可以添加和使用这个外部库而不是第一个。希望有用

于 2013-10-09T13:31:42.003 回答
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;
    }
}
于 2013-10-08T02:37:40.097 回答