已解决:问题出在我Java层的buffer和NDK的buffer是共享的,然后我为了加快速度,主线程截图和NDK的编码过程多线程进行,导致主线程获取出下一帧时污染了部分正在转换的数据。。。
解决过程:仙人掌D 的文章给了我解决方法,就是用ffplay打开编码前的rgb帧和yuv帧的数据,后来又对比了Java层的bmp数据,才突然意识到Java层的bmp没问题,为何传到NDK后,rgb就有问题了呢,最神奇的是rgb帧和yuv帧的问题还不一样,应该是污染程度不一样,yuv污染更严重,我猜应该是因为sws转换过程时间较长,上面一部分没污染,下面一部分污染了
另外编译FFmpeg和x264也使用了仙人掌D 的文章,特此感谢!
// 1、查找编码器
AVCodec *avcodec = avcodec_find_encoder(AV_CODEC_ID_H264);
if (avcodec == NULL){
return JNI_FALSE;
}
//1、获取编码器上下文
AVCodecContext *avcodec_context = avcodec_alloc_context3(avcodec);
//2、设置编解码器上下文参数
avcodec_context->pix_fmt = AV_PIX_FMT_YUV420P;
avcodec_context->width = width;
avcodec_context->height = width;
// 设置帧率25fps
avcodec_context->time_base = (AVRational){1, 25};
avcodec_context->framerate = (AVRational){25, 1};
// 设置码率
avcodec_context->bit_rate = 4096000;
// 设置GOP
avcodec_context->gop_size = 250;
avcodec_context->max_b_frames = 0; //必须是0,否则Mac&iOS无法播放
if (avcodec->id == AV_CODEC_ID_H264) {
av_opt_set(avcodec_context->priv_data, "preset", "slow", 0);
av_opt_set(avcodec_context->priv_data, "tune", "film", 0);
}
int openRet = avcodec_open2(avcodec_context, avcodec, NULL);
if (openRet < 0) {
return JNI_FALSE;
}
// 2、内存空间填充
AVFrame *rgbFrame = av_frame_alloc();
rgbFrame->format =AV_PIX_FMT_BGRA; //AV_PIX_FMT_RGBA,AV_PIX_FMT_ABGR,AV_PIX_FMT_ARGB
rgbFrame->width = width;
rgbFrame->height = width;
AVFrame *yuvFrame = av_frame_alloc();
yuvFrame->format = avcodec_context->pix_fmt;
yuvFrame->width = width;
yuvFrame->height = width;
av_frame_get_buffer(rgbFrame, 32);
av_frame_get_buffer(yuvFrame, 32);
SwsContext *img_convert_ctx = sws_getContext(avcodec_context->width,
avcodec_context->height,
static_cast(rgbFrame->format),
avcodec_context->width,
avcodec_context->height,
avcodec_context->pix_fmt,
SWS_BICUBIC, NULL, NULL, NULL);
循环处理图片序列:
while ... {
int *bmpIntData = env->GetIntArrayElements(bmpIntArray, &isCopy);
const uint8_t *bmpData = (const uint8_t *)bmpIntData;
av_image_fill_arrays(rgbFrame->data,
rgbFrame->linesize,
bmpData,
static_cast(rgbFrame->format),
rgbFrame->width,
rgbFrame->height,
1);
int ret = sws_scale(img_convert_ctx, rgbFrame->data, rgbFrame->linesize, 0, avcodec_context->height, yuvFrame->data, yuvFrame->linesize);
if (0 > ret) {
status =JNI_FALSE;
break;
}
yuvFrame->pts = i;
encodeFrame(avcodec_context, yuvFrame, av_packet, h264Output);
}
//其他一些收尾工作
//mergeH264AndAacToMp4 封装成mp4
下面是视频里图片淡入淡出过程的截图,有奇怪的半块灰色蒙层
网友评论