专栏电商日志财经减肥爱情
投稿投诉
爱情常识
搭配分娩
减肥两性
孕期塑形
财经教案
论文美文
日志体育
养生学堂
电商科学
头戴业界
专栏星座
用品音乐

iOS完整推流采集音视频数据编码同步合成流

  需求
  众所周知,原始的音视频数据无法直接在网络上传输,推流需要编码后的音视频数据以合成的视频流,如flv,mov,asf流等,根据接收方需要的格式进行合成并传输,这里以合成asf流为例,讲述一个完整推流过程:即音视频从采集到编码,同步合成asf视频流,然后可以将流进行传输,为了方便,本例将合成的视频流写入一个asf文件中,以供测试。
  注意:测试需要使用终端通过:ffplay播放demo中录制好的文件,因为asf是windows才支持的格式,mac自带播放器无法播放。1、实现原理采集:采集视频帧使用AVCaptureSession,采集音频帧使用AudioUnit编码:编码视频数据使用VideoToolbox中vtCompresssion硬编,编码音频数据使用audioconverter软编。同步:根据时间戳生成策略合成:使用FFmpegmux编码的音视频数据以合成视频流后续:合成好的视频流可以通过网络传输或是录制成文件2、阅读前提音视频基础知识推荐必读:H264,H265硬件编解码基础及码流分析iOS视频采集实战(AVCaptureSession)AudioUnit采集音频实战视频编码实战音频编码实战iOSFFmpeg环境搭建
  代码地址:iOS完整推流
  掘金地址:iOS完整推流
  简书地址:iOS完整推流
  博客地址:iOS完整推流3、总体架构
  1。mux
  对于iOS而言,我们可以通过底层API捕获视频帧与音频帧数据,捕获视频帧使用AVFoundation框架中的AVCaptureSession,其实它同时也可以捕获音频数据,而因为我们想使用最低延时与最高音质的音频,所以需要借助最底层的音频捕捉框架AudioUnit,然后使用VideoToolbox框架中的VTCompressionSessionRef可以对视频数据进行编码,使用AudioConverter可以对音频数据进行编码,我们在采集时可以将第一帧I帧产生时的系统时间作为音视频时间戳的一个起点,往后的视频说都基于此,由此可扩展做音视频同步方案,最终,我们将比那编码好的音视频数据通过FFmpeg进行合成,这里以asf流为例进行合成,并将生成好的asf流写入文件,以供测试。生成好的asf流可直接用于网络传输。3。1简易流程
  采集视频创建AVCaptureSession对象指定分辨率:sessionPresetactiveFormat,指定帧率setActiveVideoMinFrameDurationsetActiveVideoMaxFrameDuration指定摄像头位置:AVCaptureDevice指定相机其他属性:曝光,对焦,闪光灯,手电筒等等。。。将摄像头数据源加入session指定采集视频的格式:yuv,rgb。。。。kCVPixelBufferPixelFormatTypeKey将输出源加入session创建接收视频帧队列:(void)setSampleBufferDelegate:(nullableid)sampleBufferDelegatequeue:(nullabledispatchqueuet)sampleBufferCallbackQueue将采集视频数据渲染到屏幕:AVCaptureVideoPreviewLayer在回调函数中获取视频帧数据:CMSampleBufferRef
  采集音频配置音频格式ASBD:采样率,声道数,采样位数,数据精度,每个包中字节数等等。。。设置采样时间:setPreferredIOBufferDuration创建audiounit对象,指定分类。AudioComponentInstanceNew设置audiounit属性:打开输入,禁止输出。。。为接收的音频数据分配大小kAudioUnitPropertyShouldAllocateBuffer设置接收数据的回调开始audiounit:AudioOutputUnitStart在回调函数中获取音频数据:AudioUnitRender
  编码视频数据指定编码器宽高类型回调并创建上下文对象:VTCompressionSessionCreate设置编码器属性:缓存帧数,帧率,平均码率,最大码率,实时编码,是否重排序,配置信息,编码模式,I帧间隔时间等。准备编码数据:VTCompressionSessionPrepareToEncodeFrames开始编码:VTCompressionSessionEncodeFrame回调函数中获取编码后的数据CMBlockBufferRef根据合成码流格式,这里是asf所以需要AnnexB格式,自己组装sps,pps,startcode。
  编码音频数据提供原始数据类型与编码后数据类型的ASBD指定编码器类型kAudioEncoderComponentType创建编码器AudioConverterNewSpecific设置编码器属性:比特率,编码质量等将1024个采样点原始PCM数据传入编码器开始编码:AudioConverterFillComplexBuffer获取编码后的AAC数据
  音视频同步
  以编码的第一帧视频的系统时间作为音视频数据的基准时间戳,随后将采集到音视频数据中的时间戳减去该基准时间戳作为各自的时间戳,同步有两种策略,一种是以音频时间戳为准,即当出现错误时,让视频时间戳去追音频时间戳,这样做即会造成看到画面会快进或快退,二是以视频时间戳为准,即当出现错误时,让音频时间戳去追视时间戳,即声音可能会刺耳,不推荐。所以一般使用第一种方案,通过估计下一帧视频时间戳看看如果超出同步范围则进行同步。
  FFmpeg合成数据流初始化FFmpeg相关参数:AVFormatContext(管理合成上下文),AVOutputFormat(合成流格式),AVStream(音视频数据流)。。。创建上下文对象AVFormatContext:avformatalloccontext根据数据类型生成编码器AVCodec:avcodecfindencoder视频:AVCODECIDH264AVCODECIDHEVC,音频:AVCODECIDAAC生成流AVStream:avformatnewstream指定音视频流中各个参数信息,如数据格式,视频宽高帧率,比特率,基准时间,extradata,音频:采样率,声道数,采样位数等等。指定上下文及流格式中的音视频编码器id:videocodecid,audiocodecid生成视频流头数据:当音视频编码器都填充到上下文对象后,即可生产该类型对应的头信息,此头信息作为解码音视频数据的重要信息,一定需要正确合成。avformatwriteheader将音视频数据装入动态数组中。合成音视频数据:通过另一条线程取出动态数组中的音视频数据,通过比较时间戳的方式进行同步合成。将音视频数据装入AVPacket中产生合成的数据avwriteframe
  C音视频学习资料免费获取方法:关注音视频开发T哥,点击链接即可免费获取2023年最新C音视频开发进阶独家免费学习大礼包!3。2文件结构
  2。file3。3快速使用初始化相关模块(void)viewDidLoad{〔superviewDidLoad〕;Doanyadditionalsetupafterloadingtheview。〔selfconfigureCamera〕;〔selfconfigureAudioCapture〕;〔selfconfigureAudioEncoder〕;〔selfconfigurevideoEncoder〕;〔selfconfigureAVMuxHandler〕;〔selfconfigureAVRecorder〕;}在相机回调中将原始yuv数据送去编码(void)xdxCaptureOutput:(AVCaptureOutput)outputdidOutputSampleBuffer:(CMSampleBufferRef)sampleBufferfromConnection:(AVCaptureConnection)connection{if(〔outputisKindOfClass:〔AVCaptureVideoDataOutputclass〕〕YES){if(self。videoEncoder){〔self。videoEncoderstartEncodeDataWithBuffer:sampleBufferisNeedFreeBuffer:NO〕;}}}通过回调函数接收编码后的视频数据并将其送给合成流类。pragmamarkVideoEncoder(void)receiveVideoEncoderData:(XDXVideEncoderDataRef)dataRef{〔self。muxHandleraddVideoData:dataRefdatasize:(int)dataRefsizetimestamp:dataReftimestampisKeyFrame:dataRefisKeyFrameisExtraData:dataRefisExtraDatavideoFormat:XDXMuxVideoFormatH264〕;}在采集音频回调中接收音频数据并编码,最终将编码数据也送入合成流类pragmamarkAudioCaptureandAudioEncode(void)receiveAudioDataByDevice:(XDXCaptureAudioDataRef)audioDataRef{〔self。audioEncoderencodeAudioWithSourceBuffer:audioDataRefdatasourceBufferSize:audioDataRefsizepts:audioDataRefptscompleteHandler:(XDXAudioEncderDataRefdataRef){if(dataRefsize10){〔self。muxHandleraddAudioData:(uint8t)dataRefdatasize:dataRefsizechannelNum:1sampleRate:44100timestamp:dataRefpts〕;}free(dataRefdata);}〕;}先写文件后,随后接收合成后的数据并写入文件。pragmamarkMux(IBAction)startRecordBtnDidClicked:(id)sender{intsize0;chardata(char)〔self。muxHandlergetAVStreamHeadWithSize:size〕;〔self。recorderstartRecordWithIsHead:YESdata:datasize:size〕;self。isRecordingYES;}(void)receiveAVStreamWithIsHead:(BOOL)isHeaddata:(uint8t)datasize:(int)size{if(isHead){return;}if(self。isRecording){〔self。recorderstartRecordWithIsHead:NOdata:(char)datasize:size〕;}}4、具体实现
  本例中音视频采集编码模块在前面文章中已经详细介绍,这里不再重复,如需帮助请参考上文的阅读前提。下面仅介绍合成流。4。1初始化FFmpeg相关对象。AVFormatContext:管理合成流上下文对象AVOutputFormat:合成流的格式,这里使用的asf数据流AVStream:音视频数据流具体信息(void)configureFFmpegWithFormat:(constchar)format{if(moutputContext!NULL){avfree(moutputContext);moutputContextNULL;}moutputContextavformatalloccontext();moutputFormatavguessformat(format,NULL,NULL);moutputContextoformatmoutputFormat;moutputFormataudiocodecAVCODECIDNONE;moutputFormatvideocodecAVCODECIDNONE;moutputContextnbstreams0;mvideostreamavformatnewstream(moutputContext,NULL);mvideostreamid0;maudiostreamavformatnewstream(moutputContext,NULL);maudiostreamid1;log4cplusinfo(kModuleName,configureffmpegfinish。);}4。2配置视频流的详细信息
  设置该编码的视频流中详细的信息,如编码器类型,配置信息,原始视频数据格式,视频的宽高,比特率,帧率,基准时间戳,extradata等。
  这里最重要的就是extradata,注意,因为我们要根据extradata才能生成正确的头数据,而asf流需要的是annuxb格式的数据,苹果采集的视频数据格式为avcc所以在编码模块中已经将其转为annuxb格式的数据,并通过参数传入,这里可以直接使用,关于这两种格式区别也可以参考阅读前提中的码流介绍的文章。(void)configureVideoStreamWithVideoFormat:(XDXMuxVideoFormat)videoFormatextraData:(uint8t)extraDataextraDataSize:(int)extraDataSize{if(moutputContextNULL){log4cpluserror(kModuleName,s:moutputContextisnull,func);return;}if(moutputFormatNULL){log4cpluserror(kModuleName,s:moutputFormatisnull,func);return;}AVFormatContextformatContextavformatalloccontext();AVStreamstreamNULL;if(XDXMuxVideoFormatH264videoFormat){AVCodeccodecavcodecfindencoder(AVCODECIDH264);streamavformatnewstream(formatContext,codec);streamcodecparcodecidAVCODECIDH264;}elseif(XDXMuxVideoFormatH265videoFormat){AVCodeccodecavcodecfindencoder(AVCODECIDHEVC);streamavformatnewstream(formatContext,codec);streamcodecparcodectagMKTAG(h,e,v,c);streamcodecparprofileFFPROFILEHEVCMAIN;streamcodecparformatAVPIXFMTYUV420P;streamcodecparcodecidAVCODECIDHEVC;}streamcodecparformatAVPIXFMTYUVJ420P;streamcodecparcodectypeAVMEDIATYPEVIDEO;streamcodecparwidth1280;streamcodecparheight720;streamcodecparbitrate10241024;streamtimebase。den1000;streamtimebase。num1;streamtimebase(AVRational){1,1000};streamcodecflagsAVCODECFLAGGLOBALHEADER;memcpy(mvideostream,stream,sizeof(AVStream));if(extraData){intnewExtraDataSizeextraDataSizeAVINPUTBUFFERPADDINGSIZE;mvideostreamcodecparextradatasizeextraDataSize;mvideostreamcodecparextradata(uint8t)avmallocz(newExtraDataSize);memcpy(mvideostreamcodecparextradata,extraData,extraDataSize);}avfree(stream);moutputContextvideocodecidmvideostreamcodecparcodecid;moutputFormatvideocodecmvideostreamcodecparcodecid;self。isReadyForVideoYES;〔selfproductStreamHead〕;}4。3配置音频流的详细信息
  首先根据编码音频的类型生成编码器并生成流对象,然后配置音频流的详细信息,如压缩数据格式,采样率,声道数,比特率,extradata等等。这里要注意的是extradata是为了保存mp4文件时播放器能够正确解码播放准备的,可以参考这几篇文章:audioextradata1,audioextradata2(void)configureAudioStreamWithChannelNum:(int)channelNumsampleRate:(int)sampleRate{AVFormatContextformatContextavformatalloccontext();AVCodeccodecavcodecfindencoder(AVCODECIDAAC);AVStreamstreamavformatnewstream(formatContext,codec);streamindex1;streamid1;streamduration0;streamtimebase。num1;streamtimebase。den1000;streamstarttime0;streamprivdataNULL;streamcodecparcodectypeAVMEDIATYPEAUDIO;streamcodecparcodecidAVCODECIDAAC;streamcodecparformatAVSAMPLEFMTS16;streamcodecparsampleratesampleRate;streamcodecparchannelschannelNum;streamcodecparbitrate0;streamcodecparextradatasize2;streamcodecparextradata(uint8t)malloc(2);streamtimebase。den25;streamtimebase。num1;whyweputextradatahereforaudio:whensavetoMP4file,theplayercannotdecodeitcorrectlyhttp:ffmpegusers。933282。n4。nabble。comAACdecodertd1013071。htmlhttp:ffmpeg。orgdoxygentrunkmpeg4audio8c。htmlaa654ec3126f37f3b8faceae3b92df50eextradatahave16bits:Audioobjecttypenormally5bits,but11bitsifAOTESCAPESamplingindex4bitsif(Samplingindex15)Samplerate24bitsChannelconfiguration4bitslastreserved3bitsforexmpale:LowComplexitySamplingfrequency44100Hz,1channelmono:AOTLC20001044。1kHz4010044。1kHz4010048kHz30011mono10001soextradata:00010010000010000x120x800010001100010000x110x88if(streamcodecparsamplerate44100){streamcodecparextradata〔0〕0x12;iRigmicHDhavetwochanel0x11if(channelNum1)streamcodecparextradata〔1〕0x8;elsestreamcodecparextradata〔1〕0x10;}elseif(streamcodecparsamplerate48000){streamcodecparextradata〔0〕0x11;iRigmicHDhavetwochanel0x11if(channelNum1)streamcodecparextradata〔1〕0x88;elsestreamcodecparextradata〔1〕0x90;}elseif(streamcodecparsamplerate32000){streamcodecparextradata〔0〕0x12;if(channelNum1)streamcodecparextradata〔1〕0x88;elsestreamcodecparextradata〔1〕0x90;}elseif(streamcodecparsamplerate16000){streamcodecparextradata〔0〕0x14;if(channelNum1)streamcodecparextradata〔1〕0x8;elsestreamcodecparextradata〔1〕0x10;}elseif(streamcodecparsamplerate8000){streamcodecparextradata〔0〕0x15;if(channelNum1)streamcodecparextradata〔1〕0x88;elsestreamcodecparextradata〔1〕0x90;}streamcodecflagsAVCODECFLAGGLOBALHEADER;memcpy(maudiostream,stream,sizeof(AVStream));avfree(stream);moutputContextaudiocodecidstreamcodecparcodecid;moutputFormataudiocodecstreamcodecparcodecid;self。isReadyForAudioYES;〔selfproductStreamHead〕;}4。4生成流头数据
  当前面2,3部都配置完成后,我们将音视频流注入上下文对象及对象中的流格式中,即可开始生成头数据。avformatwriteheader(void)productStreamHead{log4cplusdebug(record,s,line:d,func,LINE);if(moutputFormatvideocodecAVCODECIDNONE){log4cpluserror(kModuleName,s:videocodecisNULL。,func);return;}if(moutputFormataudiocodecAVCODECIDNONE){log4cpluserror(kModuleName,s:audiocodecisNULL。,func);return;}prepareheaderandsaveheaderdatainastreamif(avioopendynbuf(moutputContextpb)0){avioclosedynbuf(moutputContextpb,NULL);log4cpluserror(kModuleName,s:AVFormatHTTPFFOPENDYURLERROR。,func);return;}HACKtoavoidmpegpsmuxertospitmanyunderflowerrorsDefaultvaluefromFFmpegTrytosetituseconfigurationoptionmoutputContextmaxdelay(int)(0。7AVTIMEBASE);intresultavformatwriteheader(moutputContext,NULL);if(result0){log4cpluserror(kModuleName,s:Errorwritingoutputheader,res:d,func,result);return;}uint8toutputNULL;intlenavioclosedynbuf(moutputContextpb,(uint8t)(output));if(len0output!NULL){avfree(output);self。isReadyForHeadYES;if(mavheaddata){free(mavheaddata);}mavheaddatasizelen;mavheaddata(uint8t)malloc(len);memcpy(mavheaddata,output,len);if(〔self。delegaterespondsToSelector:selector(receiveAVStreamWithIsHead:data:size:)〕){〔self。delegatereceiveAVStreamWithIsHead:YESdata:outputsize:len〕;}log4cpluserror(kModuleName,s:createheadlengthd,func,len);}else{self。isReadyForHeadNO;log4cpluserror(kModuleName,s:productstreamheaderfailed。,func);}}4。5然后将传来的音视频数据装入数组中
  该数组通过封装C中的vector实现一个轻量级数据结构以缓存数据。4。6合成音视频数据
  新建一条线程专门合成音视频数据,合成策略即取出音视频数据中时间戳较小的一帧先写,因为音视频数据总体偏差不大,所以理想情况应该是取一帧视频,一帧音频,当然因为音频采样较快,可能会相对多一两帧,而当音视频数据由于某种原因不同步时,则会等待,直至时间戳重新同步才能继续进行合成。interrpthreadcreate(mmuxThread,NULL,MuxAVPacket,(bridgeretainedvoid)self);if(err!0){log4cpluserror(kModuleName,s:createthreadfailed:s,func,strerror(err));}voidMuxAVPacket(voidarg){pthreadsetnamenp(XDXMUXTHREAD);XDXAVStreamMuxHandlerinstance(bridgetransferXDXAVStreamMuxHandler)arg;if(instance!nil){〔instancedispatchAVData〕;}returnNULL;}pragmamarkMux(void)dispatchAVData{XDXMuxMediaListaudioPack;XDXMuxMediaListvideoPack;memset(audioPack,0,sizeof(XDXMuxMediaList));memset(videoPack,0,sizeof(XDXMuxMediaList));〔mAudioListPackreset〕;〔mVideoListPackreset〕;while(true){intvideoCount〔mVideoListPackcount〕;intaudioCount〔mAudioListPackcount〕;if(videoCount0audioCount0){usleep(51000);log4cplusdebug(kModuleName,s:Muxdispatchlist:v:d,a:d,func,videoCount,audioCount);continue;}if(audioPack。timeStamp0){〔mAudioListPackpopData:audioPack〕;}if(videoPack。timeStamp0){〔mVideoListPackpopData:videoPack〕;}if(audioPack。timeStampvideoPack。timeStamp){log4cplusdebug(kModuleName,s:Muxdispatchinputvideotimestampllu,func,videoPack。timeStamp);if(videoPack。data!NULLvideoPack。datadata!NULL){〔selfaddVideoPacket:videoPack。datatimestamp:videoPack。timeStampextraDataHasChanged:videoPack。extraDataHasChanged〕;avfree(videoPack。datadata);avfree(videoPack。data);}else{log4cpluserror(kModuleName,s:MuxVideoAVPacketdataabnormal,func);}videoPack。timeStamp0;}else{log4cplusdebug(kModuleName,s:Muxdispatchinputaudiotimestampllu,func,audioPack。timeStamp);if(audioPack。data!NULLaudioPack。datadata!NULL){〔selfaddAudioPacket:audioPack。datatimestamp:audioPack。timeStamp〕;avfree(audioPack。datadata);avfree(audioPack。data);}else{log4cpluserror(kModuleName,s:MuxaudioAVPacketdataabnormal,func);}audioPack。timeStamp0;}}}4。7获取合成好的视频流
  通过avwriteframe即可获取合成好的数据。(void)productAVDataPacket:(AVPacket)packetextraDataHasChanged:(BOOL)extraDataHasChanged{BOOLisVideoIFrameNO;uint8toutputNULL;intlen0;if(avioopendynbuf(moutputContextpb)0){return;}if(packetstreamindex0packetflags!0){isVideoIFrameYES;}if(avwriteframe(moutputContext,packet)0){avioclosedynbuf(moutputContextpb,(uint8t)(output));if(output!NULL)free(output);log4cpluserror(kModuleName,s:Errorwritingoutputdata,func);return;}lenavioclosedynbuf(moutputContextpb,(uint8t)(output));if(len0outputNULL){log4cplusdebug(kModuleName,s:muxlen:dordataabnormal,func,len);if(output!NULL)avfree(output);return;}if(〔self。delegaterespondsToSelector:selector(receiveAVStreamWithIsHead:data:size:)〕){〔self。delegatereceiveAVStreamWithIsHead:NOdata:outputsize:len〕;}if(output!NULL)avfree(output);}
  原文链接:iOS瀹屾暣鎺祦閲囬泦闊宠棰戞暟鎹紪鐮佸悓姝悎鎴愭祦绠涔

