2013-10-08 1 views
1

J'essaie d'utiliser Android NDK et ffmpeg pour extraire la première image d'une vidéo. J'ai vu beaucoup d'exemples sur ce site qui utilisent le code de ligne de commande qui ressemble quelque chose comme ffmpeg -i video.mp4 -vframes 1 -an -f image2 -y thumbmail.png 2>&1 Je suis nouveau sur Android NDK et je ne suis pas sûr de savoir comment cela joue dans le fichier de code natif dans le jni. Serait-il utilisé dans une méthode native ou existe-t-il un moyen d'accomplir la même tâche d'une autre manière en utilisant les bibliothèques ffmpeg?Extraction de la première image dans la vidéo en utilisant ffmpeg et android ndk

Répondre

2

essayer cette http://www.roman10.net/how-to-build-ffmpeg-for-android/

Android.mk ressemble à ce

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) 

Et voici un code pour décoder les signaux audio, vous pouvez mapper pour la vidéo

#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; 
    } 
} 
4

Si vous ne voulez extraire des cadres (pas de gestion vidéo avancée), vous pouvez utiliser this android class. C'est absolument plus simple que compiler et ajouter la version ffmpeg pour Android ... Si vous voulez toujours utiliser une librairie ffmpeg, je pense qu'il sera plus facile d'utiliser une librairie statique (si vous voulez extraire des frames seulement), mais je Nous vous conseillons vivement d'utiliser la classe Api. Parfois, cette classe montre quelques erreurs. Si cela se produit, vous pouvez ajouter et utiliser this external library au lieu du premier. J'espère que c'est utile

+0

La classe android ne fonctionnerait pas pour moi parce que je veux ajouter le cadre extrait à la vidéo à un certain endroit. Merci quand même. – Papajohn000

+0

Que voulez-vous dire par "certain emplacement". Vous pouvez extraire le cadre que vous voulez. Si vous souhaitez extraire la première image d'une vidéo: MediaMetadataRetriever media = new MediaMetadataRetriever(); media.setDataSource (chemin); Bitmap bitmap = media.getFrameAtTime (0, MediaMetadataRetriever.OPTION_CLOSEST); –

+0

Je voulais dire que je voulais prendre la première image puis peu après ajouter cette première image à un certain moment dans la vidéo. Donc je suppose que ce serait plus facile si j'utilisais ffmpeg à la fois pour obtenir le cadre et ensuite ajouter ce cadre à la vidéo. – Papajohn000

Questions connexes