背景:
本人新手,目前在尝试Android平台使用ffmpeg进行h264编码。我已经把ffmpeg编译成动态库并能够使用jni调用一些解码之类的操作。
但是今天想要进行h264编码操作却一直提示找不到编码器。我运行的是ffmpeg自带的例子encode_video.c。我将它稍微改造了一下输入输出,使用jni调用。
问题:
从打印的log来看,问题出codec = avcodec_find_encoder_by_name("libx264");一直返回NULL。
而如果我改成 avcodec_find_encoder(AV_CODEC_ID_H264),这个方法倒是不报错了,但是接下来的ret = avcodec_open2(c, codec, NULL);却会返回错误permission denied。
下面附带我编译x264、ffmpeg的脚本,以及相关代码:
我用来编译x264的脚本:
[Bash shell] 纯文本查看 复制代码 #!/bin/bash
NDK=/Users/路径打码了/Library/Android/sdk/ndk-bundle
API=17
PLATFORM=arm-linux-androideabi
TOOLCHAIN=$NDK/toolchains/$PLATFORM-4.9/prebuilt/darwin-x86_64
SYSROOT=$NDK/platforms/android-$API/arch-arm/
ISYSROOT=$NDK/sysroot
ASM=$ISYSROOT/usr/include/$PLATFORM
CPU=arm
PREFIX=$(pwd)/x264-lib
build_one()
{
./configure \
--prefix=$PREFIX \
--enable-static \
--enable-pic \
--disable-asm \
--disable-cli \
--host=arm-linux \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--extra-cflags="-I$ASM -isysroot $ISYSROOT" \
--extra-ldflags="-marm" \
--sysroot=$SYSROOT
}
build_one
make clean
make -j4
make install
下面是编译ffmpeg动态链接库的脚本:
[Bash shell] 纯文本查看 复制代码 #!/bin/bash
NDK=/Users/路径打码/Library/Android/sdk/ndk-bundle
API=17
PLATFORM=arm-linux-androideabi
TOOLCHAIN=$NDK/toolchains/$PLATFORM-4.9/prebuilt/darwin-x86_64
SYSROOT=$NDK/platforms/android-$API/arch-arm/
ISYSROOT=$NDK/sysroot
ASM=$ISYSROOT/usr/include/$PLATFORM
CPU=arm
PREFIX=$(pwd)/android/$CPU
H264=/Users/wangpeng55/ffmpeg/x264/x264-lib
build_one()
{
./configure \
--prefix=$PREFIX \
--target-os=android \
--enable-cross-compile \
--enable-runtime-cpudetect \
--disable-asm \
--disable-stripping \
--enable-gpl --enable-shared --disable-static --enable-nonfree --enable-version3 --enable-small --disable-vda --disable-iconv \
--disable-encoders --enable-libx264 --enable-libfaac --enable-encoder=libx264 --enable-encoder=libfaac \
--disable-muxers --enable-muxer=mov --enable-muxer=ipod --enable-muxer=psp --enable-muxer=mp4 --enable-muxer=avi \
--disable-decoders --enable-decoder=aac --enable-decoder=aac_latm --enable-decoder=h264 --enable-decoder=mpeg4 \
--disable-demuxers --enable-demuxer=h264 --enable-demuxer=avi --enable-demuxer=mpc --enable-demuxer=mov \
--disable-parsers --enable-parser=aac --enable-parser=ac3 --enable-parser=h264 \
--disable-protocols --enable-protocol=file \
--disable-bsfs --enable-bsf=aac_adtstoasc --enable-bsf=h264_mp4toannexb \
--disable-indevs --enable-zlib \
--disable-outdevs --disable-ffprobe --disable-ffplay --disable-ffmpeg --disable-ffserver --disable-debug \
--arch=arm \
--cc=$TOOLCHAIN/bin/arm-linux-androideabi-gcc \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--nm=$TOOLCHAIN/bin/arm-linux-androideabi-nm \
--sysroot=$SYSROOT \
--extra-cflags="-I$H264/include -isysroot $ISYSROOT -D__ANDROID_API__=$API -U_FILE_OFFSET_BITS -Os -fPIC -DANDROID -D__thumb__ -mthumb -Wfatal-errors -Wno-deprecated -mfloat-abi=softfp -marm" \
--extra-ldflags="-L$H264/lib"
$ADDITIONAL_CONFIGURE_FLAG
}
build_one
make clean
make -j4
make install
以上编译都能够成功编译。
接下来是进行编码的代码:
[C] 纯文本查看 复制代码 const char *filename, *codec_name;
const AVCodec *codec;
AVCodecContext *c = NULL;
int i, ret, x, y;
FILE *f;
AVFrame *frame;
AVPacket *pkt;
uint8_t endcode[] = {0, 0, 1, 0xb7};
filename = "/storage/emulated/0/output.h264";
codec_name = "libx264";
av_register_all();
/* find the mpeg1video encoder */
codec = avcodec_find_encoder_by_name(codec_name); // 1、此处获取h264编码器总为Null
if (!codec) {
LOGE("Codec id %d not found\n", AV_CODEC_ID_H264);
return -1;
}
c = avcodec_alloc_context3(codec);
if (!c) {
LOGE("Could not allocate video codec context\n");
return -1;
}
pkt = av_packet_alloc();
if (!pkt)
return -1;
/* put sample parameters */
c->bit_rate = 400000;
/* resolution must be a multiple of two */
c->width = 352;
c->height = 288;
/* frames per second */
c->time_base = (AVRational) {1, 25};
c->framerate = (AVRational) {25, 1};
/* emit one intra frame every ten frames
* check frame pict_type before passing frame
* to encoder, if frame->pict_type is AV_PICTURE_TYPE_I
* then gop_size is ignored and the output of encoder
* will always be I frame irrespective to gop_size
*/
c->gop_size = 10;
c->max_b_frames = 1;
c->pix_fmt = AV_PIX_FMT_YUV420P;
if (codec->id == AV_CODEC_ID_H264)
av_opt_set(c->priv_data, "preset", "slow", 0);
/* open it */
ret = avcodec_open2(c, codec, NULL); // 2、如果使AV_CODEC_ID_H264获取编码器,这个地方又会报错
if (ret < 0) {
LOGE("Could not open codec: %s\n", av_err2str(ret));
return -1;
}
f = fopen(filename, "wb");
if (!f) {
LOGE("Could not open %s\n", filename);
return -1;
}
frame = av_frame_alloc();
if (!frame) {
LOGE("Could not allocate video frame\n");
return -1;
}
frame->format = c->pix_fmt;
frame->width = c->width;
frame->height = c->height;
ret = av_frame_get_buffer(frame, 32);
if (ret < 0) {
LOGE("Could not allocate the video frame data\n");
return -1;
}
/* encode 1 second of video */
for (i = 0; i < 25; i++) {
fflush(stdout);
/* make sure the frame data is writable */
ret = av_frame_make_writable(frame);
if (ret < 0)
exit(1);
/* prepare a dummy image */
/* Y */
for (y = 0; y < c->height; y++) {
for (x = 0; x < c->width; x++) {
frame->data[0][y * frame->linesize[0] + x] = x + y + i * 3;
}
}
/* Cb and Cr */
for (y = 0; y < c->height / 2; y++) {
for (x = 0; x < c->width / 2; x++) {
frame->data[1][y * frame->linesize[1] + x] = 128 + y + i * 2;
frame->data[2][y * frame->linesize[2] + x] = 64 + x + i * 5;
}
}
frame->pts = i;
/* encode the image */
encode(c, frame, pkt, f);
}
/* flush the encoder */
encode(c, NULL, pkt, f);
/* add sequence end code to have a real MPEG file */
fwrite(endcode, 1, sizeof(endcode), f);
fclose(f);
avcodec_free_context(&c);
av_frame_free(&frame);
av_packet_free(&pkt);
LOGI("encode 2 finished");
return 0;
这个问题已经卡主我三天了。。。google都翻遍了,ffmpeg用了3.4.2和4.0.4两个版本都不行。一直不知道问题出在哪里,大概猜测试因为ffmpeg没有将lib264编译进so库?但是我要怎么检查我编译好的ffmpeg的动态链接库包含了lib264这样的第三方的类库呢??
请求大神帮忙,先谢谢了。
|