The simplest mobile-based FFmpeg example: Android Video Decoder-Single library version

Source: Internet
Author: User
Tags gettext sprintf

This document records the FFmpeg-based video decoder on another Android platform. Unlike the decoder documented in the previous article, the decoder documented in this article no longer uses class libraries such as libavcodec.so, libavformat.so, and only uses a class library--libffmpeg.so. The source code for the video decoder C language comes from the simplest ffmpeg+sdl-based video player. The related concepts are no longer duplicated.


The packaging of the FFmpeg class library records the way the FFmpeg class library is packaged. The FFmpeg class library under the Android platform contains the following:
  • libavformat-56.so
  • Libavcodec-56.so
  • Libavfilter-5.so
  • Libavdevice-56.so
  • Libavutil-54.so
  • Libpostproc-53.so
  • Libswresample-1.so
  • ibswscale-3.so 

With a large number, it is cumbersome to use these libraries directly. As a result, they can be combined into a single class library. The specific Package command is the one behind "make install" in the script below.

cd ffmpeg

make clean

export NDK=/home/leixiaohua1020/cdtworkspace/android-ndk-r9d

export PREBUILT=$NDK/toolchains/arm-linux-androideabi-4.8/prebuilt

export PLATFORM=$NDK/platforms/android-8/arch-arm

export PREFIX=../ff-pure-onelib

build_one(){

  ./configure --target-os=linux --prefix=$PREFIX --enable-cross-compile --enable-runtime-cpudetect --disable-asm --arch=arm --cc=$PREBUILT/linux-x86_64/bin/arm-linux-androideabi-gcc --cross-prefix=$PREBUILT/linux-x86_64/bin/arm-linux-androideabi- --disable-stripping --nm=$PREBUILT/linux-x86_64/bin/arm-linux-androideabi-nm --sysroot=$PLATFORM --enable-gpl --enable-static --disable-shared --enable-nonfree --enable-version3 --enable-small --enable-zlib --disable-ffprobe --disable-ffplay --disable-ffmpeg --disable-ffserver --disable-debug --extra-cflags="-fPIC -DANDROID -D__thumb__ -mthumb -Wfatal-errors -Wno-deprecated -mfloat-abi=softfp -marm -march=armv7-a"

}

 

build_one

 

make

make install

 

$PREBUILT/linux-x86_64/bin/arm-linux-androideabi-ld -rpath-link=$PLATFORM/usr/lib -L$PLATFORM/usr/lib -L$PREFIX/lib -soname libffmpeg.so -shared -nostdlib -Bsymbolic --whole-archive --no-undefined -o $PREFIX/libffmpeg.so libavcodec/libavcodec.a libavfilter/libavfilter.a libswresample/libswresample.a libavformat/libavformat.a libavutil/libavutil.a libswscale/libswscale.a libpostproc/libpostproc.a libavdevice/libavdevice.a -lc -lm -lz -ldl -llog --dynamic-linker=/system/bin/linker $PREBUILT/linux-x86_64/lib/gcc/arm-linux-androideabi/4.8/libgcc.a

 

cd ..


Need to note:

(1) Unlike the previously recorded script, this script no longer needs to modify the contents of the Configure (generated by *.a instead of *.so, and does not involve a version number issue).

(2) The script in the previous document is configure "--enable-shared--disable-static", the script configure in the time set is "--enable-static-- Disable-shared ". When the compilation is complete, the following is generated:

  • Libavcodec.a

  • Libavfilter.a

  • Libswresample.a

  • Libavformat.a

  • Libavutil.a

  • Libswscale.a

  • Libpostproc.a

  • Libavdevice.a

When the script finishes running, the above *.A file will be packaged as 1 *.so files:

  • Libffmpeg.so

There is no difference between the combined class library usage and the class library usage methods before merging.

