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

Android硬编解码MediaCodec解析从猪肉餐馆的故

  上篇回顾:
  上一篇文章Android硬编解码MediaCodec解析从猪肉餐馆的故事讲起(一)已经叙述了MediaCodec工作流程和工作周期状态机,今天开始进入实战,从代码角度详细解析MediaCodec。如果没有看过上篇,建议还是看下才能和本文无缝衔接。MediaCodec代码实例
  本次讲解的代码实例是Google官方MediaCodec的学习项目grafika,grafika由多个demo组成,比如视频解码播放、实时录制视频并将视频编码为H264保存本地,录屏等功能,每个demo都有会侧重于某项技术。
  以下为grafika的App首页,每一项代表一个demo:
  今天,我们就从最基本的第一个demo讲起解码一个本地MP4视频。
  从gif可以看出,这是一个非常简单的视频,整个功能就是对mp4视频进行解码,然后将解码后的数据渲染到屏幕,对应的代码在com。android。grafika。PlayMovieActivity,基本流程结构图如下:
  那么最核心的解码代码都在MoviePlayer中。解复用代码解析
  首先要明白的概念是复用,也可以叫做封装,即将已经压缩编码的视频数据和音频数据按照一定的格式打包到一起,比如热爱看片的我们都很熟悉的MP4,MKV,RMVB,TS,FLV,AVI,就是复用格式。
  比如FLV格式的数据,是由H。264编码的视频码流和AAC编码的音频码流打包一起。
  FLV复用格式是由一个FLVHeader文件头和一个一个的Tag组成的。Tag中包含了音频数据以及视频数据。FLV的结构如下图所示(图来源于视音频数据处理入门:FLV封装格式解析
  C学习资料免费获取方法:关注音视频开发T哥,点击下方链接即可免费获取2023年最新C音视频开发进阶独家学习资料!
  资料包链接
  那么在解码视频之前,就必须先将H264视频数据从复用格式中取出来,Android平台已经提供了MediaExtractor这个工具让我们方便地进行解复用。
  以下是官网提供的MediaExtractor使用代码模板:MediaExtractorextractornewMediaExtractor();extractor。setDataSource(。。。);intnumTracksextractor。getTrackCount();遍历媒体复用文件中的每一条轨道数据流(音频或者视频流),得到我们需要处理的数据流的mime类型,并选中它for(inti0;inumTracks;i){MediaFormatformatextractor。getTrackFormat(i);Stringmimeformat。getString(MediaFormat。KEYMIME);if(weAreInterestedInThisTrack){选中我们需要处理的数据流的mime类型的数据流extractor。selectTrack(i);}}ByteBufferinputBufferByteBuffer。allocate(。。。)循环读取选中的音频或者视频流到inputBuffer中while(extractor。readSampleData(inputBuffer,。。。)0){inttrackIndexextractor。getSampleTrackIndex();longpresentationTimeUsextractor。getSampleTime();。。。extractor。advance();}extractor。release();extractornull;
  注释已经写的比较详细了,基本能看懂。
  首先了解下MediaFormat,它是一个专门描述媒体文件格式的类,内部通过一系列键值对来描述媒体格式,比如通用的媒体格式KEY:
  视频专有的格式KEY:
  音频专有的格式KEY:
  在上面的模板代码中,就是取了KEYMIME对应的值来判断媒体文件类型。
  而常见的视频的mime就有以下:
  videoxvnd。on2。vp8VP8video(i。e。videoin。webm)videoxvnd。on2。vp9VP9video(i。e。videoin。webm)videoavcH。264AVCvideovideohevcH。265HEVCvideovideomp4vesMPEG4videovideo3gppH。263video
  因为现在讲的编码主要是H264,而H264对应的mine就是videoavc。
  在grafika中的MoviePlayer的构造方法中com。android。grafika。MoviePlayerMoviePlayer,就是通过MediaExtractor来获取视频的宽高:解复用MediaExtractorextractornull;try{extractornewMediaExtractor();传入视频文件的路径extractor。setDataSource(sourceFile。toString());inttrackIndexselectTrack(extractor);if(trackIndex0){thrownewRuntimeException(NovideotrackfoundinmSourceFile);}选中得到的轨道(视频轨道),即后面都是对此轨道的处理extractor。selectTrack(trackIndex);通过该轨道的MediaFormat得到对视频对应的宽高MediaFormatformatextractor。getTrackFormat(trackIndex);Log。d(TAG,extractor。getTrackFormatformatformat);视频对应的宽高mVideoWidthformat。getInteger(MediaFormat。KEYWIDTH);mVideoHeightformat。getInteger(MediaFormat。KEYHEIGHT);if(VERBOSE){Log。d(TAG,VideosizeismVideoWidthxmVideoHeight);}}finally{if(extractor!null){extractor。release();}}
  在具体的播放视频方法com。android。grafika。MoviePlayerplay中,通过获取到的mime类型来创建一个MediaCodec解码器:MediaFormatformatextractor。getTrackFormat(trackIndex);Log。d(TAG,EgetTrackFormatformat:format);CreateaMediaCodecdecoder,andconfigureitwiththeMediaFormatfromtheextractor。ItsveryimportanttousetheformatfromtheextractorbecauseitcontainsacopyoftheCSD0CSD1codecspecificdatachunks。Stringmimeformat。getString(MediaFormat。KEYMIME);Log。d(TAG,createDecoderByTypemime:mime);通过视频mime类型初始化解码器MediaCodecdecoderMediaCodec。createDecoderByType(mime);
  此时MediaCodec处于Stopped状态中的Uninitialized状态,接下来开始启动MediaCodec(老板收拾厨房桌椅,要开店了):配置解码器,指定MediaFormat以及视频输出的Surface,解码器进入configure状态decoder。configure(format,mOutputSurface,null,0);启动解码器,开始进入Executing状态Immediatelyafterstart()thecodecisintheFlushedsubstate,whereitholdsallthebuffersdecoder。start();具体的解码流程doExtract(extractor,trackIndex,decoder,mFrameCallback);
  注意到configure方法传了mOutputSurface的Surface对象,在Android硬编解码利器MediaCodec解析从猪肉餐馆的故事讲起(一)讲过,对于原始视频数据来说:
  视频编解码支持三种色彩格式,其中第二种就是nativerawvideoformat:COLORFormatSurface,可以用来处理surface模式的数据输入输出。而这个Surface对象是从Activity的TextureView获取到的:MoviePlayer通过Surface将解码后的原始视频数据渲染到TextureView上SurfaceTexturestmTextureView。getSurfaceTexture();SurfacesurfacenewSurface(st);MoviePlayerplayernull;try{playernewMoviePlayer(newFile(getFilesDir(),mMovieFiles〔mSelectedMovie〕),surface,callback);}catch(IOExceptionioe){Log。e(TAG,Unabletoplaymovie,ioe);surface。release();return;}解码代码解析
  此时MediaCodec已经启动,此时已经进入input端和output端的大循环阶段(头脑中开始想象采购员一次又一次将生猪肉装进篮子中交给厨师,厨师做完又放在盘子上送给顾客的循环的场景)。关键代码看com。android。grafika。MoviePlayerdoExtract:Workloop。Weexecutehereuntilwerunoutofvideooraretoldtostop。privatevoiddoExtract(MediaExtractorextractor,inttrackIndex,MediaCodecdecoder,FrameCallbackframeCallback){Weneedtostrikeabalancebetweenprovidinginputandreadingoutputthatoperatesefficientlywithoutdelaysontheoutputside。Toavoiddelaysontheoutputside,weneedtokeepthecodecsinputbuffersfed。TherecanbesignificantlatencybetweensubmittingframeNtothedecoderandreceivingframeNontheoutput,soweneedtostayaheadofthegame。Manyvideodecodersseemtowantseveralframesofvideobeforetheystartproducingoutputoneimplementationwantedfourbeforeitappearedtoconfigureitself。Weneedtoprovideabunchofinputframesupfront,andtrytokeepthequeuefullaswego。(Noteitspossiblefortheencodeddatatobewrittentothestreamoutoforder,sowecantgenerallysubmitasingleframeandwaitforittoappear。)Wecantjustfixateontheinputsidethough。Ifwespendtoomuchtimetryingtostufftheinput,wemightmissapresentationdeadline。At60Hzwehave16。7msbetweenframes,sosleepingfor10mswouldeatupasignificantfractionofthetimeallowed。(Mostvideoisat30Hzorless,soformostcontentwellhavesignificantlylonger。)Waitingforoutputisokay,butsleepingonavailabilityofinputbuffersisunwiseifweneedtobeprovidingoutputonaregularschedule。Insomesituations,startuplatencymaybeaconcern。Tominimizestartuptime,wedwanttostufftheinputfullasquicklyaspossible。Thisturnsouttobesomewhatcomplicated,asthecodecmaystillbestartingupandwillrefusetoacceptinput。RemovingthetimeoutfromdequeueInputBuffer()resultsinspinningontheCPU。Ifyouhavetightstartuplatencyrequirements,itwouldprobablybebesttoprimethepumpwithasequenceofframesthatarentactuallyshown(e。g。grabthefirst10NALunitsandshovethemthrough,thenrewindtothestartofthefirstkeyframe)。Theactuallatencyseemstodependonstronglyonthenatureofthevideo(e。g。resolution)。Oneconceptuallyniceapproachistoloopontheinputsidetoensurethatthecodecalwayshasalltheinputitcanhandle。Aftersubmittingabuffer,weimmediatelychecktoseeifitwillacceptanother。Wecanuseashorttimeoutsowedontmissapresentationdeadline。Ontheoutputsideweonlycheckonce,withalongertimeout,thenreturntotheouterlooptoseeifthecodecishungryformoreinput。Inpractice,everycalltocheckforavailablebuffersinvolvesalotofmessagepassingbetweenthreadsandprocesses。Settingaverybrieftimeoutdoesntexactlyworkbecausetheoverheadrequiredtodeterminethatnobufferisavailableissubstantial。Ononedevice,thecleverapproachcausedsignificantlygreaterandmorehighlyvariablestartuplatency。Thecodebelowtakesaverysimplemindedapproachthatworks,butcarriesariskofoccasionallyrunningoutofoutput。Amoresophisticatedapproachmightdetectanoutputtimeoutandusethatasasignaltotrytoenqueueseveralinputbuffersonthenextiteration。Ifyouwanttoexperiment,settheVERBOSEflagtotrueandwatchthebehaviorinlogcat。Uselogcatvthreadtimetoseesubsecondtiming。获取解码输出数据的超时时间finalintTIMEOUTUSEC0;输入ByteBuffer数组(较高版本的MediaCodec已经用getInputBuffer取代了,可直接获取buffer)ByteBuffer〔〕decoderInputBuffersdecoder。getInputBuffers();记录传入了第几块数据intinputChunk0;用于log每帧解码时间longfirstInputTimeNsec1;booleanoutputDonefalse;booleaninputDonefalse;while(!outputDone){if(VERBOSE)Log。d(TAG,loop);if(mIsStopRequested){Log。d(TAG,Stoprequested);return;}Feedmoredatatothedecoder。if(!inputDone){拿到可用的ByteBuffer的indexintinputBufIndexdecoder。dequeueInputBuffer(TIMEOUTUSEC);if(inputBufIndex0){if(firstInputTimeNsec1){firstInputTimeNsecSystem。nanoTime();}根据index得到对应的输入ByteBufferByteBufferinputBufdecoderInputBuffers〔inputBufIndex〕;Log。d(TAG,decoderInputBuffersinputBuf:inputBuf,inputBufIndex:inputBufIndex);ReadthesampledataintotheByteBuffer。ThisneitherrespectsnorupdatesinputBufsposition,limit,etc。从媒体文件中读取的一个sample数据大小intchunkSizeextractor。readSampleData(inputBuf,0);if(chunkSize0){文件读到末尾,设置标志位,发送一个空帧,给后面解码知道具体结束位置EndofstreamsendemptyframewithEOSflagset。Whenyouqueueaninputbufferwiththeendofstreammarker,thecodectransitionstotheEndofStreamsubstate。Inthisstatethecodecnolongeracceptsfurtherinputbuffers,butstillgeneratesoutputbuffersuntiltheendofstreamisreachedontheoutput。decoder。queueInputBuffer(inputBufIndex,0,0,0L,MediaCodec。BUFFERFLAGENDOFSTREAM);Log。d(TAG,queueInputBuffer);inputDonetrue;if(VERBOSE)Log。d(TAG,sentinputEOS);}else{if(extractor。getSampleTrackIndex()!trackIndex){Log。w(TAG,WEIRD:gotsamplefromtrackextractor。getSampleTrackIndex(),expectedtrackIndex);}得到当前数据的播放时间点longpresentationTimeUsextractor。getSampleTime();把inputBufIndex对应的数据传入MediaCodecdecoder。queueInputBuffer(inputBufIndex,0,chunkSize,presentationTimeUs,0flags);Log。d(TAG,queueInputBufferinputBufIndex:inputBufIndex);if(VERBOSE){Log。d(TAG,submittedframeinputChunktodec,sizechunkSize);}记录传入了第几块数据inputChunk;extractor读取游标往前挪动extractor。advance();}}else{if(VERBOSE)Log。d(TAG,inputbuffernotavailable);}}if(!outputDone){如果解码成功,则得到解码出来的数据的buffer在输出buffer中的index。并将解码得到的buffer的相关信息放在mBufferInfo中。如果不成功,则得到的是解码的一些状态intoutputBufferIndexdecoder。dequeueOutputBuffer(mBufferInfo,TIMEOUTUSEC);Log。d(TAG,dequeueOutputBufferdecoderBufferIndex:outputBufferIndex,mBufferInfo:mBufferInfo);if(outputBufferIndexMediaCodec。INFOTRYAGAINLATER){nooutputavailableyetif(VERBOSE)Log。d(TAG,nooutputfromdecoderavailable);}elseif(outputBufferIndexMediaCodec。INFOOUTPUTBUFFERSCHANGED){notimportantforus,sincewereusingSurfaceif(VERBOSE)Log。d(TAG,decoderoutputbufferschanged);}elseif(outputBufferIndexMediaCodec。INFOOUTPUTFORMATCHANGED){MediaFormatnewFormatdecoder。getOutputFormat();if(VERBOSE)Log。d(TAG,decoderoutputformatchanged:newFormat);}elseif(outputBufferIndex0){thrownewRuntimeException(unexpectedresultfromdecoder。dequeueOutputBuffer:outputBufferIndex);}else{decoderStatus0if(firstInputTimeNsec!0){Logthedelayfromthefirstbufferofinputtothefirstbufferofoutput。longnowNsecSystem。nanoTime();Log。d(TAG,startuplag((nowNsecfirstInputTimeNsec)1000000。0)ms);firstInputTimeNsec0;}booleandoLoopfalse;if(VERBOSE)Log。d(TAG,surfacedecodergivenbufferoutputBufferIndex(outputmBufferInfosizemBufferInfo。size));判断是否到了文件结束,上面设置MediaCodec。BUFFERFLAGENDOFSTREAM标志位在这里判断if((mBufferInfo。flagsMediaCodec。BUFFERFLAGENDOFSTREAM)!0){if(VERBOSE)Log。d(TAG,outputEOS);if(mLoop){doLooptrue;}else{outputDonetrue;}}如果解码得到的buffer大小大于0,则需要渲染booleandoRender(mBufferInfo。size!0);AssoonaswecallreleaseOutputBuffer,thebufferwillbeforwardedtoSurfaceTexturetoconverttoatexture。Wecantcontrolwhenitappearsonscreen,butwecanmanagethepaceatwhichwereleasethebuffers。if(doRenderframeCallback!null){渲染前的回调,这里具体实现是通过一定时长的休眠来尽量确保稳定的帧率frameCallback。preRender(mBufferInfo。presentationTimeUs);}得到输出Buffer数组,较高版本已经被getOutputBuffer代替ByteBuffer〔〕decoderOutputBuffersdecoder。getOutputBuffers();Log。d(TAG,ecoderOutputBuffers。length:decoderOutputBuffers。length);将输出buffer数组的第outputBufferIndex个buffer绘制到surface。doRender为true绘制到配置的surfacedecoder。releaseOutputBuffer(outputBufferIndex,doRender);if(doRenderframeCallback!null){渲染后的回调frameCallback。postRender();}if(doLoop){Log。d(TAG,ReachedEOS,looping);需要循环的话,重置extractor的游标到初始位置。extractor。seekTo(0,MediaExtractor。SEEKTOCLOSESTSYNC);inputDonefalse;重置decoder到Flushed状态,不然就没法开始新一轮播放YoucanmovebacktotheFlushedsubstateatanytimewhileintheExecutingstateusingflush()。YoucanmovebacktotheFlushedsubstateatanytimewhileintheExecutingstateusingflush()decoder。flush();resetdecoderstateframeCallback。loopReset();}}}}}
  代码有官方和我加上的详细注释,这里主要挑几个重点讲下:
  1。采购员向厨师询问有无篮子可用:首先询问Mediacodec当前有没有可以input的Buffer可以使用:intinputBufIndexdecoder。dequeueInputBuffer(TIMEOUTUSEC);
  方法定义是:Returnstheindexofaninputbuffertobefilledwithvaliddataor1ifnosuchbufferiscurrentlyavailable。ThismethodwillreturnimmediatelyiftimeoutUs0,waitindefinitelyfortheavailabilityofaninputbufferiftimeoutUs0orwaituptotimeoutUsmicrosecondsiftimeoutUs0。paramtimeoutUsThetimeoutinmicroseconds,anegativetimeoutindicatesinfinite。throwsIllegalStateExceptionifnotintheExecutingstate,orcodecisconfiguredinasynchronousmode。throwsMediaCodec。CodecExceptionuponcodecerror。publicfinalintdequeueInputBuffer(longtimeoutUs){intresnativedequeueInputBuffer(timeoutUs);if(res0){synchronized(mBufferLock){validateInputByteBuffer(mCachedInputBuffers,res);}}returnres;}
  TIMEOUTUSEC为等待超时时间。当返回的inputBufIndex大于等于0,则说明当前有可用的Buffer,此时inputBufIndex表示可用Buffer在Mediacodec中的序号。如果等待了TIMEOUTUSEC时间还没找到可用的Buffer,则返回inputBufIndex小于0,等下次循环再来取Buffer。
  2。采购员将生猪肉装进篮子中并交给厨师:每次从MediaExtractor中的readSampleData方法读出视频一段数据放在ByteBuffer中,然后通过Mediacodec的queueInputBuffer将ByteBuffer传给Mediacodec内部处理。从媒体文件中读取的一个sample数据大小到inputBuf中intchunkSizeextractor。readSampleData(inputBuf,0);
  方法定义:Retrievethecurrentencodedsampleandstoreitinthebytebufferstartingatthegivenoffset。pbNote:bAsofAPI21,onsuccessthepositionandlimitof{codebyteBuf}isupdatedtopointtothedatajustread。parambyteBufthedestinationbytebufferreturnthesamplesize(or1ifnomoresamplesareavailable)。publicnativeintreadSampleData(NonNullByteBufferbyteBuf,intoffset);
  Android硬编解码MediaCodec解析从猪肉餐馆的故事讲起(一)中讲过,根据官网描述,一般如果是视频文件数据,则都不要传递给Mediacodec不是完整帧的数据,除非是标记了BUFFERFLAGPARTIALFRAME的数据。所以这里可以推断readSampleData方法是读取一帧的数据,后面我会对其进行验证。
  返回值为读取到数据大小,所以如果返回值大于0,则说明是有读取到数据的,则将数据传入MediaCodec中:得到当前数据的播放时间点longpresentationTimeUsextractor。getSampleTime();把inputBufIndex对应的数据传入MediaCodecdecoder。queueInputBuffer(inputBufIndex,0,chunkSize,presentationTimeUs,0flags);
  关于queueInputBuffer方法,定义的注释实在太长了,简单来说,这里就是将input端第inputBufIndex个Buffer从第0位开始chunkSize个字节数据传入MediaCodec中,并指定这一帧数据的渲染时间为presentationTimeUs,在解析H264视频编码原理从孙艺珍的电影说起(一)曾经说过
  这里由于B帧的引入,会导致一个现象,就是编码的帧顺序和播放的帧顺序会不一致,所以也衍生了pts和dts2个时间戳(编码时间和播放时间)
  这里的presentationTimeUs就是pts,因为解码后的帧数据可能不是和播放顺序一样的,需要presentationTimeUs来指定播放顺序。最后一个参数flags是对传入的数据描述用的标志位,一般用于一些特殊情况,这里传0即可。
  如果readSampleData方法返回值,即读到的数据大小为负数,则说明已经读到视频文件尾部了,则还是调用queueInputBuffer方法,但是需要特殊处理:decoder。queueInputBuffer(inputBufIndex,0,0,0L,MediaCodec。BUFFERFLAGENDOFSTREAM);
  发送一个空帧,标志位传BUFFERFLAGENDOFSTREAM,告诉MediaCodec,已经到文件尾部了,这个文件没有剩下需要传的数据了,即采购员告诉厨师,已经没有生猪肉了。
  发送了这个表示结束的空帧之后,就不能再传数据给input端了,一直到MediaCodec进入了flushed状态,或者进入stopped之后再start之后才可以重新传入数据给input端。
  input端的代码就到这,然后马不停蹄,立刻到ouptut端去尝试获取一下output的buffer(顾客走到厨师面前,问猪肉炒好了没有):intoutputBufferIndexdecoder。dequeueOutputBuffer(mBufferInfo,TIMEOUTUSEC);
  如果不成功(厨师对顾客说猪肉还没炒好),则得到的是解码的一些状态,在项目代码中,列出了以下几种常见的状态:
  1。MediaCodec。INFOTRYAGAINLATER:表示等了TIMEOUTUSEC时间长,也暂时还没有解码出成功的数据。一般来说,一个是等待时间还不够,另一个就是输入端是B帧,需要后面一帧P帧来作为参考帧才可以解码(关于B帧P帧详见解析H264视频编码原理从孙艺珍的电影说起(一))
  2。MediaCodec。INFOOUTPUTBUFFERSCHANGED:输出Buffer数组已经过时,需要及时更换,由于较新版本已经用getOutputBuffer获取输出Buffer了,所以该标志位也过时了。
  3。MediaCodec。INFOOUTPUTFORMATCHANGED:输出数据的MediaFormat发生了变化。
  如果解码成功,则得到解码出来的数据的buffer在输出buffer中的index。并将解码得到的buffer的相关信息放在mBufferInfo中。然后执行非常关键的一段代码:decoder。releaseOutputBuffer(outputBufferIndex,doRender);
  将输出buffer数组的第outputBufferIndex个buffer绘制到surface(还记得configure方法传了的Surface对象么)。doRender为true,绘制到配置的surface。可以理解这行代码就类似Android中Canvas的draw方法,调用就绘制一帧,并将Buffer回收。总结
  美好的时光总是如此短暂,我觉得解码的关键代码应该已经讲得比较细致了吧
  为了避免篇幅过长导致读者看了容易打瞌睡,我还是先到此为止把,下一篇博文Android硬编解码工具MediaCodec解析从猪肉餐馆的故事讲起(三)将讲解本文代码运行后的一些要点和注意细节,敬请关注参考:
  视音频数据处理入门:FLV封装格式解析MediaCodec官网
  安卓解码器MediaCodec解析
  作者:半岛铁盒里的猫链接:https:juejin。cnpost7111340889691127815来源:稀土掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  在开发的路上你不是一个人,欢迎加入C音视频开发交流群链接大家庭讨论交流!

李连杰一家四口罕见出镜,利智紧搂着老公的肩膀,表现很是亲密提到功夫巨星李连杰相信很多小伙伴们都看过他饰演的电影,相信不管是几零后都非常喜欢他,毕竟李连杰饰演的很多电影都超级经典,动作更是李连杰的拿手好戏,可惜的是李连杰生病之后就几乎淡出了启航2023!这批重大项目取得新进展随着新年的到来,我们踏上新的征程。在岁末年初的重要节点,一批重大项目取得新进展,为推动经济高质量发展注入新动能。中国石油长庆油田年产量创新高截至2022年12月31日22时,我国最总市值近12万亿!揭秘中国市值500强广东军团作者丨祝浩杰,王冰编辑丨张楠刚刚过去的一年,资本市场动荡,中国市值500强公司重新洗牌。不过,21数据新闻实验室推出最新一期中国上市公司市值500强榜单发现,一些总部在广东的上市公稳经济促发展新年喜报!我国最大油气田长庆油田年产油气突破6500万吨新甘肃客户端兰州讯(新甘肃甘肃日报记者范海瑞通讯员彭旭峰)2022年12月31日晚10时,我国最大油气田中国石油长庆油田全年生产油气当量突破6500万吨,达到6501。55万吨,创湖南宁乡大黑马99年创业,A股上市,年入52。59亿,老板东安首富宁乡市,湖南省辖县级市,由长沙市代管,位于长沙市西部湖南东偏北的洞庭湖南缘地区,是全国闻名的鱼米之乡生猪之乡茶叶之乡。宁乡市一直以来都是整个湖南省第三大强县,2021年宁乡市实现地炒股10年,我对炒股赚钱不能做的三点总结2010年开始接触股票,当时没有账户,看同事炒股赚钱,就拿了4000块现金让同事给买股票,当时对股票什么都不懂,结果可想而知,2年左右,当把股票卖了拿出来时应该还剩下1500块左右徐小明周二操作策略节前我们根据日线的序列判断了市场有反弹,但可操作性不大,主要判断为ABC下跌的B浪反弹,节后大概率还有C浪下跌。ABC全部走完之后,相对比较安全的点。浪型上,之前说一部分指数走2浪偿二代二期周年下的险企众生相猛增资调业务优投资随着2022年结束,保险公司实施偿二代二期工程首年成绩单出炉。对于保险业来说,2022年是充满挑战的一年,保费增速放缓盈利下滑分化加剧上市险企股价跌跌不休代理人数量持续减少在这种背对新能源产业的理解和分析(之八)新能源新知计划新能源是指传统能源之外的各种能源,例如太阳能地热能风能海洋能生物质能和核聚变能等等一,网友们记得,前几年由于燃煤烟尘和排放到空气中的大量工业废气汽车尾气等主要污染物,(新华全媒头条图文互动)产业变革加速产销振奋信心广州国际车展新观察(配本社同题文字稿)这是广汽本田汽车有限公司车间生产线(2021年3月4日摄)。新华社记者邓华摄在第二十届广州车展,参观者了解比亚迪电动车平台3。0(2022年12月30日摄)。新成渝地区双城经济圈迎来三周年产业协同创新开启加速期封面新闻记者熊英英刘旭强马梦飞朱宁2023年1月3日,是成渝地区双城经济圈提出三周年。三年来,四川省就抢抓重大战略机遇,积极加强与重庆的全方位协作,在政策共谋产业共推项目共建开放共
提醒中老年不论贫富,常吃5种食物,营养又滋补,好吃无负担俗话说拥有金山银山,都不如身体健康如山。尤其是对于中老年人来说,只有拥有健康的体魄,才能行动自如地做任何想做的事,晚年生活才能更加幸福。因此,上年纪的中老年人一定要让自己拥有一个健马上霜降,建议大家少吃生姜和茄子,多吃4样,滋补润燥身体棒风卷清云尽,空天万里霜,转眼间10月23日就是霜降了,它是秋季最后一个节气,霜降的到来意味着冬天已经不远了,此时最为明显的特征就是昼夜温差变大,甚至有些许寒意。都说秋季是进补的最佳道家洞天福地之十大洞天道教自古以来就有洞天福地之说。洞天福地是道教传说中的仙境,位于山岳之内,有洞穴与山外相通,当中有日月照明草木鸟兽仙人城市,景象与世间相似,各有地道相连。道士修道精诚,或可进入洞天,好消息!医保账户可与家人共享啦过去,职工社保卡医保账户上的余额,只能由本人使用。今天上午,记者从市医疗保障服务中心了解到,职工社保卡医保个人账户上的钱,可以给直系亲属使用了。市医疗保障服务中心相关负责人介绍,即人为什么会本能回避需要进行大量思考的活动?有些人回避需要大量思考的活动是怯于挑战,一般来说只要不是随手而就的事都可能让他们退缩,因为有挑战性的事总是伴随着意外,怕因失败而难堪,怕因失败而受伤害,怕因失败而徒劳有些人回避需要土耳其一热气球着陆时出意外,西班牙游客2死3伤极目新闻记者满达据路透社10月18日报道,在土耳其热门景点卡帕多西亚,一个载有28名游客的热气球在硬着陆时发生意外,导致2死3伤,均为西班牙人。卡帕多西亚位于内夫谢希尔省。内夫谢希哈萨克斯坦参议院通过划定哈土里海海域国界法案来源中国新闻网当地时间20日,哈萨克斯坦参议院(议会上院)举行全体会议,审议通过关于划分哈萨克斯坦土库曼斯坦里海海域国界线和捕鱼区域协定法案。综合哈通社今日哈萨克斯坦通讯社报道,根毛阿敏不愧是奶奶辈,破洞牛仔里竟穿秋裤打底,拎万元包太节俭随着年龄的增长,人们的审美会有一定的变化。年轻时的搭配如火一般热烈,有个性感的突出想法,将很多时髦的东西都穿在身上,从而让自己的造型变得更有个性,释放出真我。而随着年龄的增长岁月的潮州两男孩舞狮给爷爷祝寿看雄狮少年后着迷,学了半年近日,广东潮州一对年仅8岁和10岁的兄弟因表演舞狮向爷爷祝寿而受到关注。10月20日,男孩的父亲郭先生告诉南都记者,兄弟俩此前看过动画电影雄狮少年后就主动请求学习舞狮,并在爷爷的生东南亚越柬老行游影记(131)老挝琅勃拉邦达光西瀑布2月13日。在琅勃拉邦城内连着转了两天,第三天要去周边郊区转转了,今天的一日游活动是去琅勃拉邦周边游。上午800,约好了包车的TUTU司机准时来到了旅馆,谈好了价格,60,000K井柏然出生28天被抛弃,奶奶捡垃圾养他,爆红后父母来认亲最近,有网友偶遇井柏然和刘雯牵手逛街,恋爱再次实锤。俩人已经不是被拍到一次两次,属于半公开的状态。不得不说,井柏然的眼光非常好,与国际名模刘雯很配,不知俩人能不能步入婚姻殿堂。井柏
友情链接:快好找快生活快百科快传网中准网文好找聚热点快软网