2015-06-05 4 views
1

FFmpeg разваливается на: кодек/utils.c avcodec_decode_video2 вокруг линии 2400FFmpeg на андроид происходит сбой в avcodec_decode_video2 функции

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

Так я составил FFmpeg на андроид, используя следующий скрипт (конфигурационный на основе из here) :

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" 

The * .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; 
} 

Хорошо, так что функция инициализации выше работает отлично и 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 (источник, кодек/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 не вызываются, потому что я добавил вход к нему и ни одно из них не печатается. Однако, если я просто вызываю ff_h263_decode_frame непосредственно из avcodec_decode_video2, тогда мой журнал будет выводиться. Я не хочу напрямую обращаться к этой функции, и я бы предпочел корректно работать с ffmpeg framework. Что-то не так с тем, как я настроил ffmpeg? Я добавил mpegvideo, mpeg2video, flv, h263, в скрипт configure, но ни один из них не помог им (они должны быть включены автоматически --enable-decoder = mpeg4).

Любая помощь была бы принята с благодарностью.

ответ

1

кодек = avcodec_find_encoder (AV_CODEC_ID_MPEG4);

Это должно быть avcodec_find_decoder(), а не avcodec_find_encoder(). Ваш декодирующий вызов терпит неудачу/сбой, потому что вы открыли кодер, а не декодер, поэтому обратный вызов декодирования NULL (вот почему он умирает с NPE).

+0

OMG! Спасибо. Не уверен, как я пропустил это 1000 раз, но я это сделал. –