The directory structure of the source code project. The Java source code is in the SRC directory, and the C code is in the JNI directory. The Java-side code for the Android program is located in Src\com\leixiaohua1020\sffmpegandroiddecoder\mainactivity.java, as shown below.
/**
 * The simplest FFmpeg-based video decoder - Android - Single library version
 * Simplest FFmpeg Android Decoder - One Library
 *
 * Lei Lei Xiaohua
 * leixiaohua1020@126.com
 * Communication University of China / Digital TV Technology
 * Communication University of China / Digital TV Technology
 * http://blog.csdn.net/leixiaohua1020
 *
 * This program is the simplest FFmpeg-based video decoder on the Android platform.
 * It can decode the input video data into YUV pixel data.
 *
 * This software is the simplest decoder based on FFmpeg in Android.
 * It can decode video stream to raw YUV data.
 *
 */
Package com.leixiaohua1020.sffmpegandroiddecoder;


Import android.os.Bundle;
Import android.os.Environment;
Import android.app.Activity;
Import android.text.Editable;
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;
Import android.widget.TextView;

Public class MainActivity extends Activity {


    @Override
    Protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
Button startButton = (Button) this.findViewById(R.id.button_start);
Final EditText urlEdittext_input= (EditText) this.findViewById(R.id.input_url);
Final EditText urlEdittext_output= (EditText) this.findViewById(R.id.output_url);

startButton.setOnClickListener(new OnClickListener() {
Public void onClick(View arg0){

String folderurl=Environment.getExternalStorageDirectory().getPath();

String urltext_input=urlEdittext_input.getText().toString();
String inputurl=folderurl+"/"+urltext_input;

String urltext_output=urlEdittext_output.getText().toString();
String outputurl=folderurl+"/"+urltext_output;

Log.i("inputurl",inputurl);
Log.i("outputurl", outputurl);

Decode(inputurl,outputurl);

}
});
    }

    @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;
    }
    
    //JNI
    Public native int decode(String inputurl, String outputurl);
    
    Static{
    System.loadLibrary("ffmpeg");
    System.loadLibrary("sffdecoder");
    }
}

The C-language side source code is located in Jni/simplest_ffmpeg_decoder.c, as shown below.

/**
 * The simplest FFmpeg-based video decoder - Android - Single library version
 * Simplest FFmpeg Android Decoder - One Library
 *
 * Lei Lei Xiaohua
 * leixiaohua1020@126.com
 * Communication University of China / Digital TV Technology
 * Communication University of China / Digital TV Technology
 * http://blog.csdn.net/leixiaohua1020
 *
 * This program is the simplest FFmpeg-based video decoder on the Android platform.
 * It can decode the input video data into YUV pixel data.
 *
 * This software is the simplest decoder based on FFmpeg in Android.
 * It can decode video stream to raw YUV data.
 *
 */


#include <stdio.h>
#include <time.h>

#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavutil/log.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


//Output FFmpeg‘s av_log()
Void custom_log(void *ptr, int level, const char* fmt, va_list vl){
FILE *fp=fopen("/storage/emulated/0/av_log.txt","a+");
If(fp){
Vfprintf(fp,fmt,vl);
Fflush(fp);
Fclose(fp);
}
}

