最簡單的基於FFmpeg的移動端例子:Android 視頻轉碼器

=====================================================

最簡單的基於FFmpeg的移動端例子系列文章列表:

最簡單的基於FFmpeg的移動端例子:Android HelloWorld

最簡單的基於FFmpeg的移動端例子:Android 視頻解碼器

最簡單的基於FFmpeg的移動端例子:Android 視頻解碼器-單個庫版

最簡單的基於FFmpeg的移動端例子:Android 推流器

最簡單的基於FFmpeg的移動端例子:Android 視頻轉碼器

最簡單的基於FFmpeg的移動端例子附件:Android 自帶播放器

最簡單的基於FFmpeg的移動端例子附件:SDL Android HelloWorld

最簡單的基於FFmpeg的移動端例子:IOS HelloWorld

最簡單的基於FFmpeg的移動端例子:IOS 視頻解碼器

最簡單的基於FFmpeg的移動端例子:IOS 推流器

最簡單的基於FFmpeg的移動端例子:IOS 視頻轉碼器

最簡單的基於FFmpeg的移動端例子附件:IOS自帶播放器

最簡單的基於FFmpeg的移動端例子:Windows Phone HelloWorld

=====================================================


本文記錄一個安卓平臺下基於FFmpeg的視頻轉碼器。該轉碼器實際上移植自ffmpeg工程中的ffmpeg.c源代碼。有關ffmpeg.c的源代碼可以參考文章《ffmpeg.c函數結構簡單分析(畫圖)》,在這裏就不重複記錄了。



源代碼

項目的目錄結構如圖所示。Java源代碼位於src目錄,而C代碼位於jni目錄。


Android程序Java端代碼位於src\com\leixiaohua1020\sffmpegandroidtranscoder\MainActivity.java,如下所示。
/**
 * 最簡單的基於FFmpeg的轉碼器-安卓
 * Simplest FFmpeg Android Transcoder
 * 
 * 雷霄驊  Lei Xiaohua
 * [email protected]
 * 馬小雨  Ma Xiaoyu
 * [email protected]
 * 中國傳媒大學/數字電視技術
 * Communication University of China / Digital TV Technology
 * http://blog.csdn.net/leixiaohua1020
 * 
 * 
 * 本程序是安卓平臺下的轉碼器。它移植於ffmpeg.c命令行工具。
 * 
 * This software is a Transcoder in Android.
 * It is transplanted from ffmpeg.c command line tools.
 * 
 */
package com.leixiaohua1020.sffmpegandroidtranscoder;

import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        final EditText cmdEdittext= (EditText) this.findViewById(R.id.editText_cmd);
        Button startButton= (Button) this.findViewById(R.id.button_start);
        
        startButton.setOnClickListener(new OnClickListener() {
			public void onClick(View arg0){
				String cmdline=cmdEdittext.getText().toString();
		        String[] argv=cmdline.split(" ");
		        Integer argc=argv.length;
		        ffmpegcore(argc,argv);
			}
		});
    }

    public native int ffmpegcore(int argc,String[] argv);
    static{
    	System.loadLibrary("avutil-54");
    	System.loadLibrary("swresample-1");
    	System.loadLibrary("avcodec-56");
    	System.loadLibrary("avformat-56");
    	System.loadLibrary("swscale-3");
    	System.loadLibrary("postproc-53");
    	System.loadLibrary("avfilter-5");
    	System.loadLibrary("avdevice-56");
    	System.loadLibrary("sfftranscoder");
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
    
}

C語言端源代碼包含多個文件。其中下面文件拷貝自FFmpeg源代碼:
cmdutils.c
cmdutils.h
cmdutils_common_opts.h
config.h
ffmpeg.h
ffmpeg_filter.c
ffmpeg_opt.c

在編譯ffmpeg.c的時候,除了需要FFmpeg SDK中的頭文件之外,還需要從源代碼中拷貝下面頭文件。

libavformat/ffm.h
libavformat/network.h
libavformat/os_support.h
libavformat/url.h
libavutil/libm.h

ffmpeg_mod.c是修改後的ffmpeg.c文件。ffmpeg.c本身是用於命令行使用的程序,因此在改爲類庫調用的時候需要對源代碼做一些修改。例如去掉一些exit(0),釋放一些變量,main()函數改名爲ffmpegmain()等。

ffmpeg_jni.c是ffmpeg.c和Android系統之間的接口。該部分的源代碼如下所示。

/**
 * 最簡單的基於FFmpeg的轉碼器-安卓
 * Simplest FFmpeg Android Transcoder
 *
 * 雷霄驊  Lei Xiaohua
 * [email protected]
 * 馬小雨  Ma Xiaoyu
 * [email protected]
 * 中國傳媒大學/數字電視技術
 * Communication University of China / Digital TV Technology
 * http://blog.csdn.net/leixiaohua1020
 *
 *
 * 本程序是安卓平臺下的轉碼器。它移植於ffmpeg.c命令行工具。
 *
 * This software is a Transcoder in Android.
 * It is transplanted from ffmpeg.c command line tools.
 *
 */

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

