#include <unistd.h>
#include "hjcommon.hpp"
extern "C" {
#include "libavutil/imgutils.h"
}
JNIEXPORT void JNICALL Java_hankin_hjmedia_mpeg_some_MP42YUVActivity_decode(JNIEnv *env, jobject instance, jstring src_, jstring dst_)
{
char src[128];
hjcpyJstr2char(env, src_, src);
char dst[128];
hjcpyJstr2char(env, dst_, dst);
AVFormatContext * avFormatContext = 0;
int ret = avformat_open_input(&avFormatContext, src, 0, 0);
if (ret!=0)
{
LOGE("avformat_open_input error.");
return;
}
ret = avformat_find_stream_info(avFormatContext, 0);
if (ret!=0)
{
LOGE("avformat_find_stream_info error.");
return;
}
int videoStream = av_find_best_stream(avFormatContext, AVMEDIA_TYPE_VIDEO, -1, -1, 0, 0);
AVStream * avs = avFormatContext->streams[videoStream];
int width = avs->codecpar->width;
int height = avs->codecpar->height;
// duration=10024000, fps=25.00, width=1920, height=1080
LOGD("duration=%lld, fps=%.2f, width=%d, height=%d", avFormatContext->duration, hj_r2d(avs->avg_frame_rate), width, height);
AVCodecContext * videoCodec = avcodec_alloc_context3(0);
int gvRet = hjgetAVDecoder6_1(videoCodec, avs->codecpar, true, false); // nexus上,硬解码的效果没有软解码好
if (gvRet!=0) return;
int frameCount = 0;
AVPacket * packet = av_packet_alloc();
AVFrame * frame = av_frame_alloc();
bool is = true;
FILE * fp = fopen(dst, "wb+");
AVFrame * tmpFrame = 0;
int format = -1;
AVFrame * convertFrame = 0;
SwsContext * swsContext = 0;
while (true)
{
int re = av_read_frame(avFormatContext, packet);
if (re!=0) break;
if (packet->stream_index==videoStream)
{
int num = 0;
while (true)
{
num++;
ret = avcodec_send_packet(videoCodec, packet); // 硬解码的时候,avcodec_send_packet可能会失败,这里循环尝试发送5次
if (ret!=0)
{
LOGW("avcodec_send_packet error");
usleep(1000*2);
}
if (ret==0 || num>=5) break;
}
while (true)
{
ret = avcodec_receive_frame(videoCodec, frame);
if (ret!=0) break;
frameCount++;
tmpFrame = frame;
format = frame->format; // mp4软解码的format为AV_PIX_FMT_YUV420P,硬解码看硬件
LOGD("pts=%lld, size=%d, format=%d, 帧数=%d", frame->pts, frame->pkt_size, format, frameCount);
if (is && format!=AV_PIX_FMT_YUV420P) // 视频格式不为 AV_PIX_FMT_YUV420P ,需要转换为yuv,然后保存到sdcard
{
is = false;
convertFrame = av_frame_alloc();
/*
int av_image_get_buffer_size( // 返回使用给定参数存储图像所需的数据量的大小(以字节为单位)。
enum AVPixelFormat pix_fmt, // the pixel format of the image
int width, // 宽度
int height, // 高度
int align // 一个像素占几个字节?
);
*/
int imgSize = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, width, height, 1);
uint8_t * buf = (uint8_t*) av_malloc(imgSize);
/*
int av_image_fill_arrays( // 为AVFrame的数据分配内存
uint8_t *dst_data[4], // framd的data
int dst_linesize[4], // frame的linesize
const uint8_t *src, // 申请好了的内存
enum AVPixelFormat pix_fmt, // 视频格式
int width, // 宽
int height, // 高
int align // 一个像素占几个字节?
);
*/
int ss = av_image_fill_arrays(convertFrame->data, convertFrame->linesize, buf, AV_PIX_FMT_YUV420P, width, height, 1);
// av_image_get_buffer_size=3110400, av_image_fill_arrays=3110400, format=23
LOGI("av_image_get_buffer_size=%d, av_image_fill_arrays=%d, format=%d", imgSize, ss, format);
}
if (format!=AV_PIX_FMT_YUV420P) // 视频格式不为 AV_PIX_FMT_YUV420P ,需要转换为yuv,然后保存到sdcard
{
// 视频格式转换
swsContext = sws_getCachedContext(swsContext, width, height, (AVPixelFormat) frame->format,
width, height, AV_PIX_FMT_YUV420P,
SWS_FAST_BILINEAR, NULL, NULL, NULL);
sws_scale(swsContext, (const uint8_t**)frame->data, frame->linesize, 0, height, convertFrame->data, convertFrame->linesize);
tmpFrame = convertFrame;
}
// 保存到sdcard
int y_size = width * height;
fwrite(tmpFrame->data[0], 1, y_size, fp); // 1920*1080 10秒钟的视频(共241帧)存为yuv,大小为 1920*1080*1.5*241 = 700多M 。。
fwrite(tmpFrame->data[1], 1, y_size / 4, fp);
fwrite(tmpFrame->data[2], 1, y_size / 4, fp);
}
}
av_packet_unref(packet);
}
end:
av_packet_free(&packet);
av_frame_free(&frame);
avcodec_close(videoCodec);
avcodec_free_context(&videoCodec);
avformat_close_input(&avFormatContext);
fflush(fp);
fclose(fp);
// 调用java函数
jclass clz = env->GetObjectClass(instance);
jmethodID mid = env->GetMethodID(clz, "setStatus", "()V");
env->CallVoidMethod(instance, mid);
}
(八) 解码mp4,导出为YUV420P
最新推荐文章于 2024-03-25 16:52:13 发布