JNIEXPORT jint JNICALL Java_com_leixiaohua1020_sffmpegandroiddecoder_MainActivity_decode
  (JNIEnv *env, jobject obj, jstring input_jstr, jstring output_jstr)
{
AVFormatContext *pFormatCtx;
Int i, videoindex;
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
AVFrame *pFrame, *pFrameYUV;
Uint8_t *out_buffer;
AVPacket *packet;
Int y_size;
Int ret, got_picture;
Struct SwsContext *img_convert_ctx;
FILE *fp_yuv;
Int frame_cnt;
Clock_t time_start, time_finish;
Double time_duration = 0.0;

Char input_str[500]={0};
Char output_str[500]={0};
Char info[1000]={0};
Sprintf(input_str,"%s",(*env)->GetStringUTFChars(env,input_jstr, NULL));
Sprintf(output_str,"%s",(*env)->GetStringUTFChars(env,output_jstr, NULL));

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

Av_register_all();
Avformat_network_init();
pFormatCtx = avformat_alloc_context();

If(avformat_open_input(&pFormatCtx,input_str,NULL,NULL)!=0){
LOGE("Couldn‘t open input stream.\n");
Return -1;
}
If(avformat_find_stream_info(pFormatCtx,NULL)<0){
LOGE("Couldn't find stream information.\n");
Return -1;
}
Videoindex=-1;
For(i=0; i<pFormatCtx->nb_streams; i++)
If(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO){
Videoindex=i;
Break;
}
If(videoindex==-1){
LOGE("Couldn't find a video stream.\n");
Return -1;
}
pCodecCtx=pFormatCtx->streams[videoindex]->codec;
pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
If(pCodec==NULL){
LOGE("Couldn't find Codec.\n");
Return -1;
}
If(avcodec_open2(pCodecCtx, pCodec,NULL)<0){
LOGE("Couldn‘t open codec.\n");
Return -1;
}

pFrame=av_frame_alloc();
pFrameYUV=av_frame_alloc();
Out_buffer=(uint8_t *)av_malloc(avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));
Avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);
Packet=(AVPacket *)av_malloc(sizeof(AVPacket));

Img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);

  
  Sprintf(info, "[Input ]%s\n", input_str);
  Sprintf(info, "%s[Output ]%s\n",info,output_str);
  Sprintf(info, "%s[Format ]%s\n",info, pFormatCtx->iformat->name);
  Sprintf(info, "%s[Codec ]%s\n",info, pCodecCtx->codec->name);
  Sprintf(info, "%s[Resolution]%dx%d\n",info, pCodecCtx->width,pCodecCtx->height);


  Fp_yuv=fopen(output_str,"wb+");
  If(fp_yuv==NULL){
Printf("Cannot open output file.\n");
Return -1;
}

Frame_cnt=0;
Time_start = clock();

While(av_read_frame(pFormatCtx, packet)>=0){
If(packet->stream_index==videoindex){
Ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
If(ret < 0){
LOGE("Decode Error.\n");
Return -1;
}
If(got_picture){
Sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height,
pFrameYUV->data, pFrameYUV->linesize);

Y_size=pCodecCtx->width*pCodecCtx->height;
Fwrite(pFrameYUV->data[0],1,y_size,fp_yuv); //Y
Fwrite(pFrameYUV->data[1],1,y_size/4,fp_yuv); //U
Fwrite(pFrameYUV->data[2],1,y_size/4,fp_yuv); //V
//Output info
Char pictype_str[10]={0};
Switch(pFrame->pict_type){
Case AV_PICTURE_TYPE_I: sprintf(pictype_str,"I");break;
Case AV_PICTURE_TYPE_P: sprintf(pictype_str,"P");break;
Case AV_PICTURE_TYPE_B: sprintf(pictype_str,"B");break;
Default:sprintf(pictype_str,"Other");break;
}
LOGI("Frame Index: %5d. Type:%s",frame_cnt,pictype_str);
Frame_cnt++;
}
}
Av_free_packet(packet);
}
//flush decoder
//FIX: Flush Frames remaining in Codec
While (1) {
Ret = avcodec_decode_video2(pCodecCtx, pFrame, &
Got_picture, packet);
If (ret < 0)
Break;
If (!got_picture)
Break;
Sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height,
pFrameYUV->data, pFrameYUV->linesize);
Int y_size=pCodecCtx->width*pCodecCtx->height;
Fwrite(pFrameYUV->data[0],1,y_size,fp_yuv); //Y
Fwrite(pFrameYUV->data[1],1,y_size/4,fp_yuv); //U
Fwrite(pFrameYUV->data[2],1,y_size/4,fp_yuv); //V
//Output info
Char pictype_str[10]={0};
Switch(pFrame->pict_type){
Case AV_PICTURE_TYPE_I: sprintf(pictype_str,"I");break;
Case AV_PICTURE_TYPE_P: sprintf(pictype_str,"P");break;
Case AV_PICTURE_TYPE_B: sprintf(pictype_str,"B");break;
Default:sprintf(pictype_str,"Other");break;
}
LOGI("Frame Index: %5d. Type:%s",frame_cnt,pictype_str);
Frame_cnt++;
}
Time_finish = clock();
Time_duration=(double)(time_finish - time_start);

