范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

基于FFmpeg音视频流同步

  通过FFmpeg将PCM音频数据和RGB视频数据转码、编码成AAC+H264,再通过内存读写数据封装MP4格式。
  难点在于将转码后的数据输出到内存中,再从内存读取数据并封装 AVFormatContext *ic = NULL;   ic = avformat_alloc_context();     unsigned char * iobuffer=(unsigned char *)av_malloc(32768);//音视频大小   AVIOContext *avio =avio_alloc_context(iobuffer, 32768,0,buffer,fill_iobuffer,NULL,NULL);   ic->pb=avio;   err = avformat_open_input(&ic, is->filename, is->iformat, &format_opts);
  关键要在avformat_open_input()之前初始化一个AVIOContext,而且将原本的AVFormatContext的指针pb(AVIOContext类型)指向这个自行初始化AVIOContext。当自行指定了AVIOContext之后,avformat_open_input()里面的URL参数就不起作用了。示例代码开辟了一块空间iobuffer作为AVIOContext的缓存。
  此外buffer就是期望读取数据的内存,fill_iobuffer则是读取buffer数据至iobuffer的回调函数。fill_iobuffer()形式(参数,返回值)是固定的,是一个回调函数,具体怎么读取数据可以自行设计。//把数据从buffer向iobuf传   //AVIOContext使用的回调函数   //注意:返回值是读取的字节数   //手动初始化AVIOContext只需要两个东西:内容来源的buffer,和读取这个buffer到ffmpeg中的函数   int fill_iobuffer(void * buffer,uint8_t *iobuf, int bufsize){        int i;        for(i=0;ipb = avio_in_v; 	ifmt_ctx_v->flags = AVFMT_FLAG_CUSTOM_IO;   	if ((ret2 = avformat_open_input(&ifmt_ctx_v, "NOTHING", 0, 0)) < 0) { 		printf("Could not open input file1."); 		goto end; 	} 	if ((ret2 = avformat_find_stream_info(ifmt_ctx_v, 0)) < 0) { 		printf("Failed to retrieve input stream information"); 		goto end; 	}   	//视频流 	for (k = 0; k < ifmt_ctx_v->nb_streams; k++) { 		//根据输入流创建输出流 		if (ifmt_ctx_v->streams[k]->codec->codec_type == AVMEDIA_TYPE_VIDEO){ 			AVStream *in_stream = ifmt_ctx_v->streams[k]; 			AVStream *out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec); 			videoindex_v = k; 			if (!out_stream) { 				printf("Failed allocating output stream "); 				ret2 = AVERROR_UNKNOWN; 				goto end; 			} 			videoindex_out = out_stream->index; 			//复制AVCodecContext的设置 			if (avcodec_copy_context(out_stream->codec, in_stream->codec) < 0) { 				printf("Failed to copy context from input to output stream codec context "); 				goto end; 			} 			out_stream->codec->codec_tag = 0; 			if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) 				out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; 			break; 		} 	}   end: 	if (ret2 < 0 && ret2 != AVERROR_EOF) { 		printf("Error occurred. "); 		return -1; 	}   	return 0; }   int ffmpeg_muxer_audio_init() { 	//audio in 	inbuffer_a = (unsigned char*)av_malloc(AUDIO_AVIO_SIZE); 	avio_in_a = avio_alloc_context(inbuffer_a, AUDIO_AVIO_SIZE, 0, 0, 		read_audio_buffer, NULL, NULL);   	if (avio_in_a == NULL) 		goto end;   	ifmt_ctx_a = avformat_alloc_context(); 	ifmt_ctx_a->pb = avio_in_a; 	ifmt_ctx_a->flags = AVFMT_FLAG_CUSTOM_IO;   	if ((ret2 = avformat_open_input(&ifmt_ctx_a, "NOTHING", 0, 0)) < 0) { 		printf("Could not open input file."); 		goto end; 	} 	if ((ret2 = avformat_find_stream_info(ifmt_ctx_a, 0)) < 0) { 		printf("Failed to retrieve input stream information"); 		goto end; 	}   	//音频流 	for (k = 0; k < ifmt_ctx_a->nb_streams; k++) { 		//根据输入流创建输出流 		if (ifmt_ctx_a->streams[k]->codec->codec_type == AVMEDIA_TYPE_AUDIO){ 			AVStream *in_stream = ifmt_ctx_a->streams[k]; 			AVStream *out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec); 			audioindex_a = k; 			if (!out_stream) { 				printf("Failed allocating output stream "); 				ret2 = AVERROR_UNKNOWN; 				goto end; 			} 			audioindex_out = out_stream->index; 			//复制AVCodecContext的设置 			if (avcodec_copy_context(out_stream->codec, in_stream->codec) < 0) { 				printf("Failed to copy context from input to output stream codec context "); 				goto end; 			} 			out_stream->codec->codec_tag = 0; 			if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) 				out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;   			break; 		} 	}   end: 	if (ret2 < 0 && ret2 != AVERROR_EOF) { 		printf("Error occurred. "); 		return -1; 	}   	return 0; }   int ffmpeg_muxer_init() { 	char *out_filename = "myfile.mp4";//输出文件名   	av_register_all();   	//输出(Output) 	avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename); 	if (!ofmt_ctx) { 		printf("Could not create output context "); 		ret2 = AVERROR_UNKNOWN; 		goto end; 	} 	ofmt = ofmt_ctx->oformat;   	//视频流 	ffmpeg_muxer_video_init(); 	//音频流 	ffmpeg_muxer_audio_init();   	//打开输出文件 	if (!(ofmt->flags & AVFMT_NOFILE)) { 		if (avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE) < 0) { 			printf("Could not open output file "%s"", out_filename); 			goto end; 		} 	} 	//写文件头 	if (avformat_write_header(ofmt_ctx, NULL) < 0) { 		printf("Error occurred when opening output file "); 		goto end; 	}   	aacbsfc = av_bitstream_filter_init("aac_adtstoasc");   end: 	if (ret2 < 0 && ret2 != AVERROR_EOF) { 		printf("Error occurred. "); 		return -1; 	}   	return 0; }   int ffmpeg_muxer(int enccnt) { 	if (InitFlg == 1){ 		ffmpeg_muxer_init(); 		InitFlg = 0; 	}   	while (1) { 		AVFormatContext *ifmt_ctx; 		int stream_index = 0; 		AVStream *in_stream, *out_stream; 		int cmpflg = 0;   		if ((ifmt_ctx_v != NULL) && (ifmt_ctx_a != NULL)) 			cmpflg = av_compare_ts(cur_pts_v, ifmt_ctx_v->streams[videoindex_v]->time_base, cur_pts_a, ifmt_ctx_a->streams[audioindex_a]->time_base); 		if ((ifmt_ctx_v == NULL) && (ifmt_ctx_a != NULL)) 			cmpflg = 1; 		if ((ifmt_ctx_v != NULL) && (ifmt_ctx_a == NULL)) 			cmpflg = 0;   		//获取一个AVPacket 		if (cmpflg <= 0){ 			ifmt_ctx = ifmt_ctx_v; 			stream_index = videoindex_out;   			if (av_read_frame(ifmt_ctx, &pkt2) >= 0){ 				do{ 					in_stream = ifmt_ctx->streams[pkt2.stream_index]; 					out_stream = ofmt_ctx->streams[stream_index];   					if (pkt2.stream_index == videoindex_v){ 						//FIX:No PTS (Example: Raw H.264) 						//Simple Write PTS 						if (pkt2.pts == AV_NOPTS_VALUE){ 							//Write PTS 							AVRational time_base1 = in_stream->time_base; 							//Duration between 2 frames (us) 							int64_t calc_duration = (double)AV_TIME_BASE / av_q2d(in_stream->r_frame_rate); 							//Parameters 							pkt2.pts = (double)(frame_index*calc_duration) / (double)(av_q2d(time_base1)*AV_TIME_BASE); 							pkt2.dts = pkt2.pts; 							pkt2.duration = (double)calc_duration / (double)(av_q2d(time_base1)*AV_TIME_BASE); 							frame_index++; 						}   						cur_pts_v = pkt2.pts; 						break; 					} 				} while (av_read_frame(ifmt_ctx, &pkt2) >= 0); 			} 			else{ 				break; 			} 		} 		else{ 			ifmt_ctx = ifmt_ctx_a; 			stream_index = audioindex_out; 			if (av_read_frame(ifmt_ctx, &pkt2) >= 0){ 				do{ 					in_stream = ifmt_ctx->streams[pkt2.stream_index]; 					out_stream = ofmt_ctx->streams[stream_index];   					if (pkt2.stream_index == audioindex_a){   						//FIX:No PTS 						//Simple Write PTS 						if (pkt2.pts == AV_NOPTS_VALUE){ 							//Write PTS 							AVRational time_base1 = in_stream->time_base; 							//Duration between 2 frames (us) 							int64_t calc_duration = (double)AV_TIME_BASE / av_q2d(in_stream->r_frame_rate); 							//Parameters 							pkt2.pts = (double)(frame_index*calc_duration) / (double)(av_q2d(time_base1)*AV_TIME_BASE); 							pkt2.dts = pkt2.pts; 							pkt2.duration = (double)calc_duration / (double)(av_q2d(time_base1)*AV_TIME_BASE); 							frame_index++; 						} 						cur_pts_a = pkt2.pts;   						break; 					} 				} while (av_read_frame(ifmt_ctx, &pkt2) >= 0); 			} 			else{ 				break; 			}   		}   		av_bitstream_filter_filter(aacbsfc, out_stream->codec, NULL, &pkt2.data, &pkt2.size, pkt2.data, pkt2.size, 0);   		/* copy packet */ 		//转换PTS/DTS(Convert PTS/DTS) 		pkt2.pts = av_rescale_q_rnd(pkt2.pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); 		pkt2.dts = av_rescale_q_rnd(pkt2.dts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX)); 		pkt2.duration = av_rescale_q(pkt2.duration, in_stream->time_base, out_stream->time_base); 		pkt2.pos = -1; 		pkt2.stream_index = stream_index;   		printf("Write 1 Packet. size:%5d	pts:%8d ", pkt2.size, pkt2.pts); 		//写入(Write) 		if (av_interleaved_write_frame(ofmt_ctx, &pkt2) < 0) { 			printf("Error muxing packet "); 			break; 		} 		av_free_packet(&pkt2); 	}   end: 	if (ret2 < 0 && ret2 != AVERROR_EOF) { 		printf("Error occurred. "); 		return -1; 	}   	return 0;   }   int ffmpeg_video_encode_init() { 	AVOutputFormat* fmt;   	const char* out_file = "record.h264"; //Output Filepath,用于设置AVFormatContext   	//初始化并注册视频文件格式与编解码库 	av_register_all(); 	//初始化AVFormatContext,Allocate an AVFormatContext.  	pFormatCtx_v = avformat_alloc_context(); 	fmt = av_guess_format(NULL, out_file, NULL); 	pFormatCtx_v->oformat = fmt;   	//AVStream的初始化函数 	video_st = avformat_new_stream(pFormatCtx_v, 0); 	video_st->time_base.num = 1; 	video_st->time_base.den = 25;   	if (video_st == NULL){ 		return -1; 	} 	//Param that must set 	pCodecCtx_v = video_st->codec; 	pCodecCtx_v->codec_id = fmt->video_codec; 	pCodecCtx_v->codec_type = AVMEDIA_TYPE_VIDEO; 	pCodecCtx_v->pix_fmt = PIX_FMT_YUV420P; 	pCodecCtx_v->width = in_w; 	pCodecCtx_v->height = in_h; 	pCodecCtx_v->time_base.num = 1; 	pCodecCtx_v->time_base.den = 25;  //10&25 	pCodecCtx_v->bit_rate = 4334000;// 400000; 	pCodecCtx_v->gop_size = 10;    //250 //关键帧的最大间隔帧数/ 	//H264 	//pCodecCtx->me_range = 16; 	//pCodecCtx->max_qdiff = 4; 	//pCodecCtx->qcompress = 0.6; 	pCodecCtx_v->qmin = 10; 	pCodecCtx_v->qmax = 51;   	//Optional Param 	pCodecCtx_v->max_b_frames = 1; //3   	// Set Option 	AVDictionary *param = 0; 	//H.264 	if (pCodecCtx_v->codec_id == AV_CODEC_ID_H264) { 		av_dict_set(¶m, "preset", "superfast", 0); 		av_dict_set(¶m, "tune", "zerolatency", 0); 	}   	//Show some Information 	av_dump_format(pFormatCtx_v, 0, out_file, 1);   	pCodec_v = avcodec_find_encoder(pCodecCtx_v->codec_id); 	if (!pCodec_v){ 		printf("Can not find video encoder!  "); 		return -1; 	} 	if (avcodec_open2(pCodecCtx_v, pCodec_v, ¶m) < 0){ 		printf("Failed to open video encoder!  "); 		return -1; 	}   	pFrameRGB = av_frame_alloc(); 	pFrameYUV = av_frame_alloc();   	picture_size_RGB = avpicture_get_size(PIX_FMT_RGB24, pCodecCtx_v->width, pCodecCtx_v->height); 	picture_size_YUV = avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx_v->width, pCodecCtx_v->height); 	picture_buf_RGB = (uint8_t *)av_malloc(picture_size_RGB); 	picture_buf_YUV = (uint8_t *)av_malloc(picture_size_YUV); 	avpicture_fill((AVPicture *)pFrameRGB, picture_buf_RGB, PIX_FMT_RGB24, pCodecCtx_v->width, pCodecCtx_v->height); 	avpicture_fill((AVPicture *)pFrameYUV, picture_buf_YUV, PIX_FMT_YUV420P, pCodecCtx_v->width, pCodecCtx_v->height);   	scxt = sws_getContext(pCodecCtx_v->width, pCodecCtx_v->height, PIX_FMT_RGB24, pCodecCtx_v->width, pCodecCtx_v->height, 		PIX_FMT_YUV420P, SWS_POINT, NULL, NULL, NULL);   	av_new_packet(&pkt_v, picture_size_YUV); 	y_size = pCodecCtx_v->width * pCodecCtx_v->height;   	return 0; }   int ffmpeg_video_encode(int i) { 	int got_picture = 0; 	//Read raw YUV data 	//YUV420 数据在内存中的长度是 width * hight * 3 / 2 	if (fread(picture_buf_RGB, 1, y_size * 3, in_file_v) != y_size * 3){ 		printf("video goto end! "); 		fseek(in_file_v, 0, SEEK_SET); 		fread(picture_buf_RGB, 1, y_size * 3, in_file_v); 	} 	 	sws_scale(scxt, pFrameRGB->data, pFrameRGB->linesize, 0, pCodecCtx_v->height, pFrameYUV->data, pFrameYUV->linesize);   	pFrameYUV->data[0] = picture_buf_YUV;              // Y 	pFrameYUV->data[1] = picture_buf_YUV + y_size;      // U  	pFrameYUV->data[2] = picture_buf_YUV + y_size * 5 / 4;  // V 	//PTS 	//pFrameYUV->pkt_pts = i; 	pFrameYUV->pkt_pts = i * (video_st->time_base.den) / ((video_st->time_base.num) * 25);   	av_init_packet(&pkt_v); 	//Encode 	int ret = avcodec_encode_video2(pCodecCtx_v, &pkt_v, pFrameYUV, &got_picture); 	if (ret < 0){ 		printf("Failed to video encode!  "); 		return -1; 	} 	if (got_picture == 1){ 		if ((videoencodesize + pkt_v.size) > VIDEO_AVIO_SIZE) 		{ 			printf("video avio buffer is full: %d, to mux! ", videoencodesize); 			ffmpeg_muxer(i); 			//fwrite(videoBuf, 1, videoencodesize, out_encode); 			videoencodesize = 0; 		} 		memcpy(videoBuf + videoencodesize, pkt_v.data, pkt_v.size); 		frmsize_v = pkt_v.size; 		videoencodesize += frmsize_v; 		printf("Succeed to encode video frame: %5d	size:%5d ", i, pkt_v.size); 		av_free_packet(&pkt_v); 	} }   void ffmpeg_video_encode_close() { 	//video Clean 	if (video_st){ 		avcodec_close(video_st->codec); 		av_free(pFrameRGB); 		av_free(pFrameYUV); 		av_free(picture_buf_RGB); 		av_free(picture_buf_YUV); 	} 	avio_close(pFormatCtx_v->pb); 	avformat_free_context(pFormatCtx_v);   	fclose(in_file_v); }   int ffmpeg_audio_encode_init() { 	AVOutputFormat* fmt;   	const char* out_file = "record_audio.aac";	//输出文件,用于设置AVFormatContext   	av_register_all();   	avformat_alloc_output_context2(&pFormatCtx_a, NULL, NULL, out_file); 	fmt = pFormatCtx_a->oformat;   	audio_st = avformat_new_stream(pFormatCtx_a, 0); 	if (audio_st == NULL){ 		return -1; 	} 	pCodecCtx_a = audio_st->codec; 	pCodecCtx_a->codec_id = fmt->audio_codec; 	pCodecCtx_a->codec_type = AVMEDIA_TYPE_AUDIO; 	pCodecCtx_a->sample_fmt = AV_SAMPLE_FMT_S16; 	pCodecCtx_a->sample_rate = 48000;  //44100---11025(8000) 	pCodecCtx_a->channel_layout = AV_CH_LAYOUT_STEREO; 	pCodecCtx_a->channels = av_get_channel_layout_nb_channels(pCodecCtx_a->channel_layout); 	pCodecCtx_a->bit_rate = 1536000;    //64000   	//输出格式信息 	av_dump_format(pFormatCtx_a, 0, out_file, 1);   	pCodec_a = avcodec_find_encoder(pCodecCtx_a->codec_id); 	if (!pCodec_a) 	{ 		printf("audio 没有找到合适的编码器! "); 		return -1; 	} 	if (avcodec_open2(pCodecCtx_a, pCodec_a, NULL) < 0) 	{ 		printf("audio 编码器打开失败! "); 		return -1; 	} 	frame_a = av_frame_alloc(); 	frame_a->nb_samples = pCodecCtx_a->frame_size; 	frame_a->format = pCodecCtx_a->sample_fmt;   	frame_size_a = av_samples_get_buffer_size(NULL, pCodecCtx_a->channels, pCodecCtx_a->frame_size, pCodecCtx_a->sample_fmt, 1); 	frame_buf_a = (uint8_t *)av_malloc(frame_size_a); 	avcodec_fill_audio_frame(frame_a, pCodecCtx_a->channels, pCodecCtx_a->sample_fmt, (const uint8_t*)frame_buf_a, frame_size_a, 1); 	av_new_packet(&pkt_a, frame_size_a);   	return 0; }   int ffmpeg_audio_encode(int i) { 	//读入PCM 	if (fread(frame_buf_a, 1, frame_size_a, in_file_a) != frame_size_a) 	{ 		printf("audio goto end! "); 		fseek(in_file_a, 0, SEEK_SET); 		fread(frame_buf_a, 1, frame_size_a, in_file_a); 	}   	frame_a->data[0] = frame_buf_a;  //采样信号 	frame_a->pts = i;//i*100 	int got_frame = 0; 	//编码 	int ret = avcodec_encode_audio2(pCodecCtx_a, &pkt_a, frame_a, &got_frame); 	if (ret < 0) 	{ 		printf("audio 编码错误! "); 		return -1; 	} 	if (got_frame == 1) 	{ 		if ((audioencodesize + pkt_a.size) > AUDIO_AVIO_SIZE) 		{ 			printf("audio avio buffer is full: %d, to mux! ", audioencodesize); 			ffmpeg_muxer(i); 			audioencodesize = 0; 		} 		memcpy(audioBuf + audioencodesize, pkt_a.data, pkt_a.size); 		frmsize_a = pkt_a.size; 		audioencodesize += frmsize_a;   		printf("audio 编码成功第%d帧! ", i); 		av_free_packet(&pkt_a); 	}   	return 0; }   void ffmpeg_audio_encode_close() { 	//audio清理 	if (audio_st) 	{ 		avcodec_close(audio_st->codec); 		av_free(frame_a); 		av_free(frame_buf_a); 	} 	avio_close(pFormatCtx_a->pb); 	avformat_free_context(pFormatCtx_a);   	fclose(in_file_a); }   int flush_video_encoder(AVFormatContext *fmt_ctx, unsigned int stream_index){ 	int ret; 	int got_frame; 	AVPacket enc_pkt; 	if (!(fmt_ctx->streams[stream_index]->codec->codec->capabilities & 		CODEC_CAP_DELAY)) 		return 0; 	while (1) { 		enc_pkt.data = NULL; 		enc_pkt.size = 0; 		av_init_packet(&enc_pkt); 		ret = avcodec_encode_video2(fmt_ctx->streams[stream_index]->codec, &enc_pkt, 			NULL, &got_frame); 		av_frame_free(NULL); 		if (ret < 0) 			break; 		if (!got_frame){ 			ret = 0; 			break; 		} 		printf("Flush Encoder: Succeed to encode 1 frame!	size:%5d ", enc_pkt.size); 		/* mux encoded frame */ 		ret = av_write_frame(fmt_ctx, &enc_pkt); 		printf("Succeed to encode pkt.pts: %5d	pkt.dts:%5d ", enc_pkt.pts, enc_pkt.dts); 		if (ret < 0) 			break; 	} 	return ret; }   int main(int argc, char* argv[]) { 	int framenum = 1000;	//帧数 	int i = 0; 	 	//mux初始化flag 	InitFlg = 1; 	//video编码初始化函数 	ffmpeg_video_encode_init(); 	//audio编码初始化函数 	ffmpeg_audio_encode_init();   	for (i = 0; i