#ifdef ANDROID
#include <jni.h>
#include <android/log.h>
#define LOGE(format, ...)  __android_log_print(ANDROID_LOG_ERROR, "(>_<)", format, ##__VA_ARGS__)
#define LOGI(format, ...)  __android_log_print(ANDROID_LOG_INFO,  "(^_^)", format, ##__VA_ARGS__)
#else
#define LOGE(format, ...)  printf("(>_<) " format "\n", ##__VA_ARGS__)
#define LOGI(format, ...)  printf("(^_^) " format "\n", ##__VA_ARGS__)
#endif


int ffmpegmain(int argc, char **argv);

//Output FFmpeg's av_log()
void custom_log(void *ptr, int level, const char* fmt, va_list vl){

	//To TXT file

	FILE *fp=fopen("/storage/emulated/0/av_log.txt","a+");
	if(fp){
		vfprintf(fp,fmt,vl);
		fflush(fp);
		fclose(fp);
	}


	//To Logcat
	//LOGE(fmt, vl);
}

JNIEXPORT jint JNICALL Java_com_leixiaohua1020_sffmpegandroidtranscoder_MainActivity_ffmpegcore( JNIEnv * env, jobject thiz, jint cmdnum, jobjectArray cmdline)
{

  //FFmpeg av_log() callback
  av_log_set_callback(custom_log);

  int argc=cmdnum;
  char** argv=(char**)malloc(sizeof(char*)*argc);
  
  int i=0;
  for(i=0;i<argc;i++)
  {
    jstring string=(*env)->GetObjectArrayElement(env,cmdline,i);
    const char* tmp=(*env)->GetStringUTFChars(env,string,0);
    argv[i]=(char*)malloc(sizeof(char)*1024);
    strcpy(argv[i],tmp);
  }
  
  ffmpegmain(argc,argv);

  for(i=0;i<argc;i++){
    free(argv[i]);
  }
  free(argv);
  return 0;

}

Android.mk文件位於jni/Android.mk,如下所示。

# Android.mk for FFmpeg
#
# Lei Xiaohua 雷霄驊
# [email protected]
# http://blog.csdn.net/leixiaohua1020
# 

LOCAL_PATH := $(call my-dir)

# FFmpeg library
include $(CLEAR_VARS)
LOCAL_MODULE := avcodec
LOCAL_SRC_FILES := libavcodec-56.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := avdevice
LOCAL_SRC_FILES := libavdevice-56.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := avfilter
LOCAL_SRC_FILES := libavfilter-5.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := avformat
LOCAL_SRC_FILES := libavformat-56.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := avutil
LOCAL_SRC_FILES := libavutil-54.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := postproc
LOCAL_SRC_FILES := libpostproc-53.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := swresample
LOCAL_SRC_FILES := libswresample-1.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := swscale
LOCAL_SRC_FILES := libswscale-3.so
include $(PREBUILT_SHARED_LIBRARY)

# Program
include $(CLEAR_VARS)
LOCAL_MODULE := sfftranscoder
LOCAL_SRC_FILES :=ffmpeg_jni.c ffmpeg_mod.c ffmpeg_opt.c ffmpeg_filter.c cmdutils.c
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
LOCAL_LDLIBS := -llog -lz
LOCAL_SHARED_LIBRARIES := avcodec avdevice avfilter avformat avutil postproc swresample swscale
include $(BUILD_SHARED_LIBRARY)

運行結果

App在手機上運行後的結果如下圖所示。


注意需要把等待轉碼的視頻文件拷貝至存儲卡相應的目錄中。例如對於上述截圖的情況,需要將sintel.mp4拷貝至存儲卡的根目錄中。

單擊“Start”按鈕開始轉碼,將存儲卡中的sintel.mp4轉碼爲sintel.mkv。



下載


simplest ffmpeg mobile

項目主頁

Github:https://github.com/leixiaohua1020/simplest_ffmpeg_mobile

開源中國:https://git.oschina.net/leixiaohua1020/simplest_ffmpeg_mobile

SourceForge:https://sourceforge.net/projects/simplestffmpegmobile/


CSDN工程下載地址:http://download.csdn.net/detail/leixiaohua1020/8924391


本解決方案包含了使用FFmpeg在移動端處理多媒體的各種例子:
[Android]
simplest_android_player: 基於安卓接口的視頻播放器
simplest_ffmpeg_android_helloworld: 安卓平臺下基於FFmpeg的HelloWorld程序
simplest_ffmpeg_android_decoder: 安卓平臺下最簡單的基於FFmpeg的視頻解碼器
simplest_ffmpeg_android_decoder_onelib: 安卓平臺下最簡單的基於FFmpeg的視頻解碼器-單庫版
simplest_ffmpeg_android_streamer: 安卓平臺下最簡單的基於FFmpeg的推流器
simplest_ffmpeg_android_transcoder: 安卓平臺下移植的FFmpeg命令行工具
simplest_sdl_android_helloworld: 移植SDL到安卓平臺的最簡單程序
[IOS]
simplest_ios_player: 基於IOS接口的視頻播放器
simplest_ffmpeg_ios_helloworld: IOS平臺下基於FFmpeg的HelloWorld程序
simplest_ffmpeg_ios_decoder: IOS平臺下最簡單的基於FFmpeg的視頻解碼器
simplest_ffmpeg_ios_streamer: IOS平臺下最簡單的基於FFmpeg的推流器
simplest_ffmpeg_ios_transcoder: IOS平臺下移植的ffmpeg.c命令行工具
simplest_sdl_ios_helloworld: 移植SDL到IOS平臺的最簡單程序

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章