Android中使用FFMPEG将yuv420p编码为h264
16lz
2021-01-23
单帧
JNIEXPORT jbyteArray JNICALLJava_com_uestc_smileteeth_view_recordvideo_RecordVideoLib_encodeFrame(JNIEnv *env, jclass type, jbyteArray yuv420p_, jint width, jint height, jint index) { jbyte *yuv420p = (*env)->GetByteArrayElements(env, yuv420p_, NULL); AVCodec *pCodec; AVCodecContext *pCodecCtx = NULL; int i, ret, got_output; AVFrame *pFrame; AVPacket pkt; int y_size; jbyteArray h264; //编码格式; enum AVCodecID codec_id = AV_CODEC_ID_H264; int in_w = width, in_h = height; //注册所有编解码器; avcodec_register_all(); //寻找解码器; pCodec = avcodec_find_encoder(codec_id); if (!pCodec) { LOGI("Codec not found"); } pCodecCtx = avcodec_alloc_context3(pCodec); if (!pCodecCtx) { LOGI("Could not allocate video codec context!"); } pCodecCtx->bit_rate = 4000000; pCodecCtx->width = in_w; pCodecCtx->height = in_h; pCodecCtx->time_base.num = 1; pCodecCtx->time_base.den = 25; pCodecCtx->gop_size = 10; pCodecCtx->max_b_frames = 0; pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P; if (codec_id == AV_CODEC_ID_H264) { av_opt_set(pCodecCtx->priv_data, "preset", "slow", 0);// av_opt_set(pCodecCtx->priv_data, "preset", "superfast", 0);// av_opt_set(pCodecCtx->priv_data, "tune", "zerolatency", 0); } if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) { LOGI("Could not open codec!"); } pFrame = av_frame_alloc(); if (!pFrame) { LOGI("Could not allocate video frame!"); } pFrame->format = pCodecCtx->pix_fmt; pFrame->width = pCodecCtx->width; pFrame->height = pCodecCtx->height; ret = av_image_alloc(pFrame->data, pFrame->linesize, pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, 16); if (ret < 0) { LOGI("Could not allocate raw picture buffer!"); } y_size = pCodecCtx->width * pCodecCtx->height; //Encode av_init_packet(&pkt); pkt.data = NULL; // packet data will be allocated by the encoder pkt.size = 0; //Y、U、V这样去是正确的; //Y pFrame->data[0] = yuv420p; //U pFrame->data[1] = yuv420p + y_size; //V pFrame->data[2] = yuv420p + y_size * 5 / 4; //pts和dts; pFrame->pts = index; //int64_t类型的打印方式有所不同; LOGI("pts %" PRId64 "\n", pFrame->pts); /* encode the image */ ret = avcodec_encode_video2(pCodecCtx, &pkt, pFrame, &got_output); if (ret < 0) { LOGI("Error encoding frame!"); } //没有用到; if (got_output) { LOGI("Succeed to encode frame size:%5d!", pkt.size); h264 = (*env)->NewByteArray(env, pkt.size); (*env)->SetByteArrayRegion(env, h264, 0, pkt.size, pkt.data); av_free_packet(&pkt); } //Flush Encoder for (got_output = 1; got_output; i++) { ret = avcodec_encode_video2(pCodecCtx, &pkt, NULL, &got_output); if (ret < 0) { LOGI("Error encoding frame!"); } if (got_output) { LOGI("Flush Encoder: Succeed to encode 1 frame! size:%5d", pkt.size); h264 = (*env)->NewByteArray(env, pkt.size); (*env)->SetByteArrayRegion(env, h264, 0, pkt.size, pkt.data); av_free_packet(&pkt); } } avcodec_close(pCodecCtx); av_free(pCodecCtx); av_frame_free(&pFrame); (*env)->ReleaseByteArrayElements(env, yuv420p_, yuv420p, 0); return h264;}
文件
JNIEXPORT jbyteArray JNICALLJava_com_uestc_smileteeth_view_recordvideo_RecordVideoLib_encodeVideoFrame(JNIEnv *env, jclass type, jstring path1_, jstring path2_, jint frameNum, jint width, jint height, jintArray pts_) { const char *path1 = (*env)->GetStringUTFChars(env, path1_, 0); const char *path2 = (*env)->GetStringUTFChars(env, path2_, 0); jint *pts = (*env)->GetIntArrayElements(env, pts_, NULL); AVFormatContext *pFormatCtx; AVOutputFormat *fmt; AVStream *video_st; AVCodecContext *pCodecCtx; AVCodec *pCodec; AVPacket pkt; uint8_t *picture_buf; AVFrame *pFrame; int picture_size; int y_size; int framecnt = 0; //FILE *in_file = fopen("src01_480x272.yuv", "rb"); //Input raw YUV data FILE *in_file = fopen(path1, "rb"); //Input raw YUV data int in_w = width, in_h = height; //Input data's width and height //总帧数; int framenum = frameNum; //Frames to encode //输出路径; const char *out_file = path2; av_register_all(); //Method1. pFormatCtx = avformat_alloc_context(); //Guess Format fmt = av_guess_format(NULL, out_file, NULL); pFormatCtx->oformat = fmt; //Method 2. //avformat_alloc_output_context2(&pFormatCtx, NULL, NULL, out_file); //fmt = pFormatCtx->oformat; //Open output URL if (avio_open(&pFormatCtx->pb, out_file, AVIO_FLAG_READ_WRITE) < 0) { LOGI("Failed to open output file! "); } video_st = avformat_new_stream(pFormatCtx, 0); //video_st->time_base.num = 1; //video_st->time_base.den = 25; if (video_st == NULL) { } //Param that must set pCodecCtx = video_st->codec; //pCodecCtx->codec_id =AV_CODEC_ID_HEVC; pCodecCtx->codec_id = fmt->video_codec; pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO; pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P; pCodecCtx->width = in_w; pCodecCtx->height = in_h; pCodecCtx->bit_rate = 30000000; pCodecCtx->gop_size = 5; pCodecCtx->time_base.num = 1; pCodecCtx->time_base.den = 25; //H264 pCodecCtx->me_range = 32; //pCodecCtx->max_qdiff = 4; //pCodecCtx->qcompress = 0.6; pCodecCtx->qmin = 10; pCodecCtx->qmax = 40; //Optional Param pCodecCtx->max_b_frames = 0; // Set Option AVDictionary *param = 0; //H.264 if (pCodecCtx->codec_id == AV_CODEC_ID_H264) { av_dict_set(¶m, "preset", "slow", 0); av_dict_set(¶m, "tune", "zerolatency", 0); //av_dict_set(¶m, "profile", "main", 0); } //H.265 if (pCodecCtx->codec_id == AV_CODEC_ID_H265) { av_dict_set(¶m, "preset", "ultrafast", 0); av_dict_set(¶m, "tune", "zero-latency", 0); } //Show some Information av_dump_format(pFormatCtx, 0, out_file, 1); pCodec = avcodec_find_encoder(pCodecCtx->codec_id); if (!pCodec) { LOGI("Can not find encoder! "); } if (avcodec_open2(pCodecCtx, pCodec, ¶m) < 0) { LOGI("Failed to open encoder! "); } pFrame = av_frame_alloc(); picture_size = avpicture_get_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height); picture_buf = (uint8_t *) av_malloc(picture_size); avpicture_fill((AVPicture *) pFrame, picture_buf, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height); //Write File Header avformat_write_header(pFormatCtx, NULL); av_new_packet(&pkt, picture_size); y_size = pCodecCtx->width * pCodecCtx->height; for (int i = 0; i < framenum; i++) { LOGI("完整视频正在编码第%d帧", i + 1); //Read raw YUV data if (fread(picture_buf, 1, y_size * 3 / 2, in_file) <= 0) { LOGI("Failed to read raw data! "); } else if (feof(in_file)) { break; } pFrame->data[0] = picture_buf; // Y pFrame->data[1] = picture_buf + y_size; // U pFrame->data[2] = picture_buf + y_size * 5 / 4; // V //PTS pFrame->pts = pts[i]; LOGI("pts %" PRId64 "\n", pFrame->pts); int got_picture = 0; //Encode int ret = avcodec_encode_video2(pCodecCtx, &pkt, pFrame, &got_picture); if (ret < 0) { LOGI("Failed to encode! "); } if (got_picture == 1) { framecnt++; LOGI("Succeed to encode frame: %5d\tsize:%5d", framecnt, pkt.size); pkt.stream_index = video_st->index; ret = av_write_frame(pFormatCtx, &pkt); av_free_packet(&pkt); } } //Flush Encoder int ret = flush_encoder(pFormatCtx, 0); if (ret < 0) { LOGI("Flushing encoder failed!"); } //Write file trailer av_write_trailer(pFormatCtx); //Clean if (video_st) { avcodec_close(video_st->codec); av_free(pFrame); av_free(picture_buf); } avio_close(pFormatCtx->pb); avformat_free_context(pFormatCtx); fclose(in_file); (*env)->ReleaseStringUTFChars(env, path1_, path1); (*env)->ReleaseStringUTFChars(env, path2_, path2); (*env)->ReleaseIntArrayElements(env, pts_, pts, 0);}int flush_encoder(AVFormatContext *fmt_ctx, unsigned int stream_index) { int ret; int got_frame; AVPacket enc_pkt; if (!(fmt_ctx->streams[stream_index]->codec->codec->capabilities & CODEC_CAP_DELAY)) return 0; while (1) { enc_pkt.data = NULL; enc_pkt.size = 0; av_init_packet(&enc_pkt); ret = avcodec_encode_video2(fmt_ctx->streams[stream_index]->codec, &enc_pkt, NULL, &got_frame); av_frame_free(NULL); if (ret < 0) break; if (!got_frame) { ret = 0; break; } LOGI("Flush Encoder: Succeed to encode 1 frame!\tsize:%5d", enc_pkt.size); /* mux encoded frame */ ret = av_write_frame(fmt_ctx, &enc_pkt); if (ret < 0) break; } return ret;}
推荐
雷神的FFMPEG专栏
更多相关文章
- android 根据SD卡中图片路径读取并显示SD中的图片――源代码
- android读取SDCard任意路径下的文件
- Android之adt 23找不到NDK路径设置解决方案
- Android 模拟器中AVD路径的修改
- Android各版本 内外卡真实路径
- AVD(android virtual device)路径设置
- APK安装路径移动至外部存储设备
- android实现图片按任意路径截取
- Android下载文件保存到路径