if (mIsPushing) {
mNativePush.fireVideo(bytes);
}
}
音频采集 音频采集基于 AudioRecord 实现,在一个子线程采集音频 PCM 数据,并将数据不断传入 Native 层进行编码。
private class AudioRecordRunnable implements Runnable { @Override public void run() { mAudioRecord.startRecording(); while (mIsPushing) { //通过AudioRecord不断读取音频数据 byte[] buffer = new byte[mMinBufferSize]; int length = mAudioRecord.read(buffer, 0, buffer.length); if (length > 0) { //传递给 Native 代码,进行音频编码 mNativePush.fireAudio(buffer, length); } } } } **编码和推流** 音视频数据编码和推流在 Native 层实现,首先添加 faac , x264 , librtmp 第三方库到 AS 工程,然后初始化相关设置,基于生产者与消费者模式,将编码后的音视频数据,在生产者线程中打包 RTMPPacket 放入双向链表,在消费者线程中从链表中取 RTMPPacket ,通过 RTMP\_SendPacket 方法发送给服务器。 x264 初始化: JNIEXPORT void JNICALL Java_com_haohao_live_jni_NativePush_setVideoOptions(JNIEnv *env, jobject instance, jint width, jint height, jint bitRate, jint fps) { x264_param_t param; //x264_param_default_preset 设置 x264_param_default_preset(¶m, "ultrafast", "zerolatency"); //编码输入的像素格式YUV420P param.i_csp = X264_CSP_I420; param.i_width = width; param.i_height = height; y_len = width * height; u_len = y_len / 4; v_len = u_len; //参数i_rc_method表示码率控制,CQP(恒定质量),CRF(恒定码率),ABR(平均码率) //恒定码率,会尽量控制在固定码率 param.rc.i_rc_method = X264_RC_CRF; param.rc.i_bitrate = bitRate / 1000; //* 码率(比特率,单位Kbps) param.rc.i_vbv_max_bitrate = bitRate / 1000 * 1.2; //瞬时最大码率 //码率控制不通过timebase和timestamp,而是fps param.b_vfr_input = 0; param.i_fps_num = fps; //* 帧率分子 param.i_fps_den = 1; //* 帧率分母 param.i_timebase_den = param.i_fps_num; param.i_timebase_num = param.i_fps_den; param.i_threads = 1;//并行编码线程数量,0默认为多线程 //是否把SPS和PPS放入每一个关键帧 //SPS Sequence Parameter Set 序列参数集,PPS Picture Parameter Set 图像参数集 //为了提高图像的纠错能力 param.b_repeat_headers = 1; //设置Level级别 param.i_level_idc = 51; //设置Profile档次 //baseline级别,没有B帧,只有 I 帧和 P 帧 x264_param_apply_profile(¶m, "baseline"); //x264_picture_t(输入图像)初始化 x264_picture_alloc(&pic_in, p