android上的FFmpeg在avcodec_decode_video2函数中崩溃

时间:2015-06-05 22:41:45

标签: android ffmpeg mpeg-4

FFmpeg正在崩溃:libavcodec / utils.c avcodec_decode_video2在2400行附近

ret = avctx->codec->decode(avctx, picture, got_picture_ptr, &tmp);

所以我使用以下配置脚本(基于here)在android上编译了ffmpeg:

prefix=${src_root}/ffmpeg/android/arm

addi_cflags="-marm -Os -fpic"
addi_ldflags=""

./configure \
--prefix=${prefix} \
--target-os=linux \
--arch=arm \
--enable-shared \
--disable-doc \
--disable-programs \
--disable-symver \
--cross-prefix=${TOOLCHAIN}/bin/arm-linux-androideabi- \
--enable-cross-compile \
--enable-decoder=aac \
--enable-decoder=mpeg4 \
--enable-decoder=h263 \
--enable-decoder=flv \
--enable-decoder=mpegvideo \
--enable-decoder=mpeg2video \
--sysroot=${SYSROOT} \
--extra-cflags="${addi_cflags}" \
--pkg-config=$(which pkg-config) >> ${build_log} 2>&1 || die "Couldn't configure ffmpeg"

* .so文件被复制到我从我的Android.mk脚本引用的项目中:

LOCAL_PATH := $(call my-dir)
FFMPEG_PATH=/path/to/android-ffmpeg-with-rtmp/build/dist

include $(CLEAR_VARS)
LOCAL_MODULE := libavcodec
LOCAL_SRC_FILES :=$(FFMPEG_PATH)/lib/libavcodec-56.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := libavdevice
LOCAL_SRC_FILES :=$(FFMPEG_PATH)/lib/libavdevice-56.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := libavfilter
LOCAL_SRC_FILES :=$(FFMPEG_PATH)/lib/libavfilter-5.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := libavformat
LOCAL_SRC_FILES :=$(FFMPEG_PATH)/lib/libavformat-56.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := libavutil
LOCAL_SRC_FILES :=$(FFMPEG_PATH)/lib/libavutil-54.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := libswresample
LOCAL_SRC_FILES :=$(FFMPEG_PATH)/lib/libswresample-1.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := libswscale
LOCAL_SRC_FILES :=$(FFMPEG_PATH)/lib/libswscale-3.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_LDLIBS := -llog
LOCAL_C_INCLUDES := $(FFMPEG_PATH)/include
#LOCAL_PRELINK_MODULE := false
LOCAL_MODULE    := axonffmpeg
LOCAL_SRC_FILES := libffmpeg.c
LOCAL_CFLAGS := -g
LOCAL_SHARED_LIBRARIES := libavcodec libavdevice libavfilter libavformat libavutil libswresample libswscale
include $(BUILD_SHARED_LIBRARY)

我正在构建一个小包装来解码来自外部相机的帧(mpeg4视频,第2部分简单配置文件):

#include <jni.h>
#include <string.h>
#include <android/log.h>

#include <libavutil/opt.h>
#include <libavcodec/avcodec.h>
#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavutil/imgutils.h>
#include <libavutil/mathematics.h>
#include <libavutil/samplefmt.h>

#define DEBUG_TAG "LibFFMpeg:NDK"

AVCodec *codec;
AVFrame *current_frame;
AVCodecContext *context;

int resWidth, resHeight, bitRate;

void my_log_callback(void *ptr, int level, const char *fmt, va_list vargs);

jint Java_com_mycompany_axonv2_LibFFMpeg_initDecoder(JNIEnv * env, jobject this,
  jint _resWidth, jint _resHeight, jint _bitRate)
{
     __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "initDecoder called");

    int len;

    resWidth = _resWidth;
    resHeight = _resHeight;
    bitRate = _bitRate;
    av_log_set_callback(my_log_callback);
    av_log_set_level(AV_LOG_VERBOSE);
    avcodec_register_all();
    codec = avcodec_find_encoder(AV_CODEC_ID_MPEG4);
    if (!codec) {
      __android_log_print(ANDROID_LOG_ERROR, DEBUG_TAG, "codec %d not found", AV_CODEC_ID_MPEG4);
      return -1;
    }
    context = avcodec_alloc_context3(codec);    
    if (!context) {
      __android_log_print(ANDROID_LOG_ERROR, DEBUG_TAG,  "Could not allocate codec context");
      return -1;
    }

    context->width = resWidth;
    context->height = resHeight;
    context->bit_rate = bitRate;
    context->pix_fmt = AV_PIX_FMT_YUV420P;
    context->time_base.den = 6;
    context->time_base.num = 1;
    int openRet = avcodec_open2(context, codec, NULL);
    if (openRet < 0) {
      __android_log_print(ANDROID_LOG_ERROR, DEBUG_TAG,  "Could not open codec, error:%d", openRet);
      return -1;
    }
    current_frame = av_frame_alloc();    
    if (!current_frame) {
      __android_log_print(ANDROID_LOG_ERROR, DEBUG_TAG,  "Could not allocate video frame");
      return -1;
    }    
    return 0;    
}


void my_log_callback(void *ptr, int level, const char *fmt, va_list vargs) {

  __android_log_print (level, DEBUG_TAG, fmt, vargs);

}