再谈赞友期权一切只是出自本人观点,不作任何投资参考。首先,我们大家都清楚这个过程已经历经四年了,我们从一名铁粉一路坚信走到现在。其中有太多的不容易,疫情三年,许多中小企业,个体户都没有熬过冲击险守千元!一则传闻致禾迈股份大跌14?股民腰斩都嫌贵本文来源时代财经作者兰烁(图片来源unsplash)前一交易日刚登龙虎榜,A股第二高价股禾迈股份(688032。SH)半年报出炉后股价大跌。8月29日晚间,禾迈股份公布2022年半福燕来了!2022服贸会吉祥物发布8月30日,2022年中国国际服务贸易交易会吉祥物发布。从京交会到服贸会,中国国际服务贸易交易会(简称服贸会)已走过了十年。今年的服贸会首次迎来了吉祥物,取材于北京雨燕的福燕展翅飞房产2022半年报时代中国上半年合同销售金额274。6亿元每经记者黄婉银每经编辑陈梦妤8月30日,时代中国(01233。HK,股价1。26港元,市值26。48亿)发布2022年中期业绩报告。报告期内,时代中国录得营收64。98亿元(人民币法拍房升温捡漏仍需谨慎来源证券时报证券时报记者吴家明从去年以来,关于房贷断供以及法拍房数量暴增的消息常常成为市场讨论的焦点。不过,一般购房者想要捡漏,还是要谨慎。其实,法拍房平台上的房子,背后的故事各有广西自贸试验区加快构建面向东盟跨境产业链入驻企业超7。6万家中新社南宁8月30日电(记者林浩)8月30日,中国(广西)自由贸易试验区工作办公室专职副主任白岚介绍,中国(广西)自由贸易试验区(以下简称广西自贸试验区)建设三年来,加快构建面向东超六成电诈借助虚假App?反电诈法要求加强App许可备案随着信息通信网络发展,电信网络诈骗已经成为当前突出的犯罪类型。日前,十三届全国人大常委会第三十六次会议表决通过了反电信网络诈骗法(下称反电诈法)。9月7日,2022年中国互联网法治不贴秋膘,一年白养入秋后,建议多饮3样,3注意,去火又营养相信大家都能感觉到,最近几天后,阴雨连绵,降雨不断,气温也在一场又一场雨水中有了大幅度的降低。因此,为了养护身体,我们应该顺应传统,合理贴秋膘,才能保证身体健康。对此,建议大家平时稍微一动就满头大汗,张仲景治疗但头汗出的经方,只有三味药吃个饭都能累得满头大汗?是内热太盛还是其他原因?单纯的止汗,为什么经常反复?中医有什么简单有效的解决办法?适当出汗是人体新陈代谢过程中的正常排泄现象,属于生理性汗出。如果大量出汗,历史首人!历史第1!13号秀疯狂增肌,他要签1。2亿美金顶薪合同迈阿密热火队度过了一个安静又无趣的休赛期,他们没有完成任何一笔交易也没有增加任何一名新援。更难的是,塔克转投76人,大莫里斯被篮网挖走,热火锋线告急当然了,莱利也没有闲着,他连续开日本投降77周年我们凭什么赢得最终胜利?纪念8。15日本投降今天是日本宣布投降77周年。于今日的我们而言,这不过是一句话。而于当时的人们来说,这背后是无尽的苦难和巨大的牺牲。日本投降签字仪式日本为什么侵华?俗话说,远亲不
王者荣耀学会西施这些操作,上王者简简单单大家好,今天我给大家分享一个我最近一直拿她上分的英雄西施。大家都知道一个会玩的西施是能带领团队走向胜利的,可是我身边的朋友都不太懂西施的一些连招,那么今天我就借此机会也给大家分享一蒹葭苍苍秋末冬初,已是秋风萧瑟,寒气逼人,芦花飞雪,正是欣赏芦花的好季节。偶得清闲,漫步于中华路东的汤河南岸,那沿河的芦苇荡,着实让人眼界大开,令人感奋。一种新鲜感,亲切感油然而生。童年时隔离(车旅日志)我是申时到的普洱,彼时阳光灿烂,街道两旁绿树成荫,没有一丝初秋的感觉,温暖得象初夏。这里没有大都市的车水马龙,下班高峰街道上也车稀人疏,很难见到戴口罩的,心里自然踏实不少。在繁华的齐齐哈尔再添大型游乐项目!在这里13日由铁锋区扎龙镇组织建设的空中索道自行车项目在芦山景区完工项目建设在芦山之上索道全长100米距地最高落差15米总投资50万元芦山坐落于飞鹤大道三公里处,为齐扎沿线旅游重要节点,金鸡奖真实生图杨颖黑粗眉,苏有朋眼角8条褶,高圆圆发型减分今年的金鸡奖可以说是迎来了半个娱乐圈的人,各大女明星穿着华丽的服装争相斗妍,有的大展事业线穿深V有的穿高级定制华丽礼服,每个女星都是一道绝美的风景,虽然最终奖项的获得者是67岁的老敦煌,我曾独自来过你喜欢一个人去旅行吗一个人悄悄去过敦煌,背着简单的行囊,记下路途的感想。茫茫荒漠上的一片绿洲,曾经,商贾云集,留下千年前的壁画,记载了历史,堪称世界上最珍贵的历史文化遗产。不能拍照经典IP魔域爆出新作!魔域2手游即将上线一提到魔域,相信大家并不会很陌生,它曾经是网吧一哥,也是不少人童年的回忆,魔域在当年能出圈,还要靠着当年主打的无限制PK玩法。相信不少老玩家还记得,曾经进入网吧,几乎所有人都在玩魔肺间质纤维化咳咳喘喘痛苦不堪,需要注意哪些事项?肺间质纤维化导致肺组织瘢痕累累,患者会不同程度地缺氧而出现呼吸困难。病情容易反复发作,咳咳喘喘,最后因呼吸衰竭而死亡。病变主要累及肺间质,也可累及肺泡上皮细胞及肺血管。其主要危害有肠易激综合征有哪些分型?如何康复?这几点要做到现如今人们的生活水平不断提高,饮食的种类也越来越多,往往就会养成不良的饮食习惯,如果长此以往,越来越多的人就会有肠胃的问题,肠易激综合征就是常见的一种。我们要了解疾病的相关知识,才对话资管30人丨盈米基金CEO肖雯在满足投资者获得感与机构长远发展之间形成良性循环视频加载中经过近三年的实践和探索,基金投顾行业已发展成为大资管生态圈中不可或缺的一环。在三年的时间点上回望,行业走过了怎样的道路,发展路径与初心是否一致?监管部门和行业机构密切关注相亲遇到了自己的理想型男生,呜呜呜狠狠慕了相亲是一种玄学运气差的能让你见识到人类的多样性运气好的可能就成了一段好缘分的契机妹子就在相亲中遇到了自己的理想型男生来瞅瞅网友的经历这谁能不心动啊!图源一万颗甜甜圈约下次见面的回复
友情链接:快好找快生活快百科快传网中准网文好找聚热点快软网