Android使用FFMPEG将H264解码为yuv420p
16lz
2021-01-23
JNIEXPORT jbyteArray JNICALLJava_com_uestc_smileteeth_view_recordvideo_RecordVideoLib_decodeVideo(JNIEnv *env, jclass type, jstring input_, jstring output_) { const char *input = (*env)->GetStringUTFChars(env, input_, 0); const char *output = (*env)->GetStringUTFChars(env, output_, 0); AVFormatContext *pFormatCtx; int i, videoindex; AVCodecContext *pCodecCtx; AVCodec *pCodec; AVFrame *pFrame, *pFrameYUV; uint8_t *out_buffer; AVPacket *packet; int y_size; int ret, got_picture; struct SwsContext *img_convert_ctx; FILE *fp_yuv; int frame_cnt; clock_t time_start, time_finish; double time_duration = 0.0; char info[1000] = {0}; av_register_all(); avformat_network_init(); pFormatCtx = avformat_alloc_context(); if (avformat_open_input(&pFormatCtx, input, NULL, NULL) != 0) { LOGI("Couldn't open input stream.\n"); return -1; } if (avformat_find_stream_info(pFormatCtx, NULL) < 0) { LOGI("Couldn't find stream information.\n"); return -1; } videoindex = -1; for (i = 0; i < pFormatCtx->nb_streams; i++) if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { videoindex = i; break; } if (videoindex == -1) { LOGI("Couldn't find a video stream.\n"); return -1; } pCodecCtx = pFormatCtx->streams[videoindex]->codec; pCodec = avcodec_find_decoder(pCodecCtx->codec_id); if (pCodec == NULL) { LOGI("Couldn't find Codec.\n"); return -1; } if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) { LOGI("Couldn't open codec.\n"); return -1; } pFrame = av_frame_alloc(); pFrameYUV = av_frame_alloc(); out_buffer = (unsigned char *) av_malloc( av_image_get_buffer_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1)); av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize, out_buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1); packet = (AVPacket *) av_malloc(sizeof(AVPacket)); img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL); sprintf(info, "[Input ]%s\n", input); sprintf(info, "%s[Output ]%s\n", info, output); sprintf(info, "%s[Format ]%s\n", info, pFormatCtx->iformat->name); sprintf(info, "%s[Codec ]%s\n", info, pCodecCtx->codec->name); sprintf(info, "%s[Resolution]%dx%d\n", info, pCodecCtx->width, pCodecCtx->height); fp_yuv = fopen(output, "wb+"); if (fp_yuv == NULL) { printf("Cannot open output file.\n"); return -1; } frame_cnt = 0; time_start = clock(); while (av_read_frame(pFormatCtx, packet) >= 0) { if (packet->stream_index == videoindex) { ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet); if (ret < 0) { LOGI("Decode Error.\n"); return -1; } if (got_picture) { sws_scale(img_convert_ctx, (const uint8_t *const *) pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize); y_size = pCodecCtx->width * pCodecCtx->height; fwrite(pFrameYUV->data[0], 1, y_size, fp_yuv); //Y fwrite(pFrameYUV->data[1], 1, y_size / 4, fp_yuv); //U fwrite(pFrameYUV->data[2], 1, y_size / 4, fp_yuv); //V //Output info char pictype_str[10] = {0}; switch (pFrame->pict_type) { case AV_PICTURE_TYPE_I: sprintf(pictype_str, "I"); break; case AV_PICTURE_TYPE_P: sprintf(pictype_str, "P"); break; case AV_PICTURE_TYPE_B: sprintf(pictype_str, "B"); break; default: sprintf(pictype_str, "Other"); break; } LOGI("Frame Index: %5d. Type:%s", frame_cnt, pictype_str); frame_cnt++; } } av_free_packet(packet); } //flush decoder //FIX: Flush Frames remained in Codec while (1) { ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet); if (ret < 0) break; if (!got_picture) break; sws_scale(img_convert_ctx, (const uint8_t *const *) pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize); int y_size = pCodecCtx->width * pCodecCtx->height; fwrite(pFrameYUV->data[0], 1, y_size, fp_yuv); //Y fwrite(pFrameYUV->data[1], 1, y_size / 4, fp_yuv); //U fwrite(pFrameYUV->data[2], 1, y_size / 4, fp_yuv); //V //Output info char pictype_str[10] = {0}; switch (pFrame->pict_type) { case AV_PICTURE_TYPE_I: sprintf(pictype_str, "I"); break; case AV_PICTURE_TYPE_P: sprintf(pictype_str, "P"); break; case AV_PICTURE_TYPE_B: sprintf(pictype_str, "B"); break; default: sprintf(pictype_str, "Other"); break; } LOGI("Frame Index: %5d. Type:%s", frame_cnt, pictype_str); frame_cnt++; } time_finish = clock(); time_duration = (double) (time_finish - time_start); sprintf(info, "%s[Time ]%fms\n", info, time_duration); sprintf(info, "%s[Count ]%d\n", info, frame_cnt); sws_freeContext(img_convert_ctx); fclose(fp_yuv); av_frame_free(&pFrameYUV); av_frame_free(&pFrame); avcodec_close(pCodecCtx); avformat_close_input(&pFormatCtx); (*env)->ReleaseStringUTFChars(env, input_, input); (*env)->ReleaseStringUTFChars(env, output_, output); return 0;}
推荐
雷神的FFMPEG专栏
更多相关文章
- 一些优秀的 Android 开发专栏推荐
- Android 专栏整理
- android contentprovider学习(遇到最满意的介绍)---阿冬专栏
- Android Gradle Plugin指南(一)——简介 - 琴弦第七的专栏 - 博客
- Android中文资源站专栏:五个好用的日常软件
- 专家专栏:Android层次化安全架构及核心组件概览
- 没有这样的专栏:blog_article.date
- 教你如何秒杀12306,JAVA程序抢票成功!----阿冬专栏