Sprintf(info, "%s[Time ]%fms\n",info,time_duration);
Sprintf(info, "%s[Count ]%d\n",info,frame_cnt);

sws_freeContext(img_convert_ctx);

  Fclose(fp_yuv);

Av_frame_free(&pFrameYUV);
Av_frame_free(&pFrame);
Avcodec_close(pCodecCtx);
Avformat_close_input(&pFormatCtx);

Return 0;
}


The Android.mk file is located in Jni/android.mk, as shown below.


# Android.mk for FFmpeg
#
# Lei Xiaohua 雷霄骅
# leixiaohua1020@126.com
# http://blog.csdn.net/leixiaohua1020
#

LOCAL_PATH := $(call my-dir)

# FFmpeg library
Include $(CLEAR_VARS)
LOCAL_MODULE := ffmpeg
LOCAL_SRC_FILES := libffmpeg.so
Include $(PREBUILT_SHARED_LIBRARY)


# Program
Include $(CLEAR_VARS)
LOCAL_MODULE := sffdecoder
LOCAL_SRC_FILES :=simplest_ffmpeg_decoder.c
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
LOCAL_LDLIBS := -llog -lz
LOCAL_SHARED_LIBRARIES := ffmpeg
Include $(BUILD_SHARED_LIBRARY)


The results of running the results app on your phone are as shown in.
The stand-alone "Start" button allows you to decode the video files stored in the Kagan directory into YUV files (which need to wait a while to complete the decoding). Note that the decoded YUV file size is huge and may consume a lot of memory card space.
Download


Simplest FFmpeg Mobile
Project Home

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

Open source China: https://git.oschina.net/leixiaohua1020/simplest_ffmpeg_mobile

CSDN Project: http://download.csdn.net/detail/leixiaohua1020/8924391


This solution contains various examples of using FFMPEG to process multimedia on the mobile side:
[Android]
Simplest_android_player: Android interface-based video player
Simplest_ffmpeg_android_helloworld: FFmpeg-based HelloWorld program under Android platform
Simplest_ffmpeg_android_decoder: The simplest ffmpeg-based video decoder on the Android platform
Simplest_ffmpeg_android_decoder_onelib: The simplest ffmpeg-based video decoder on the Android Platform-Library edition
Simplest_ffmpeg_android_streamer: The simplest ffmpeg-based push-to-flow device under the Android platform
Simplest_ffmpeg_android_transcoder: FFmpeg command-line tool ported under Android platform
Simplest_sdl_android_helloworld: The simplest program for porting SDL to the Android platform
[IOS]
Simplest_ios_player: Video player based on iOS interface
HelloWorld program based on FFmpeg under the Simplest_ffmpeg_ios_helloworld:ios platform
The simplest ffmpeg-based video decoder under the Simplest_ffmpeg_ios_decoder:ios platform
The simplest ffmpeg based on the Simplest_ffmpeg_ios_streamer:ios platform
FFMPEG.C command-line tool ported under Simplest_ffmpeg_ios_transcoder:ios Platform
Simplest_sdl_ios_helloworld: The simplest program to migrate SDL to the iOS platform

Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.


Simplest FFmpeg-based mobile example: Android Video Decoder-Single library version

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.