2500元内性价比最高手机推荐1。IQOOneo5,搭载7nm高通骁龙870处理器,独立显示芯片。4400mah电池,66w闪充。6。62英寸三星E4中置打孔屏,120赫兹刷新率,4800w三摄。独立显示芯片可配备12GBRAM的英特尔酷睿i51135G7TigerLake迷你PC,售价700起文章来源配备12GBRAM的英特尔酷睿i51135G7TigerLake迷你电脑CNXSoftware中文站MinisforumTL50是一款基于TigerLake四核八线程处理器熟悉的荣耀回来了!120Hz屏66W闪充6nm芯片,仅1899元今天我们来聊一下荣耀手机,其实荣耀手机独立华为后,很多网友可能不怎么看好了,大家可以看到荣耀V40V40轻奢版和荣耀50系列等,性价比都不是很高,跟以前还是华为子品牌相差太多了,不联想要干什么?杨元庆突然宣布,准备自研芯片?对于联想,相信大家都不陌生,它曾是国内最知名的民营企业,深受无数国人拥戴。但是后来联想却走错了路,一方面喊着科技无国界的口号,另一方面不断地淡化自己是一家中国公司的身份,这让它引起性能提升20!高通芯片王牌浮出水面,骁龙888面临淘汰近段时间,国产手机品牌陆续推出了骁龙888Plus旗舰机。虽然这款处理器是骁龙888的升级版,但最高主频的提升同时也意味着功耗的增大。因此在笔者看来,相比骁龙888,骁龙888Pl小米为什么要做铁蛋?铁蛋能干啥?这是官方回复在8月10日晚间小米的新品发布会上,最后的彩蛋CyberDog让很多人看到了小米在黑科技和未来技术方面的努力,而且发布会之后CyberDog的关注度也越来越高,对此,小米集团副总裁汉印M11便携口袋标签打印机让杂乱生活更有序前言厨房收纳文件分类充电器分类等都离不开标签打印机,有了它找东西一找一个准,对于大多数人来说标签打印机还是新鲜事物,如何选择一款实用的标签打印机也是非常的头疼。汉印M11便携口袋标Redmi10通过NBTC认证仅支持4GLTE网络继本周早些时候现身新加坡电商网站之后,近日Redmi10获得了泰国NBTC的认证,表明该机即将上市发售。不过遗憾的是,在认证文件中只是确认Redmi10仅支持4GLTE网络,而不支百度地图推出全新AR步行导航走地下通道再也不担心迷路了中国青年报客户端讯(中青报中青网记者孟佩佩)动辄多个出入口的地下通道,经常让人一不留神就走错方向,又由于地下通道的信号弱,导航也束手无策。近日,记者了解到,百度地图针对地下通道场景限制再次被破解,RTX30LHR继续空气卡新软件让Ryzen55600G更香N卡LHR限制再次被攻破利润驱使之下破解永不止步,RTX30LHR系列看来会继续空气卡。和之前RTX3060哈希率限制第一次被攻破不同,这次和显卡驱动无关。即便是后期更改了硬件ID一周充一次,一次续航150km!这三款长续航电动车,跑外卖都在用随着科学技术的发展,如今的电动车功能已经超过了一般意义上咱们所说的代步车,一波波黑科技的加持,电动车已然演变成了一个智能化的科技品。一键启动智能导航语音提示等等,尽管有很多花里胡哨
百万召回一年白干,上汽通用五菱的口碑危机?一则召回信息,将聚光灯照在了国民神车上。7月16日,上汽通用五菱汽车股份有限公司根据缺陷汽车产品召回管理条例缺陷汽车产品召回管理条例实施办法和机动车排放召回管理规定的要求,向国家市游戏性能全面觉醒,iQOONeo3助你轻松上分上星如今,智能手机成为人们生活中不可缺少的需求。对于年轻人而言,手机游戏也成为了他们闲暇之余的娱乐项目,常常一起开黑带妹。王者荣耀和平精英崩坏3等等大型手游,对手机的硬件配置也有一定要2020年中国移动互联网内容生态洞察报告核心摘要随着智能终端的发展和人们精神消费品质的不断升级,用户需求驱动着内容消费形式的不断革新,深刻地改变着移动互联网下的内容生产分发传播消费全过程,不断拓宽原有应用场景和边界,助力SVC综艺市场洞察创造营2020内容共建IP矩阵核心摘要腾讯视频S级女团成长综艺创造营2020于今年5月重磅上线,收视口碑赢得双丰收,赛制升级和导师阵容为节目一度带来超过行业平均水平14倍的讨论热度。另一方面,节目与品牌携手通过2020年中国视频会议行业研究报告核心摘要概念界定视频会议强调不同地点的人或群体,通过网络与多媒体设备,将声音影像与文件等资料经过编码分发解码等流程实现实时互传。不同于直播与录播的单向互动,视频会议更加注重多方音视重磅!20192020年中国产业互联网发展指数报告核心摘要2019年以来,中国GDP增长的科技进步贡献率达到58。5,与发达国家相比仍有近20个百分点的增长空间。与此同时,经历二十余年的发展中国已成长为互联网超级应用大国,围绕消费2020年中国公共充电桩行业研究报告核心摘要充电桩市场2020年充电桩纳入新基建,窗口期缩短,充电桩行业有望迎来关键发展阶段。驱动因素充电桩政策及补贴逐渐向运营端转移运营及盈利能力的提高将带动企业获得新一轮融资而充电2020年中国AI零售行业发展研究报告核心摘要概念界定通过人工智能技术作为主要驱动力,为零售行业各参与主体各业务环节赋能,突出AI技术对零售业的整体升级改造。发展特点AI零售技术服务可帮助零售企业及品牌商促进降本增效提2020年中国政务云行业研究报告核心摘要驱动因素政府管理理念的转变驱动政务信息化向政务云演进的内在动因。以云计算产业的发展进步为基石,各项国家政策对政务云起到直接推动作用。基于数字中国建设的大背景,转变职能中心的2020年中国AI医疗行业研究报告核心摘要前言本次AI医疗研究范畴仅限于围绕临床诊疗开展的核心医疗活动,包括CDSS智慧病案AI检查AI新药研发及手术机器人。目前中国对AI医疗的需求逐渐扩大,而供给尚显不足,整体供2021年中国电竞行业研究报告核心摘要市场2020年电竞整体市场规模超过1450亿元,增长主要来自于移动电竞游戏市场和电竞生态市场的快速发展。预计在2021年电竞市场将突破1800亿元。驱动电竞成为杭州亚运会正