【发布时间】:2015-06-05 22:41:44
【问题描述】:
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 自动包含)。
任何帮助将不胜感激。
【问题讨论】: