当前位置:   article > 正文

Android音视频开发 -> ffmpeg+h264+avfilter+camera推流旋转角度_android freetype avfilter_graph_create_filter -22

android freetype avfilter_graph_create_filter -22

音视频开发系列

Android音视频开发 -> 搭建开发环境

Android音视频开发 -> ffmpeg+h264+aac编译以及测试调用

Android音视频开发 -> 本地音频采集

Android音视频开发 -> 本地camera视频采集

Android音视频开发 -> ffmpeg+h264+avfilter+camera推流旋转角度

Android音视频开发 -> fdk-aac编码pcm为eld-aac

Android音视频开发 -> fdk-aac解码eld-aac为pcm

大体思路

  • ffmpeg推流相关组件初始化
  • avFilter初始化
  • 264编码器初始化
  • 接收摄像头的实时数据开始推流,这个数据格式需要转换摄像头是NV21的需要转换成YUV420P

公共变量

//解封装全局上下文
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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

ffmpeg推流以及avFilter初始化

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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101

264编码器初始化

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(&param, "preset", "superfast", 0);
        av_dict_set(&param, "tune", "zerolatency", 0);
    }
    //创建h264视频编码器
    if (avcodec_open2(pCodecCtx, pCodec, &param) < 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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82

开始推流

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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76

释放资源

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;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/174839
推荐阅读
相关标签
  

闽ICP备14008679号