android librtmp 推送h264流 aac流 基本过程总结四 推流x264
来源:互联网 发布:申请域名后怎么使用 编辑:程序博客网 时间:2024/05/21 21:40
android librtmp 推送h264流 aac流 基本过程总结三 推流x264
1. x264初始化配置注意:这里边我踩了一些坑,rtmp 推流过程中去掉nal中pps,sps,只允许一帧中只有一个nal片,之前测试初始化x264参数没注意到这个问题导致自己推流再nginx服务器中没有正确的切成ts流,播放异常。另外需要注意推流的时候一定要跟faac流一个时间线,要不然会出现音视频不同步,或者视频中没有音频流的现象都是有可能发生的typedef struct x264_args{x264_t *encoder; //锟斤拷锟斤拷锟斤拷 int64_t i_pts; //锟斤拷锟斤拷帧锟斤拷锟斤拷 int outf;int width;int height;int init_flag;AVFrame * png_frame;#if H264_TO_MP4_SUPPORTMp4Args mp4_args;#endifx264_picture_t pic_in;x264_picture_t pic_out;//x264锟斤拷x264_picture_t 锟斤拷示帧锟斤拷锟斤拷锟斤拷前锟斤拷锟斤拷锟斤拷}X264Args;定义x264普通的结构体
int X264encode_Init_Args_ForRtmp(X264Args *args, char *name,int width, int height){if (args == NULL ){return -1;}Thread_Lock_By_Kind(THREAD_LOCK_X264_ENCODE);FilterArgs * png_args = NULL ;int ret = 0; int FPS = GOAL_FPS; x264_param_t param;args->i_pts = 0;args->width = width;args->height = height;dmprint_string("encode start");x264_param_default_preset(¶m, "superfast", "zerolatency");//0延时 对实时性有保证 param.i_level_idc=30;//算法的复杂度 param.i_threads = X264_SYNC_LOOKAHEAD_AUTO;//linux可以设置0,主要为了防止开启多线程导致输出NAL片段多,这样保证一桢只有一个NAL // 否则有几个线程,在编码成几个NALU。缺省为true。 param.b_sliced_threads = false; param.rc.b_mb_tree = 0;//这个不为0,将导致编码延时帧...在实时编码时,必须为0 // 该参数设置是让每个I帧都附带sps/pps。// param.b_repeat_headers = 1; // 重复SPS/PPS 放到关键帧前面// param.b_repeat_headers = 0; param.i_width = width; param.i_height = height; param.i_fps_num = FPS; param.i_fps_den = 1; param.i_csp = X264_CSP_I420;// param.i_keyint_min = FPS * 1; param.i_keyint_max = FPS * 2; param.rc.i_qp_min = 18; // param.rc.i_qp_max =31; //xiaoyu 70 param.analyse.i_me_range = 16; param.rc.i_qp_step = 2;// param.rc.i_rc_method = X264_RC_CQP; // param.rc.i_qp_constant = 23; x264_param_apply_profile(¶m, "baseline");//鏍稿骞朵慨鏀归儴鍒嗛潪娉曞弬鏁? args->encoder = x264_encoder_open(¶m);//鎵撳紑缂栫爜鍣? x264_picture_alloc(&args->pic_in, X264_CSP_I420, width, height);//鐢宠涓€甯у唴瀛? #if LINUX_VERSION || ANDROID_VERSION free(args->pic_in.img.plane[0] );#else free( *( ( ( void **) args->pic_in.img.plane[0] ) - 1 ) );#endif //鐢宠珛铏曠悊鐨勭珐瀛樺唴瀛?if (is_watermark_flag){png_args = get_filter_args(width,height,AV_PIX_FMT_YUV420P);Filter_Alloc_Frame(&args->png_frame,png_args);Frame_Add_WaterMark(width,height,AV_PIX_FMT_YUV420P,2);free(png_args);}args->init_flag = 1;//end:if (ret < 0){/*close(args->outf);//鍏抽棴鏂囦欢*/x264_encoder_close(args->encoder);//鍏抽棴缂栫爜鍣?if (is_watermark_flag){is_watermark_flag = 0;Frame_Release_WaterMark(2);Filter_Free_Frame(&args->png_frame);args->png_frame = NULL;}//mp4_for_h264_release(&args->mp4_args);args->init_flag = 0;}Thread_unLock_By_Kind(THREAD_LOCK_X264_ENCODE); return ret;}2. 编码一帧frame//mode = 0 I420 1 NV21int X264encodeAddframe_Args_ForRtmp(X264Args *args, uint8_t* jb, int nw, int nh, int isFrontCamera, int orientation, int isInversion, char *out, int *nal_len, int *nal_count, int mode){if (args == NULL || args->init_flag != 1)return -1;Thread_Lock_By_Kind(THREAD_LOCK_X264_ENCODE);int ret = 0;int len = h264_width*h264_height*3 >> 1;uint8_t* buffer = (uint8_t*) jb;x264_nal_t *nals = NULL;int nnal = 0;x264_nal_t *nal = NULL;char *pbuf = NULL;if (jb == NULL){ret = -1;goto end;}pbuf = (char *)malloc(args->width * args->height * 3);if (pbuf == NULL)goto end;if (mode == 0){detailYuvPic(buffer, (uint8_t *)pbuf, nw, nh, args->width,args->height, orientation , isInversion, isFrontCamera);}else{detailYuvPic_forAndroid(buffer, (uint8_t *)pbuf, nw, nh,args->width,args->height, orientation , isInversion, isFrontCamera);}if (is_watermark_flag){ memcpy(args->png_frame->data[0],pbuf,len);Frame_Get_WaterMark(args->png_frame,args->png_frame, 2);buffer = args->png_frame->data[0]; }elsebuffer= (uint8_t *)pbuf;//yuv420:灏唝uvbuff 濉厖杩沺ic_in锛岄渶瑕佹墜鍔ㄦ寚瀹氳繖涓変釜鎸囬拡args->pic_in.img.plane[0] = buffer;args->pic_in.img.plane[1] = buffer+(args->height * args->width);args->pic_in.img.plane[2] = buffer+(args->height * args->width * 5 >> 2);args->pic_in.img.i_plane = 3;//鎵嬪姩鎸囧畾鍏跺榻愰暱搴?args->pic_in.img.i_stride[0] = args->width;args->pic_in.img.i_stride[1] = args->width >>1;args->pic_in.img.i_stride[2] = args->width >>1;//棰滆壊绌洪棿args->pic_in.img.i_csp = X264_CSP_I420;//pic_in.i_type = X264_TYPE_AUTO;//缂栫爜args->pic_in.i_pts = args->i_pts++;*nal_count = 0;ret = x264_encoder_encode(args->encoder, &nals, &nnal, &args->pic_in, &args->pic_out);//缂栫爜锛屽苟涓斿埗瀹歯alif (ret > 0){len = 0;for (nal = nals; nal < nals + nnal; nal++) {memcpy(out + len, nal->p_payload, nal->i_payload);len += nal->i_payload;*nal_len = nal->i_payload;*nal_count += 1;nal_len++;}dm_printf("count = %d", nnal);}else{len = 0;*nal_count = 0;}args->i_pts += 66;end:if (pbuf != NULL)free(pbuf);pbuf = NULL;Thread_unLock_By_Kind(THREAD_LOCK_X264_ENCODE);return ret;}3.释放编码资源
int X264encode_Finish_Args_ForRtmp(X264Args *args){if (args == NULL || args->init_flag != 1)return -1;Thread_Lock_By_Kind(THREAD_LOCK_X264_ENCODE);int num = 0;int ret = 0;dmprint_string("encode finish");num = x264_encoder_delayed_frames(args->encoder);dm_printf("num = %d\n",num);x264_encoder_close(args->encoder);//鍏抽棴缂栫爜鍣?if (is_watermark_flag){is_watermark_flag = 0;Frame_Release_WaterMark(2);}if (args->png_frame != NULL){Filter_Free_Frame(&args->png_frame);args->png_frame = NULL;}memset(args, 0, sizeof(X264Args));Thread_unLock_By_Kind(THREAD_LOCK_X264_ENCODE);return ret;}4. rtmp 发送 sps,pps 头
static int send_video_sps_pps(RTMP* m_pRtmp, unsigned char *sps, int sps_len, unsigned char *pps, int pps_len){RTMPPacket * packet;unsigned char * body;int i;int ret = 0;if (m_pRtmp == NULL)return -1;packet = (RTMPPacket *) malloc(RTMP_HEAD_SIZE + 1024);memset(packet, 0, RTMP_HEAD_SIZE);packet->m_body = (char *) packet + RTMP_HEAD_SIZE;body = (unsigned char *) packet->m_body;i = 0;body[i++] = 0x17;body[i++] = 0x00;body[i++] = 0x00;body[i++] = 0x00;body[i++] = 0x00;/*AVCDecoderConfigurationRecord*/body[i++] = 0x01;body[i++] = sps[1];body[i++] = sps[2];body[i++] = sps[3];body[i++] = 0xff;/*sps*/body[i++] = 0xe1;body[i++] = (sps_len >> 8) & 0xff;body[i++] = sps_len & 0xff;memcpy(&body[i], sps, sps_len);i += sps_len;/*pps*/body[i++] = 0x01;body[i++] = (pps_len >> 8) & 0xff;body[i++] = (pps_len) & 0xff;memcpy(&body[i], pps, pps_len);i += pps_len;packet->m_packetType = RTMP_PACKET_TYPE_VIDEO;packet->m_nBodySize = i;packet->m_nChannel = 0x04;packet->m_nTimeStamp = 0;packet->m_hasAbsTimestamp = 0;packet->m_headerType = RTMP_PACKET_SIZE_MEDIUM;packet->m_nInfoField2 = m_pRtmp->m_stream_id;if (RTMP_IsConnected(m_pRtmp)) {//调用发送接口int success = RTMP_SendPacket(m_pRtmp, packet, TRUE);if (success != 1) {dm_printf("send_video_sps_pps fail");ret = -1;}}elseret = -1;free(packet);return ret;}5.rtmp发送普通的NAL
static int send_rtmp_video(RTMP* m_pRtmp, unsigned char *data, int data_len, int timestamp) {int type;RTMPPacket * packet;unsigned char * body;unsigned char* buffer = data;unsigned int length = data_len;int ret = 0;if (m_pRtmp == NULL)return -1;/*去掉帧界定符(这里可能2种,但是sps or pps只能为 00 00 00 01)*/if (buffer[2] == 0x00) { /*00 00 00 01*/buffer += 4;length -= 4;} else if (buffer[2] == 0x01) { /*00 00 01*/buffer += 3;length -= 3;}type = buffer[0] & 0x1f;packet = (RTMPPacket *) malloc(RTMP_HEAD_SIZE + length + 9);memset(packet, 0, RTMP_HEAD_SIZE);packet->m_body = (char *) packet + RTMP_HEAD_SIZE;packet->m_nBodySize = length + 9;/*send video packet*/body = (unsigned char *) packet->m_body;memset(body, 0, length + 9);/*key frame*/body[0] = 0x27;if (type == NAL_SLICE_IDR) //此为关键帧{body[0] = 0x17;}body[1] = 0x01; /*nal unit*/body[2] = 0x00;body[3] = 0x00;body[4] = 0x00;body[5] = (length >> 24) & 0xff;body[6] = (length >> 16) & 0xff;body[7] = (length >> 8) & 0xff;body[8] = (length) & 0xff;/*copy data*/memcpy(&body[9], buffer, length);packet->m_nTimeStamp = timestamp;packet->m_hasAbsTimestamp = 0;packet->m_packetType = RTMP_PACKET_TYPE_VIDEO;packet->m_nInfoField2 = m_pRtmp->m_stream_id;packet->m_nChannel = 0x04;packet->m_headerType = RTMP_PACKET_SIZE_MEDIUM;if (RTMP_IsConnected(m_pRtmp)) {// 调用发送接口ret = RTMP_SendPacket(m_pRtmp, packet, TRUE);if (ret != 1){dm_printf("send_rtmp_video fail");ret = -1;} } else{dm_printf("send_rtmp_video RTMP is not ready");ret = -1;}free(packet);return ret;}6. 初始化rtmp
定义结构体
typedef struct rtmp_infor{char *aac_buf;char *x264_buf;int nal_len[20];int nal_count;int audio_first;int video_first;int init_flag;RTMP *prtmp ;X264Args x264args;AudioEncodeFaac aacargs;}RTMPInfor;int RTMP_Send_Init(char *url, int width, int height, int sample_rate, int channel){int ret = 0;if (rtmp_infor.init_flag == 1){dm_printf("RTMP_Send_Init again init");return -1;}if (url == NULL){dm_printf("url is NULL");return -1;}if (width <= 0 || height <= 0 || channel <= 0){dm_printf("width or height or channel is error");return -1;}pthread_mutex_lock(&thread_lock_rtmp_send);memset(&rtmp_infor, 0, sizeof(rtmp_infor));ret = RTMP_Connect(&rtmp_infor.prtmp, url);if (ret < 0){dm_printf("RTMP_Connect fail");goto end;}ret = Audio_Encode_Init_Faac(&rtmp_infor.aacargs, sample_rate, channel);if (ret < 0){dm_printf("Audio_Encode_Init_Faac fail");goto end;}ret = X264encode_Init_Args_ForRtmp(&rtmp_infor.x264args, NULL, width, height);if (ret < 0){dm_printf("Audio_Encode_Init_Faac fail");goto end;}rtmp_infor.aac_buf = (char *)malloc(NB_SAMPLE << channel);rtmp_infor.x264_buf = (char *)malloc(width * height * 3 >> 1);if (rtmp_infor.aac_buf == NULL || rtmp_infor.x264_buf == NULL){dm_printf("aac_buf or 264_buf alloc fail");ret = -1;goto end;}rtmp_infor.init_flag = 1;end:if (ret < 0){X264encode_Finish_Args_ForRtmp(&rtmp_infor.x264args);Audio_Encode_Release_Faac(&rtmp_infor.aacargs);RTMP_Close(&rtmp_infor.prtmp);if (rtmp_infor.aac_buf != NULL)free(rtmp_infor.aac_buf);if (rtmp_infor.x264_buf != NULL)free(rtmp_infor.x264_buf);memset(&rtmp_infor, 0, sizeof(rtmp_infor));}pthread_mutex_unlock(&thread_lock_rtmp_send);return ret;}
7,rtmp发送一桢264流int RTMP_Send_Video(unsigned char *data, int nw, int nh, int isFrontCamera, int orientation, int isInversion, int mode, int timestamp){int ret = 0;if (data == NULL)return -1;if (!rtmp_infor.init_flag){dm_printf("RTMP_Send Not Init");return -1;}pthread_mutex_lock(&thread_lock_rtmp_send);ret = X264encodeAddframe_Args_ForRtmp(&rtmp_infor.x264args,(uint8_t *)data, nw, nh, isFrontCamera, orientation, isInversion, rtmp_infor.x264_buf, rtmp_infor.nal_len, &rtmp_infor.nal_count, mode);if (ret < 0)goto end;rtmp_send_video(rtmp_infor.prtmp, (unsigned char *)rtmp_infor.x264_buf, rtmp_infor.nal_len, rtmp_infor.nal_count, timestamp, &rtmp_infor.video_first);end:pthread_mutex_unlock(&thread_lock_rtmp_send);return ret;}8,rtmp释放资源
int RTMP_Send_Release(){if (!rtmp_infor.init_flag)return 0;pthread_mutex_lock(&thread_lock_rtmp_send);X264encode_Finish_Args_ForRtmp(&rtmp_infor.x264args);Audio_Encode_Release_Faac(&rtmp_infor.aacargs);RTMP_Close(&rtmp_infor.prtmp);if (rtmp_infor.aac_buf != NULL)free(rtmp_infor.aac_buf);if (rtmp_infor.x264_buf != NULL)free(rtmp_infor.x264_buf);memset(&rtmp_infor, 0, sizeof(rtmp_infor));pthread_mutex_unlock(&thread_lock_rtmp_send);return 0;}总结:rtmp发送264流,还是有一些坑要踩的,我认为我遇到最主要的坑,就是编码的时候一桢编出来很多NAL单元,导致推过去的流解不出来,希望写这个博客对初学者有点帮助1 0
- android librtmp 推送h264流 aac流 基本过程总结四 推流x264
- android librtmp 推送h264流 aac流 基本过程总结五 推流aac
- android librtmp 推送h264流 aac流 基本过程总结二 x264移植
- android librtmp 推送h264流 aac流 基本过程总结一 移植librtmp
- android librtmp 推送h264流 aac流 基本过程总结三 移植faac
- h.264 aac librtmp推流应用
- Android 使用librtmp推流
- 树莓派使用python-librtmp实现rtmp推流h264
- iOS音频AAC视频H264编码 推流最佳方案
- 基于FFMPEG的RTP推流H264和AAC文件
- 【基于libRTMP的流媒体直播之 AAC、H264 推送】
- 基于libRTMP的流媒体直播之 AAC、H264 推送
- 基于libRTMP的流媒体直播之 AAC、H264 推送
- 基于libRTMP的流媒体直播之 AAC、H264 推送
- 【基于libRTMP的流媒体直播之 AAC、H264 推送】
- 【基于libRTMP的流媒体直播之 AAC、H264 推送】
- 基于libRTMP的流媒体直播之 AAC、H264 推送
- 【基于libRTMP的流媒体直播之 AAC、H264 推送】
- Java 集合——ConcurrentHashMap
- 学习Web安全建议
- 快速理解盒模型
- flex实现div/li等水平居中布局
- Android系统编译脚本理解
- android librtmp 推送h264流 aac流 基本过程总结四 推流x264
- 跳转页面referrer验证失败
- 简单的一个ViewPager无限循环
- ViewPager与RadioGroup
- Invalid bitcode signature,App Match-O Linker
- Mysql
- 拜读阮一峰JavaScript教程笔记
- JavaScript基础(运算符)
- workbench模拟器simulator的使用之虚拟网卡的建立
原创粉丝点击
热门IT博客
热门问题
老师的惩罚
人脸识别
我在镇武司摸鱼那些年
重生之率土为王
我在大康的咸鱼生活
盘龙之生命进化
天生仙种
凡人之先天五行
春回大明朝
姑娘不必设防,我是瞎子
杜仲茶哪里的好
杜仲茶能降压吗
杜仲茶怎么样
杜仲茶专卖店
杜仲茶哪里有得卖
杜仲茶雄花茶
杜仲茶 便秘
杜仲茶好喝吗
杜仲茶能天天喝吗
什么叫杜仲茶
杜仲茶辨别
睡前喝杜仲茶
鹤寿杜仲茶价格
杜仲茶适合人群
杜仲茶 降压
杜仲茶味道
长期喝杜仲茶
杜仲茶 减肥
什么样的杜仲茶好
杜仲茶 失眠
月子 杜仲茶
产后喝杜仲茶
杜仲茶拉丝
君辉杜仲茶价格
坐月子喝杜仲茶
杜仲茶 拉肚子
产后 杜仲茶
杜仲茶饮用方法
杜仲茶哪些人不适宜喝
杜仲茶的功效与作用
杜仲茶的作用与功效
杜仲茶可以长期喝吗
喝杜仲茶有什么好处
杜仲茶和杜仲雄花茶
隔夜的杜仲茶能喝吗
杜仲茶可以隔夜喝吗
哪个牌子的杜仲茶好
孕妇可以喝杜仲茶吗
杜仲雄花茶的作用与功效
杜肿的作用是什么
杜仲泡酒有什么功效