jint Java_com_mycompany_axonv2_LibFFMpeg_queueFrameForDecoding(JNIEnv * env, jobject this,
  jlong pts, jbyteArray jBuffer)
{

    __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "queueFrameForDecoding called");

    AVPacket avpkt;
    av_init_packet(&avpkt);
    int buffer_len = (*env)->GetArrayLength(env, jBuffer);
    uint8_t* buffer = (uint8_t *) (*env)->GetByteArrayElements(env, jBuffer,0);
    int got_frame = 0;
    __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "copied %d bytes into uint8_t* buffer", buffer_len);

    av_packet_from_data(&avpkt, buffer, buffer_len);
    __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "av_packet_from_data called");

    avpkt.pts = pts;
    int ret = avcodec_decode_video2(context, current_frame, &got_frame, &avpkt);

    __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "avcodec_decode_video2 returned %d" , ret);

    (*env)->ReleaseByteArrayElements(env, jBuffer, (jbyte*) buffer, 0);
    __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "ReleaseByteArrayElements()");

    return 0;
}

好的,所以上面的init函数工作正常,queueFrameForDecoding工作到avcodec_decode_video2函数。我并不期待它能够正常工作,但是因为我已经记录输出到我们在该函数中的位置,我发现有一个调用(在avutil.c中): (最新代码中的第2400行)

avcodec_decode_video2(...) { 
   ....
        ret = avctx->codec->decode(avctx, picture, got_picture_ptr, &tmp);

init运行正常并找到编解码器和所有这些。在avcodec_decode_video2调用之前,一切都很顺利:

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'samsung/klteuc/klteatt:4.4.2/KOT49H/G900AUCU2ANG3:user/release-keys'
Revision: '14'
pid: 19355, tid: 22584, name: BluetoothReadTh  >>> com.mycompany.axonv2 <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000000
r0 79308400  r1 79491710  r2 7b0b4a70  r3 7b0b49e8
r4 79308400  r5 79491710  r6 00000000  r7 7b0b49e8
r8 7b0b4a70  r9 7b0b4a80  sl 795106d8  fp 00000000
ip 00000000  sp 7b0b49b8  lr 7ba05c18  pc 00000000  cpsr 600f0010
d0  206c616768616c62  d1  6564206365646f63
d2  756f722065646f63  d3  20736920656e6974
d4  0b0a01000a0a0a0b  d5  0a630a01000a0a0a
d6  0a630a011a00f80a  d7  0b130a011a00f90a
d8  0000000000000000  d9  0000000000000000
d10 0000000000000000  d11 0000000000000000
d12 0000000000000000  d13 0000000000000000
d14 0000000000000000  d15 0000000000000000
d16 6369705f746f6720  d17 7274705f65727574
d18 8000000000000000  d19 00000b9e42bd5730
d20 0000000000000000  d21 0000000000000000
d22 7b4fd10400000000  d23 773b894877483b68
d24 0000000000000000  d25 3fc2f112df3e5244
d26 40026bb1bbb55516  d27 0000000000000000
d28 0000000000000000  d29 0000000000000000
d30 0000000000000000  d31 0000000000000000
scr 60000010
backtrace:
#00  pc 00000000  <unknown>
#01  pc 00635c14  /data/app-lib/com.mycompany.axonv2-6/libavcodec-56.so (avcodec_decode_video2+1128)

我不明白为什么它在尝试调用解码函数时会崩溃。我查看了编解码器函数指针列表,这应该是调用ff_h263_decode_frame(source,libavcodec / mpeg4videodec.c):

AVCodec ff_mpeg4_decoder = {
    .name                  = "mpeg4",
    .long_name             = NULL_IF_CONFIG_SMALL("MPEG-4 part 2"),
    .type                  = AVMEDIA_TYPE_VIDEO,
    .id                    = AV_CODEC_ID_MPEG4,
    .priv_data_size        = sizeof(Mpeg4DecContext),
    .init                  = decode_init,
    .close                 = ff_h263_decode_end,
    .decode                = ff_h263_decode_frame,
    .capabilities          = CODEC_CAP_DRAW_HORIZ_BAND | CODEC_CAP_DR1 |
                             CODEC_CAP_TRUNCATED | CODEC_CAP_DELAY |
                             CODEC_CAP_FRAME_THREADS,
    .flush                 = ff_mpeg_flush,
    .max_lowres            = 3,
    .pix_fmts              = ff_h263_hwaccel_pixfmt_list_420,
    .profiles              = NULL_IF_CONFIG_SMALL(mpeg4_video_profiles),
    .update_thread_context = ONLY_IF_THREADS_ENABLED(mpeg4_update_thread_context),
    .priv_class = &mpeg4_class,
};

我知道没有调用ff_h263_decode_frame函数,因为我添加了日志记录并且没有打印出来。 但是,如果我直接从avcodec_decode_video2调用ff_h263_decode_frame,那么我的日志记录会输出。我不想直接调用此函数,而是希望ffmpeg框架正常工作。我如何配置ffmpeg有什么问题吗?我已将mpegvideo,mpeg2video,flv,h263添加到配置脚本中,但没有人帮助它们(它们应该由--enable-decoder = mpeg4自动包含)。

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:1)

  

codec = avcodec_find_encoder(AV_CODEC_ID_MPEG4);

那应该是avcodec_find_decoder(),而不是avcodec_find_encoder()。您的解码调用失败/崩溃是因为您打开了编码器而不是解码器,因此解码回调为NULL(这就是它因NPE而死的原因)。