赞
踩
Android音视频开发 -> ffmpeg+h264+aac编译以及测试调用
Android音视频开发 -> ffmpeg+h264+avfilter+camera推流旋转角度
Android音视频开发 -> fdk-aac编码pcm为eld-aac
Android音视频开发 -> fdk-aac解码eld-aac为pcm
//解封装全局上下文 AVFormatContext *avFormatContext; //流通道,存储音视频流 AVStream *video_st; //解码信息上下文 AVCodecContext *pCodecCtx; //解码器返回指针对象 AVCodec *pCodec; //解码前数据结构体 AVPacket enc_pkt; //储存原始数据流 AVFrame *pFrameYUV; int count = 0; //初始化分辨率 int width; int height; //初始化YUV分辨率 int yuv_width; int yuv_height; //计算Y长度 int y_length; //计算UV长度 int uv_length; //帧率(表示一秒上传多少张图片人眼一般感觉流畅是24帧) int fps = 24; //水印标识 int flags = 0; //AVFilter相关 const char *filters_descr; AVFilterContext *buffersink_ctx = NULL; AVFilterContext *buffersrc_ctx = NULL; AVFilterGraph *filter_graph; //推流地址 const char *out_path; //是否第一次初始化编码器 int initFlag = 0;
int PushFLow::pushInit(JNIEnv *env, jstring pushPath, int mWight, int mHight, int flag) { //释放资源 close(); initFlag = 0; //初始化分辨率 width = mWight; height = mHight; //计算yuv数据的长度 yuv_width = width; yuv_height = height; y_length = width * height; uv_length = width * height / 4; //获取用户输入flag flags = flag; //获取推流地址 out_path = env->GetStringUTFChars(pushPath, 0); //注册组件 av_register_all(); //初始化网络库 avformat_network_init(); //创建输出上下文 avformat_alloc_output_context2(&avFormatContext, NULL, "flv", out_path); //初始化AVFrame pFrameYUV = av_frame_alloc(); //AVFilter相关 if (flags != 0) { if (flags == 1) filters_descr = "transpose=1"; if (flags == 2) filters_descr = "movie=/sdcard/test.png[wm];[in][wm]overlay=1:5[out]"; if (flags == 3) filters_descr = "drawtext=fontsize=56:fontcolor=green:text='Hello World'"; if (avFilterInit(filters_descr) < 0) { LOGE("初始化AVFilter失败"); close(); return -1; } } return 0; } int PushFLow::avFilterInit(const char *filters_descr) { char args[512]; //分配AVFilterGraph filter_graph = avfilter_graph_alloc(); //设置参数(未知) enum AVPixelFormat pix_fmts[] = {AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE}; AVBufferSinkParams *buffersink_params; AVCodecContext *avfilterContext = avcodec_alloc_context3(nullptr); snprintf(args, sizeof(args), "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", width, height, AV_PIX_FMT_YUV420P, 1, fps, avfilterContext->sample_aspect_ratio.num, avfilterContext->sample_aspect_ratio.den); avcodec_free_context(&avfilterContext); buffersink_params = av_buffersink_params_alloc(); buffersink_params->pixel_fmts = pix_fmts; //创建过滤器源(就是原始AVFrame数据流) const AVFilter *buffersrc = avfilter_get_by_name("buffer"); if (avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in", args, NULL, filter_graph) < 0) { LOGE("创建过滤器源失败"); close(); return -1; } //创建接收过滤器(接收添加水印后的AVFrame数据流) const AVFilter *buffersink = avfilter_get_by_name("buffersink");//新版的ffmpeg库必须为buffersink if (avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out", NULL, buffersink_params, filter_graph) < 0) { LOGE("创建接收过滤器失败"); close(); return -1; } //释放buffersink_params av_free(buffersink_params); //生成源和接收过滤器的输入输出 AVFilterInOut *outputs = avfilter_inout_alloc(); AVFilterInOut *inputs = avfilter_inout_alloc(); outputs->name = av_strdup("in"); outputs->filter_ctx = buffersrc_ctx; outputs->pad_idx = 0; outputs->next = NULL; inputs->name = av_strdup("out"); inputs->filter_ctx = buffersink_ctx; inputs->pad_idx = 0; inputs->next = NULL; //解析filters_descr过滤器并向filter_graph添加过滤器 if (avfilter_graph_parse_ptr(filter_graph, filters_descr, &inputs, &outputs, NULL) < 0) { LOGE("解析添加过滤器失败"); close(); return -1; } //检查过滤器的完整性 if (avfilter_graph_config(filter_graph, NULL) < 0) { LOGE("过滤器缺失"); close(); return -1; } return 0; }
int PushFLow::encoderInit(int encoderWight, int encoderHeight) { if (pCodecCtx != nullptr) { avcodec_free_context(&pCodecCtx); } //找到x264编码器 pCodec = avcodec_find_encoder(AV_CODEC_ID_H264); if (!pCodec) { LOGE("查找h264编码器失败"); return -1; } //初始化编解码上下文 pCodecCtx = avcodec_alloc_context3(pCodec); //编码器的ID号,这里为264编码器,可以根据video_st里的codecID 参数赋值 pCodecCtx->codec_id = pCodec->id; //像素的格式,也就是说采用什么样的色彩空间来表明一个像素点 pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P; //编码器编码的数据类型 pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO; //编码目标的视频帧大小,以像素为单位 pCodecCtx->width = encoderWight; pCodecCtx->height = encoderHeight; pCodecCtx->framerate = (AVRational) {fps, 1}; //帧率的基本单位,我们用分数来表示, pCodecCtx->time_base = (AVRational) {1, fps}; //目标的码率(表示图片是否清晰,一般100kb但是要转换1kb=1024b=8bit) pCodecCtx->bit_rate = 100 * 1024 * 8; //固定允许的码率误差,数值越大,视频越小 pCodecCtx->gop_size = 50; //未知 if (avFormatContext->oformat->flags & AVFMT_GLOBALHEADER) pCodecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; //x264参数 pCodecCtx->qcompress = 0.6; //最大和最小量化系数 pCodecCtx->qmin = 10; pCodecCtx->qmax = 51; pCodecCtx->max_b_frames = 0; //一些配置参数比如网络延迟的时候用 AVDictionary *param = 0; if (pCodecCtx->codec_id == AV_CODEC_ID_H264) { //避免x264延时 av_dict_set(¶m, "preset", "superfast", 0); av_dict_set(¶m, "tune", "zerolatency", 0); } //创建h264视频编码器 if (avcodec_open2(pCodecCtx, pCodec, ¶m) < 0) { LOGE("创建h264编码器失败"); close(); return -1; } //创建流通道 video_st = avformat_new_stream(avFormatContext, pCodec); if (video_st == NULL) { LOGE("创建流通道失败"); close(); return -1; } //流通道参数 video_st->time_base.num = 1; video_st->time_base.den = fps; video_st->codecpar->codec_tag = 0; //设置编码器参数 if (avcodec_parameters_from_context(video_st->codecpar, pCodecCtx) < 0) { LOGE("设置编码器参数失败"); close(); return -1; } //打开输出IO if (avio_open(&avFormatContext->pb, out_path, AVIO_FLAG_READ_WRITE) < 0) { LOGE("打开输出IO失败"); close(); return -1; } //写入头部信息 if (avformat_write_header(avFormatContext, NULL) != 0) { LOGE("写入头部信息失败"); close(); return -1; } return 0; }
int PushFLow::pushStart(JNIEnv *env, jbyte *byte) { //给pFrameYUV申请内存地址 int picture_size = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, width, height, 1); uint8_t *buffers = (uint8_t *) av_malloc(picture_size); //将buffers的地址赋给AVFrame中的图像数据,根据像素格式判断有几个数据指针 av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize, buffers, AV_PIX_FMT_YUV420P, width, height, 1); //数据转换NV21转换YUV420P,因为安卓的摄像头数据是NV21的但是ffmpeg支持的格式是YUV420P的 memcpy(pFrameYUV->data[0], byte, y_length); //Y pFrameYUV->pts = count; for (int i = 0; i < uv_length; i++) { //将v数据存到第三个平面 *(pFrameYUV->data[2] + i) = *(byte + y_length + i * 2); //将U数据存到第二个平面 *(pFrameYUV->data[1] + i) = *(byte + y_length + i * 2 + 1); } pFrameYUV->format = AV_PIX_FMT_YUV420P; pFrameYUV->width = yuv_width; pFrameYUV->height = yuv_height; if (flags != 0) { //给AVFrame添加滤镜 if (av_buffersrc_add_frame(buffersrc_ctx, pFrameYUV) < 0) { LOGE("添加滤镜失败"); close(); return -1; } //获取添加完滤镜后的AVFrame if (av_buffersink_get_frame(buffersink_ctx, pFrameYUV) < 0) { LOGE("获取添加滤镜后数据失败"); close(); return -1; } } //初始化编码器 if (initFlag == 0) {//编码器只初始化一次 if (encoderInit(pFrameYUV->width, pFrameYUV->height) < 0) { LOGE("初始化编码器失败"); close(); return -1; } initFlag = 1; } //开始编码 if (avcodec_send_frame(pCodecCtx, pFrameYUV) < 0) { LOGE("编码失败"); close(); return -1; } //初始化AVPacket av_init_packet(&enc_pkt); //编码后数据填充到enc_pkt if (avcodec_receive_packet(pCodecCtx, &enc_pkt) < 0) { LOGE("数据填充失败"); close(); return -1; } //计算写入需要参数 enc_pkt.stream_index = video_st->index; enc_pkt.pts = count * (video_st->time_base.den) / ((video_st->time_base.num) * fps); enc_pkt.dts = enc_pkt.pts; enc_pkt.duration = (video_st->time_base.den) / ((video_st->time_base.num) * fps); enc_pkt.pos = -1; //写入数据,开始推流 if (av_interleaved_write_frame(avFormatContext, &enc_pkt) != 0) { LOGE("推流失败"); close(); return -1; } //释放内存 av_frame_unref(pFrameYUV); av_packet_unref(&enc_pkt); av_free(buffers); count++; return 0; }
void PushFLow::close() { //释放解封装上下文 if (avFormatContext != nullptr) { avio_close(avFormatContext->pb); avformat_free_context(avFormatContext); avFormatContext = nullptr; } if (video_st) { avcodec_close(video_st->codec); } //释放解码器上下文 if (pCodecCtx != nullptr) { avcodec_free_context(&pCodecCtx); pCodecCtx = nullptr; } //释放pFrameYUV if (pFrameYUV != nullptr) { av_frame_free(&pFrameYUV); pFrameYUV = nullptr; } //释放enc_pkt if (&enc_pkt != nullptr) { av_freep(&enc_pkt); } //AVFilter相关 if (buffersink_ctx != nullptr) { avfilter_free(buffersink_ctx); buffersink_ctx = nullptr; } if (buffersrc_ctx != nullptr) { avfilter_free(buffersrc_ctx); buffersrc_ctx = nullptr; } if (filter_graph != nullptr) { avfilter_graph_free(&filter_graph); filter_graph = nullptr; } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。